bsp: k230: add sysctl driver

SystemCtrl includes:
- boot
- clock
- power
- reset

These drivers are built-in by default.

Signed-off-by: Wang Chen <unicorn_wang@outlook.com>
This commit is contained in:
Wang Chen 2025-04-02 15:46:38 +08:00 committed by Rbb666
parent 05699d63d5
commit 33a719db63
13 changed files with 6152 additions and 0 deletions

View File

@ -0,0 +1,19 @@
# RT-Thread building script for component
from building import *
cwd = GetCurrentDir()
src = Glob('*.c')
CPPPATH = [cwd]
group = DefineGroup('Sysctl', src, depend = [''], CPPPATH = CPPPATH)
objs = [group]
file_list = os.listdir(cwd)
for item in file_list:
if os.path.isfile(os.path.join(cwd, item, 'SConscript')):
objs = objs + SConscript(os.path.join(item, 'SConscript'))
Return('objs')

View File

@ -0,0 +1,19 @@
# RT-Thread building script for component
from building import *
cwd = GetCurrentDir()
src = Glob('*.c')
CPPPATH = [cwd]
group = DefineGroup('Sysctl_boot', src, depend = [''], CPPPATH = CPPPATH)
objs = [group]
file_list = os.listdir(cwd)
for item in file_list:
if os.path.isfile(os.path.join(cwd, item, 'SConscript')):
objs = objs + SConscript(os.path.join(item, 'SConscript'))
Return('objs')

View File

@ -0,0 +1,97 @@
/* Copyright (c) 2023, Canaan Bright Sight Co., Ltd
*
* 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.
*
* 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 HOLDER 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.
*/
#include <rtthread.h>
#include "sysctl_boot.h"
#include "ioremap.h"
#include "board.h"
volatile sysctl_boot_t* sysctl_boot = (volatile sysctl_boot_t*)BOOT_BASE_ADDR;
sysctl_boot_mode_e sysctl_boot_get_boot_mode(void)
{
switch(sysctl_boot->soc_boot_ctl & 0x3) /* bit 0~1 */
{
case 1:
return SYSCTL_BOOT_NANDFLASH;
case 2:
return SYSCTL_BOOT_EMMC;
case 3:
return SYSCTL_BOOT_SDCARD;
case 0:
default:
return SYSCTL_BOOT_NORFLASH;
}
}
bool sysctl_boot_get_otp_bypass(void)
{
if(sysctl_boot->soc_boot_ctl & 0x10)
return true;
else
return false;
}
void sysctl_boot_set_pll_lock(void)
{
sysctl_boot->soc_boot_ctl |= 1 << 3;
}
void sysctl_boot_set_spi2axi(void)
{
sysctl_boot->soc_boot_ctl |= 1 << 2;
}
void sysctl_boot_reset_soc(void)
{
sysctl_boot->soc_glb_rst |= (1 << 0) | (1 << 16);
while(1)
{
}
}
void sysctl_boot_soc_sleep_ctl(void)
{
sysctl_boot->soc_slp_ctl |= (1 << 4) | (1 << 20);
}
int sysctl_boot_read_is_boot_wakeup(void)
{
return sysctl_boot->soc_wakeup_src;
}
int rt_hw_sysctl_boot_init(void)
{
sysctl_boot = rt_ioremap((void*)BOOT_BASE_ADDR, BOOT_IO_SIZE);
if(!sysctl_boot)
{
rt_kprintf("sysctl_boot ioremap error\n");
return -1;
}
return 0;
}
INIT_BOARD_EXPORT(rt_hw_sysctl_boot_init);

View File

@ -0,0 +1,96 @@
/* Copyright (c) 2023, Canaan Bright Sight Co., Ltd
*
* 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.
*
* 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 HOLDER 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.
*/
#ifndef __SYSCTL_BOOT_H__
#define __SYSCTL_BOOT_H__
#include <stdint.h>
#include <stdbool.h>
typedef struct pll {
volatile uint32_t cfg0;
volatile uint32_t cfg1;
volatile uint32_t ctl;
volatile uint32_t state;
} pll_t;
/*
* pll related registers see TRM 2.2.4 Table 2-2-8
* soc_glb_rst: see TRM 2.1.4 Table 2-2-1
* Others: see TRM 2.3.4 Table 2-3-2
*/
typedef struct sysctl_boot {
pll_t pll[4];
volatile uint32_t soc_boot_ctl; /* 0x40 */
volatile uint32_t reserved0[7]; /* 0x44 0x48 0x4c 0x50 0x54 0x58 0x5c*/
volatile uint32_t soc_glb_rst; /* 0x60 */
volatile uint32_t soc_rst_tim; /* 0x64 */
volatile uint32_t soc_slp_tim; /* 0x68 */
volatile uint32_t soc_slp_ctl; /* 0x6c */
volatile uint32_t clk_stable_tim; /* 0x70 */
volatile uint32_t cpu_wakeup_tim; /* 0x74 */
volatile uint32_t soc_wakeup_src; /* 0x78 */
volatile uint32_t cpu_wakeup_cfg; /* 0x7c */
volatile uint32_t timer_pause_ctl; /* 0x80 */
volatile uint32_t reserved1[3]; /* 0x84 0x88 0x8c */
volatile uint32_t sysctl_int0_raw; /* 0x90 */
volatile uint32_t sysctl_int0_en; /* 0x94 */
volatile uint32_t sysctl_int0_state; /* 0x98 */
volatile uint32_t reserved2; /* 0x9c */
volatile uint32_t sysctl_int1_raw; /* 0xa0 */
volatile uint32_t sysctl_int1_en; /* 0xa4 */
volatile uint32_t sysctl_int1_state; /* 0xa8 */
volatile uint32_t reserved3; /* 0xac */
volatile uint32_t sysctl_int2_raw; /* 0xb0 */
volatile uint32_t sysctl_int2_en; /* 0xb4 */
volatile uint32_t sysctl_int2_state; /* 0xb8 */
volatile uint32_t reserved4[17]; /* 0xbc 0xc0-0xcc 0xd0-0xdc 0xe0-0xec 0xf0-0xfc*/
volatile uint32_t cpu0_hart_rstvec; /* 0x100 */
volatile uint32_t cpu1_hart_rstvec; /* 0x104 */
volatile uint32_t reserved5[4]; /* 0x108 0x10c 0x110 0x114 */
volatile uint32_t soc_sleep_mask; /* 0x118 */
} sysctl_boot_t;
/* See TRM 1.4.1 Boot media Selection */
typedef enum
{
SYSCTL_BOOT_NORFLASH = 0,
SYSCTL_BOOT_NANDFLASH = 1,
SYSCTL_BOOT_EMMC = 2,
SYSCTL_BOOT_SDCARD = 3,
SYSCTL_BOOT_MAX,
} sysctl_boot_mode_e;
sysctl_boot_mode_e sysctl_boot_get_boot_mode(void);
bool sysctl_boot_get_otp_bypass(void);
void sysctl_boot_set_pll_lock(void);
void sysctl_boot_set_spi2axi(void);
void sysctl_boot_reset_soc(void);
int sysctl_boot_read_is_boot_wakeup(void);
void sysctl_boot_soc_sleep_ctl(void);
#endif

View File

@ -0,0 +1,19 @@
# RT-Thread building script for component
from building import *
cwd = GetCurrentDir()
src = Glob('*.c')
CPPPATH = [cwd]
group = DefineGroup('Sysctl_clock', src, depend = [''], CPPPATH = CPPPATH)
objs = [group]
file_list = os.listdir(cwd)
for item in file_list:
if os.path.isfile(os.path.join(cwd, item, 'SConscript')):
objs = objs + SConscript(os.path.join(item, 'SConscript'))
Return('objs')

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,611 @@
/* Copyright (c) 2023, Canaan Bright Sight Co., Ltd
*
* 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.
*
* 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 HOLDER 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.
*/
#ifndef __SYSCTL_CLK_H__
#define __SYSCTL_CLK_H__
#include <stdint.h>
#include <stdbool.h>
/* See TRM 2.2.4 Table 2-2-9 */
typedef struct sysctl_clk {
volatile uint32_t cpu0_clk_cfg; /* 0x00 */
volatile uint32_t reserved_0; /* 0x04 */
volatile uint32_t reserved_1; /* 0x08 */
volatile uint32_t reserved_2; /* 0x0c */
volatile uint32_t pmu_clk_cfg; /* 0x10 */
volatile uint32_t reserved0[1]; /* 0x14 */
volatile uint32_t hs_clken_cfg; /* 0x18 */
volatile uint32_t hs_sdclk_cfg; /* 0x1c */
volatile uint32_t hs_spi_cfg; /* 0x20 */
volatile uint32_t ls_clken_cfg0; /* 0x24 */
volatile uint32_t ls_clken_cfg1; /* 0x28 */
volatile uint32_t uart_i2c_clkdiv_cfg; /* 0x2c */
volatile uint32_t ls_clkdiv_cfg; /* 0x30 */
volatile uint32_t reserved_3; /* 0x34 */
volatile uint32_t reserved_4; /* 0x38 */
volatile uint32_t reserved_5; /* 0x3c */
volatile uint32_t reserved_6; /* 0x40 */
volatile uint32_t reserved_7; /* 0x44 */
volatile uint32_t reserved1[2]; /* 0x48 0x4c */
volatile uint32_t sysctl_clken_cfg; /* 0x50 */
volatile uint32_t timer_clk_cfg; /* 0x54 */
volatile uint32_t sysctl_clk_div_cfg; /* 0x58 */
volatile uint32_t shrm_clk_cfg; /* 0x5c */
volatile uint32_t ddr_clk_cfg; /* 0x60 */
volatile uint32_t reserved_8; /* 0x64 */
volatile uint32_t reserved_9; /* 0x68 */
volatile uint32_t reserved_10; /* 0x6c */
volatile uint32_t reserved_11; /* 0x70 */
volatile uint32_t reserved_12; /* 0x74 */
volatile uint32_t reserved_13; /* 0x78 */
volatile uint32_t reserved2[1]; /* 0x7c */
volatile uint32_t sec_clk_div; /* 0x80 */
volatile uint32_t reserved3[31]; /* 0x84 0x88 0x8c 0x90 0x94 0x98 0x9c 0xa0-0xac 0xb0-0xbc 0xc0-0xcc 0xd0-0xdc 0xe0-0xec 0xf0-0xfc*/
volatile uint32_t usb_test_clk_div; /* 0x100 */
volatile uint32_t dphy_test_clk_div; /* 0x104 */
volatile uint32_t spi2axi_clk_div; /* 0x108 */
} sysctl_clk_t;
/*
* Clock Tree and clock node table
*
* Abbreviations:
* - D: DIV
* - G: GATE
* - M: MUX
* - fD: fraDIV
*/
typedef enum {
/*
* First level is sysctl_boot / sysctrl_root module, which
* is composed of osc24m, pll[0|1|2|3], pll[0|1|2|3]_[div2|div3|div4] (pllx
* outputs 4 signals, namely pllx, div2, div3, and div4).
* Plus timerx_pulse_in, which is an external pulse input through the soc
* pin (pinmux) as a source of timer clock.
*
* - osc24m: fixed-clock
* - pll[0|1|2|3]: clock generated by PLL
* - pll[0|1|2|3]_[div2|div3|div4]: fixed-clock
* - timerx_pulse_in: fixed-clock, maxsize is 1MHz
*
* osc24m ---+--> pll0 ---+--------> pll0 ------->+
* | +--(D2)--> pll0_div2 -->|
* | +--(D3)--> pll0_div3 -->|
* | +--(D4)--> pll0_div4 -->|
* | |
* +--> pll1 ---+--------> pll1 ------->|
* | +--(D2)--> pll1_div2 -->|
* | +--(D3)--> pll1_div3 -->|
* | +--(D4)--> pll1_div4 -->|
* | +--> sysctl_clock
* +--> pll2 ---+--------> pll2 ------->|
* | +--(D2)--> pll2_div2 -->|
* | +--(D3)--> pll2_div3 -->|
* | +--(D4)--> pll2_div4 -->|
* | |
* +--> pll3 ---+--------> pll3 ------->|
* | +--(D2)--> pll3_div2 -->|
* | +--(D3)--> pll3_div3 -->|
* | +--(D4)--> pll3_div4 -->|
* | |
* +----------------------------------->+
* |
* timerx_pulse_in ------------------------------>+
*/
SYSCTL_CLK_ROOT_OSC_IN = 0, /* 24M */
SYSCTL_CLK_ROOT_TIMERX_PULSE_IN, /* 50M */
SYSCTL_CLK_ROOT_PLL0, /* 1.6G */
SYSCTL_CLK_ROOT_PLL0_DIV_2, /* 800M */
SYSCTL_CLK_ROOT_PLL0_DIV_3, /* 533M */
SYSCTL_CLK_ROOT_PLL0_DIV_4, /* 400M */
SYSCTL_CLK_ROOT_PLL1, /* 2.376G */
SYSCTL_CLK_ROOT_PLL1_DIV_2, /* 1.188G */
SYSCTL_CLK_ROOT_PLL1_DIV_3, /* 792M */
SYSCTL_CLK_ROOT_PLL1_DIV_4, /* 594M */
SYSCTL_CLK_ROOT_PLL2, /* 2.667G */
SYSCTL_CLK_ROOT_PLL2_DIV_2, /* 1.3335G */
SYSCTL_CLK_ROOT_PLL2_DIV_3, /* 889M */
SYSCTL_CLK_ROOT_PLL2_DIV_4, /* 666.75M */
SYSCTL_CLK_ROOT_PLL3, /* 1.6G */
SYSCTL_CLK_ROOT_PLL3_DIV_2, /* 800M */
SYSCTL_CLK_ROOT_PLL3_DIV_3, /* 533M */
SYSCTL_CLK_ROOT_PLL3_DIV_4, /* 400M */
SYSCTL_CLK_ROOT_MAX,
/*
* Second level is sysctl_clock module, which is composed of several clock sub-trees
* - CPU0: aclk/pliclk/pclk
* - pmu system: pclk
* - HS (High Speed) system: hs/sdx/ssix/usbx
* - LS (Low Speed) system : ls/uartx/i2cx/gpio/pwm/jamlinkx/audio/adc/codec
* - System Control (such as wdt, timer, iomux, mailbox): sysctl/wdtx/timer/iomux/mailbox/hdi/stc/ts
* - Timer: timerx
* - shrm (share memory) system: shrm/decompress/gsdma/nonai2d/pdma
* - sec (security) system: aclk/fixclk/pclk
* - usb test mode: clk480/clk100
* - dphy dft mode clock: dphy_test_clk
* - spi2axi clock: aclk
*/
/*
* cpu0 clock tree:
*
* pll0_div2 --(DG)--> cpu0_src --+--(DG)--> cpu0_plic
* |--(D)---> cpu0_aclk
* +--(G)---> cpu0_noc_ddrcp4
* pll0_div4 --(DG)--> cpu0_pclk
*/
/* root node: pll0_div2 */
SYSCTL_CLK_CPU0_SRC, /* cpu0 coredefualt 800MHz ---> select pll0_div_2 */
SYSCTL_CLK_CPU0_PLIC, /* cpu0 plic clk400MHz */
SYSCTL_CLK_CPU0_ACLK, /* cpu0 axi clk400MHz */
SYSCTL_CLK_CPU0_NOC_DDRCP4, /* ddrc axi4clk & noc AXI clock400MHz */
/* root node: pll0_div4 */
SYSCTL_CLK_CPU0_PCLK, /* cpu0 apb pclk200MHz */
/*
* pmu system clock tree:
*
* osc24m -->(G)--> pmu_pclk
*
* - pmu_pclk: pmu apb clk gate
*/
SYSCTL_CLK_PMU_PCLK,
/*
* High-Speed system clock tree
*
* pll0_div4 --+--(D)--> hs_hclk_high_src --+--(G)----> hs_hclk_high_gate
* | |
* | +--(DG)--> hs_hclk_src --+--(G)--> sd0_ahb_gate
* | |--(G)--> sd1_ahb_gate
* | |--(G)--> ssi1_ahb_gate
* | |--(G)--> ssi2_ahb_gate
* | |--(G)--> usb0_ahb_gate
* | +--(G)--> usb1_ahb_gate
* |
* +--(DG)--> ssi0_axi
* |--(DG)--> ssi1
* |--(DG)--> ssi2
* +--(DG)--> qspi_axi_src --+--(G)--> ssi1_aclk_gate
* | |
* | +--(G)--> ssi2_aclk_gate
* |
* +--(DG)--> sd_card_src --+--(G)--> sd0_card_gate
* |
* +--(G)--> sd1_card_gate
*
* pll0_div2 --\
* (M)--(G)--> ssi0
* pll2_div4 --/
*
*
* pll2_div4 --(DG)--> sd_axi_src --+--(G)--> sd0_axi_gate
* |--(G)--> sd1_axi_gate
* |--(G)--> sd0_base_gate
* +--(G)--> sd1_base_gate
*
*
*
* osc24m -----------------------------------------\
* (M)--+--(G)--> usb0_ref_gate
* pll0 --(D)--> pll0_div16 --(D)--> usb_ref_50m --/ |
* +--(G)--> usb1_ref_gate
*
*
* osc24m --(DG)--> sd_timer_src --+--(G)--> sd0_timer_gate
* |
* +--(G)--> sd1_timer_gate
*/
/* root node: pll0_div4, through hs_hclk_high_src */
SYSCTL_CLK_HS_HCLK_HIGH_SRC,
SYSCTL_CLK_HS_HCLK_HIGH_GATE,
SYSCTL_CLK_HS_HCLK_SRC,
SYSCTL_CLK_SD0_AHB_GATE,
SYSCTL_CLK_SD1_AHB_GATE,
SYSCTL_CLK_USB0_AHB_GATE,
SYSCTL_CLK_USB1_AHB_GATE,
SYSCTL_CLK_SSI1_AHB_GATE,
SYSCTL_CLK_SSI2_AHB_GATE,
/* root node: pll0_div4 */
SYSCTL_CLK_SSI0_AXI,
SYSCTL_CLK_SSI1,
SYSCTL_CLK_SSI2,
SYSCTL_CLK_QSPI_AXI_SRC,
SYSCTL_CLK_SSI1_ACLK_GATE,
SYSCTL_CLK_SSI2_ACLK_GATE,
/*root node: pll0_div4, through sd_card_src */
SYSCTL_CLK_SD_CARD_SRC,
SYSCTL_CLK_SD0_CARD_GATE,
SYSCTL_CLK_SD1_CARD_GATE,
/* root node: pll0_div2 MUX pll2_div4 */
SYSCTL_CLK_SSI0, /* ospi core clk */
/* root node: pll2_div4 */
SYSCTL_CLK_SD_AXI_SRC,
SYSCTL_CLK_SD0_AXI_GATE,
SYSCTL_CLK_SD1_AXI_GATE,
SYSCTL_CLK_SD0_BASE_GATE,
SYSCTL_CLK_SD1_BASE_GATE,
/* root node: pll0_div16 */
SYSCTL_CLK_PLL0_DIV16,
SYSCTL_CLK_USB_REF_50M, /* usbx reference clk */
SYSCTL_CLK_USB0_REF_GATE,
SYSCTL_CLK_USB1_REF_GATE,
/* root node: osc24m */
SYSCTL_CLK_SD_TIMER_SRC,
SYSCTL_CLK_SD0_TIMER_GATE,
SYSCTL_CLK_SD1_TIMER_GATE,
/* Low-Speed system clock tree
*
* pll0_div4 --(DG)--+--> ls_apb_src --+--(G) --> uart0_apb_gate
* | +--(G) --> uart1_apb_gate
* | +--(G) --> uart2_apb_gate
* | +--(G) --> uart3_apb_gate
* | +--(G) --> uart4_apb_gate
* | +--(G) --> i2c0_apb_gate
* | +--(G) --> i2c1_apb_gate
* | +--(G) --> i2c2_apb_gate
* | +--(G) --> i2c3_apb_gate
* | +--(G) --> i2c4_apb_gate
* | +--(G) --> gpio_apb_gate
* | +--(G) --> pwm_apb_gate
* | +--(G) --> jamlink0_apb_gate
* | +--(G) --> jamlink1_apb_gate
* | +--(G) --> jamlink2_apb_gate
* | +--(G) --> jamlink3_apb_gate
* | +--(G) --> audio_apb_gate
* | +--(G) --> adc_apb_gate
* | +--(G) --> codec_apb_gate
* |
* +--(DG)--> i2c0_core
* +--(DG)--> i2c1_core
* +--(DG)--> i2c2_core
* +--(DG)--> i2c3_core
* +--(DG)--> i2c4_core
* +--(DG)--> codec_adc
* +--(DG)--> codec_dac
* +--(DG)--> audio_dev
* +--(DG)--> pdm
* +--(DG)--> adc
*
* pll0 --(D)--> pll0_div16 --+--(DG)--> uart0_core
* +--(DG)--> uart1_core
* +--(DG)--> uart2_core
* +--(DG)--> uart3_core
* +--(DG)--> uart4_core
*
* pll0 --(D)--> pll0_div16 --(D)--> jamlink_CO_div --+--(G)--> jamlink0_CO_gate
* +--(G)--> jamlink1_CO_gate
* +--(G)--> jamlink2_CO_gate
* +--(G)--> jamlink3_CO_gate
*
* osc24m --(DG)--> gpio_debounce
*/
/* root node: pll0_div4, through ls_apb_src */
SYSCTL_CLK_LS_APB_SRC,
SYSCTL_CLK_UART0_APB_GATE,
SYSCTL_CLK_UART1_APB_GATE,
SYSCTL_CLK_UART2_APB_GATE,
SYSCTL_CLK_UART3_APB_GATE,
SYSCTL_CLK_UART4_APB_GATE,
SYSCTL_CLK_I2C0_APB_GATE,
SYSCTL_CLK_I2C1_APB_GATE,
SYSCTL_CLK_I2C2_APB_GATE,
SYSCTL_CLK_I2C3_APB_GATE,
SYSCTL_CLK_I2C4_APB_GATE,
SYSCTL_CLK_GPIO_APB_GATE,
SYSCTL_CLK_PWM_APB_GATE,
SYSCTL_CLK_JAMLINK0_APB_GATE,
SYSCTL_CLK_JAMLINK1_APB_GATE,
SYSCTL_CLK_JAMLINK2_APB_GATE,
SYSCTL_CLK_JAMLINK3_APB_GATE,
SYSCTL_CLK_AUDIO_APB_GATE,
SYSCTL_CLK_ADC_APB_GATE,
SYSCTL_CLK_CODEC_APB_GATE,
/* root node: pll0_div4 */
SYSCTL_CLK_I2C0_CORE,
SYSCTL_CLK_I2C1_CORE,
SYSCTL_CLK_I2C2_CORE,
SYSCTL_CLK_I2C3_CORE,
SYSCTL_CLK_I2C4_CORE,
SYSCTL_CLK_CODEC_ADC,
SYSCTL_CLK_CODEC_DAC,
SYSCTL_CLK_AUDIO_DEV,
SYSCTL_CLK_PDM,
SYSCTL_CLK_ADC,
/* root node: pll0_div16 */
SYSCTL_CLK_UART0_CORE,
SYSCTL_CLK_UART1_CORE,
SYSCTL_CLK_UART2_CORE,
SYSCTL_CLK_UART3_CORE,
SYSCTL_CLK_UART4_CORE,
/* root node: pll0_div16, through jamlink_CO_div */
SYSCTL_CLK_JAMLINK_CO_DIV,
SYSCTL_CLK_JAMLINK0_CO_GATE,
SYSCTL_CLK_JAMLINK1_CO_GATE,
SYSCTL_CLK_JAMLINK2_CO_GATE,
SYSCTL_CLK_JAMLINK3_CO_GATE,
/* root node: osc24m */
SYSCTL_CLK_GOIP_DEBOUNCE,
/*
* System Control clock tree
*
* pll0_div16 --> sysctl_apb_src --+--(G)--> wdt0_apb_gate
* +--(G)--> wdt1_apb_gate
* +--(G)--> timer_apb_gate
* +--(G)--> iomux_apb_gate
* +--(G)--> mailbox_apb_gate
*
* pll0_div4 --(DG)--> hdi_core
*
* pll1_div4 --(DG)--> timestamp
*
* osc24m --(D)--> temp_sensor
*
* osc24m --+--(DG)--> wdt0
* |
* +--(DG)--> wdt1
*/
/* root node: pll0_div16, through sysctl_apb_src */
SYSCTL_CLK_SYSCTRL_APB_SRC,
SYSCTL_CLK_WDT0_APB_GATE,
SYSCTL_CLK_WDT1_APB_GATE,
SYSCTL_CLK_TIMER_APB_GATE,
SYSCTL_CLK_IOMUX_APB_GATE,
SYSCTL_CLK_MAILBOX_APB_GATE,
/* root node: pll0_div4 */
SYSCTL_CLK_HDI_CORE,
/* root node: pll1_div4 */
SYSCTL_CLK_TIMESTAMP,
/* root node: osc24m */
SYSCTL_CLK_TEMP_SENSOR,
/* root node: osc24m */
SYSCTL_CLK_WDT0,
SYSCTL_CLK_WDT1,
/*
* timer clock tree
*
* pll0_div16 --(D)--> timer0_src --\
* (M)--(G)-->timer0
* timerx_pulse_in -----------------/
*
* pll0_div16 --(D)--> timer1_src --\
* (M)--(G)-->timer1
* timerx_pulse_in -----------------/
*
* pll0_div16 --(D)--> timer2_src --\
* (M)--(G)-->timer2
* timerx_pulse_in -----------------/
*
* pll0_div16 --(D)--> timer3_src --\
* (M)--(G)-->timer3
* timerx_pulse_in -----------------/
*
* pll0_div16 --(D)--> timer4_src --\
* (M)--(G)-->timer4
* timerx_pulse_in -----------------/
*
* pll0_div16 --(D)--> timer5_src --\
* (M)--(G)-->timer5
* timerx_pulse_in -----------------/
*/
/* root node: pll0_div16 & timerx_pulse_in */
SYSCTL_CLK_TIMERX_PULSE_IN,
SYSCTL_CLK_TIMER0_SRC,
SYSCTL_CLK_TIMER0,
SYSCTL_CLK_TIMER1_SRC,
SYSCTL_CLK_TIMER1,
SYSCTL_CLK_TIMER2_SRC,
SYSCTL_CLK_TIMER2,
SYSCTL_CLK_TIMER3_SRC,
SYSCTL_CLK_TIMER3,
SYSCTL_CLK_TIMER4_SRC,
SYSCTL_CLK_TIMER4,
SYSCTL_CLK_TIMER5_SRC,
SYSCTL_CLK_TIMER5,
/*
* shrm system clock tree
*
* pll0_div2 --\
* (M)--(G)--> shrm_src --+--(D)--> shrm_div2 --(G)--> shrm_axi_slave
* pll3_div2 --/ |
* +--(G)--> decompress_axi
*
* pll0_div4 -->(DG)--> shrm_apb
*
* pll0_div4 -->(G)--> shrm_axi_src --+--(G)--> gsdma_axi_gate
* +--(G)--> nonai2d_axi_gate
* +--(G)--> peri_dma_axi_gate
*/
/* root node: pll0_div2 & pll3_div2 */
SYSCTL_CLK_SHRM_SRC,
SYSCTL_CLK_SHRM_DIV2,
SYSCTL_CLK_SHRM_AXIS_SLAVE,
SYSCTL_CLK_DECOMPRESS_AXI,
/* root node: pll0_div4 */
SYSCTL_CLK_SHRM_APB,
/* root node: pll0_div4, through shrm_axi_src */
SYSCTL_CLK_SHRM_AXI_SRC,
SYSCTL_CLK_GSDMA_AXI_GATE,
SYSCTL_CLK_NONAI2D_AXI_GATE,
SYSCTL_CLK_PERI_DMA_AXI_GATE,
/*
* Security system clock tree
*
* pll0_div4 --(DG)--> sec_apb
*
* pll1_div4 --+--(DG)--> sec_fix
* |
* +--(DG)--> sec_axi
*/
/* root node: pll0_div4 */
SYSCTL_CLK_SEC_APB,
/* root node: pll1_div4 */
SYSCTL_CLK_SEC_FIX,
SYSCTL_CLK_SEC_AXI,
/*
* usb test mode clock tree
*
* pll1 --(DG)--> usb_480m
*
* pll0_div4 --(DG)--> usb_100m
*/
/* root node: pll1 */
SYSCTL_CLK_USB_480M,
/* root node: pll0_div4 */
SYSCTL_CLK_USB_100M,
/*
* dphy dft mode clock tree
*
* pll0 --(DG)--> dphy_dft_mode
*/
/* root node: pll0 */
SYSCTL_CLK_DPHY_DFT_MODE,
/*
* spi2axi clock tree
*
* pll0_div4 --(DG)--> spi2axi_axi
*/
/* root node: pll0_div4 */
SYSCTL_CLK_SPI2AXI_AXI,
SYSCTL_CLK_NODE_MAX,
} sysctl_clk_node_e;
#define SYSCTL_READ_ENABLE (1 << 0)
#define SYSCTL_READ_DISABLE (0 << 0)
#define SYSCTL_WRITE_ENABLE (1 << 1)
#define SYSCTL_WRITE_DISABLE (0 << 1)
/*
* API for root clock. 24M, PLL0-3, these 5 clocks are root clocks
* It is assumed here that the big core has read and write permissions to the
* root clock, so the properties of clk are not judged in these APIs,
* because these APIs are only for the root clock.
*/
/*
* Get the bypass status of the PLL.
* If it is bypas, the PLL output is 24M OSC clock.
*/
bool sysctl_boot_get_root_clk_bypass(sysctl_clk_node_e clk);
void sysctl_boot_set_root_clk_bypass(sysctl_clk_node_e clk, bool enable);
/* Enable pll, enable 24M clock&pll */
bool sysctl_boot_get_root_clk_en(sysctl_clk_node_e clk);
void sysctl_boot_set_root_clk_en(sysctl_clk_node_e clk, bool enable);
/* Get the phase-locked loop lock status */
bool sysctl_boot_get_root_clk_lock(sysctl_clk_node_e clk);
/* Get the root clock frequency */
uint32_t sysctl_boot_get_root_clk_freq(sysctl_clk_node_e clk);
/*
* Set the PLL clock frequency
* The formula for setting the PLL clock frequency is:
* pll_out_freq = (double)OSC_CLOCK_FREQ_24M * (double)(fbdiv+1) / (double)(refdiv+1) / (double)(outdiv+1)
*/
bool sysctl_boot_set_root_clk_freq(sysctl_clk_node_e clk, uint32_t fbdiv, uint32_t refdiv, uint32_t outdiv, uint32_t bwadj);
/*
* API for trunk and leaf nodes in the clock tree, i.e. clocks other than the five root clocks.
*/
/*
* Set the leaf node clock source on the clock tree.
* Please set it according to the clock tree.
* Many clock nodes have only one clock source, so the setting will return false.
*/
bool sysctl_clk_set_leaf_parent(sysctl_clk_node_e leaf, sysctl_clk_node_e parent);
/* Get the clock source of the leaf node in the clock tree */
sysctl_clk_node_e sysctl_clk_get_leaf_parent(sysctl_clk_node_e leaf);
/*
* Set the clock node enable.
* Note: only set the enable of this clock node, and do not set the enable of
* the upstream clock.
* Difference from Linux kernel: Linux kernel clock framework will automatically
* set the enable of the upstream clock. The test code does not have kernel
* framework, so only the enable of the clock of this node is set.
*/
void sysctl_clk_set_leaf_en(sysctl_clk_node_e leaf, bool enable);
/* Get the enable status of this clock node */
bool sysctl_clk_get_leaf_en(sysctl_clk_node_e leaf);
/* Set the frequency division factor of this clock node */
bool sysctl_clk_set_leaf_div(sysctl_clk_node_e leaf, uint32_t numerator, uint32_t denominator);
/* Get the frequency division coefficient of this clock node */
double sysctl_clk_get_leaf_div(sysctl_clk_node_e leaf);
/*
* Calculate clock freqency.
* This API searches the entire clock path, calculates the frequency division
* at each level starting from the clock source, and finally obtains the
* current clock frequency.
*/
uint32_t sysctl_clk_get_leaf_freq(sysctl_clk_node_e leaf);
#endif /* __SYSCTL_CLK_H__ */

View File

@ -0,0 +1,19 @@
# RT-Thread building script for component
from building import *
cwd = GetCurrentDir()
src = Glob('*.c')
CPPPATH = [cwd]
group = DefineGroup('Sysctl_power', src, depend = [''], CPPPATH = CPPPATH)
objs = [group]
file_list = os.listdir(cwd)
for item in file_list:
if os.path.isfile(os.path.join(cwd, item, 'SConscript')):
objs = objs + SConscript(os.path.join(item, 'SConscript'))
Return('objs')

View File

@ -0,0 +1,775 @@
/* Copyright (c) 2023, Canaan Bright Sight Co., Ltd
*
* 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.
*
* 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 HOLDER 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.
*/
#include <rtthread.h>
#include <rthw.h>
#include <stdio.h>
#include "sysctl_pwr.h"
#include "drv_hardlock.h"
#include "ioremap.h"
#include "board.h"
volatile sysctl_pwr_s* sysctl_pwr = (volatile sysctl_pwr_s*)PWR_BASE_ADDR;
/*****************************************************************************************
* SET POWER DOMAIN'S TIME
* powerdomain:power domain
* timtype: idleReq_to_idleAck, idleAck_to_idle.....
* tim_value: ack_to_tim, idle_to_tim......
*****************************************************************************************/
/* ack timeout value, lpi idleReq to idleAck */
bool sysctl_pwr_set_ack_to_tim(volatile uint32_t *reg, uint32_t ack_to_tim)
{
volatile uint32_t *ret = reg;
if((NULL == reg) || (ack_to_tim > 0x1F))
return false;
else
{
*ret &= 0xffffffe0;
*reg = (*ret) | (ack_to_tim << 0);
return true;
}
}
/* idle timeout value, lpi idleAck to idle */
bool sysctl_pwr_set_idle_to_tim(volatile uint32_t *reg, uint32_t idle_to_tim)
{
volatile uint32_t *ret = reg;
if((NULL == reg) || (idle_to_tim > 0x1F))
return false;
else
{
*ret &= 0xffffe0ff;
*reg = (*ret) | (idle_to_tim << 8);
return true;
}
}
/* NOC power controller in idle min time, idle to idelReq(inactive) */
bool sysctl_pwr_set_idle_hd_tim(volatile uint32_t *reg, uint32_t idle_hd_tim)
{
volatile uint32_t *ret = reg;
if((NULL == reg) || (idle_hd_tim > 0x3F))
return false;
else
{
*ret &= 0xffc0ffff;
*reg = (*ret) | (idle_hd_tim << 16);
return true;
}
}
/*
* After turning ISO on/off, you need to wait for a while to ensure that the
* isolation cells in the power domain are actually enabled/disabled.
*/
bool sysctl_pwr_set_iso_su_tim(volatile uint32_t *reg, uint32_t iso_su_tim)
{
volatile uint32_t *ret = reg;
if((NULL == reg) || (iso_su_tim > 0xF))
return false;
else
{
*ret &= 0xfffffff0;
*reg = (*ret) | (iso_su_tim << 0);
return true;
}
}
/*
* After powering off a power domain, it takes some time to exit the
* power-off state.
*/
bool sysctl_pwr_set_pd_hd_tim(volatile uint32_t *reg, uint32_t pd_hd_tim)
{
volatile uint32_t *ret = reg;
if((NULL == reg) || (pd_hd_tim > 0xFF))
return false;
else
{
*ret &= 0xfffff00f;
*reg = (*ret) | (pd_hd_tim << 4);
return true;
}
}
/*
* After restoring the power supply of a power domain (bringup), you need to
* wait for a period of time to ensure that the power supply of the power domain
* is fully restored.
*/
bool sysctl_pwr_set_pwr_su_tim(volatile uint32_t *reg, uint32_t pwr_su_tim)
{
volatile uint32_t *ret = reg;
if((NULL == reg) || (pwr_su_tim > 0xFF))
return false;
else
{
*ret &= 0xfff00fff;
*reg = (*ret) | (pwr_su_tim << 12);
return true;
}
}
/* set cpu1 wait for interrupt time */
bool sysctl_pwr_set_wfi_tim(volatile uint32_t *reg, uint32_t wfi_tim)
{
volatile uint32_t *ret = reg;
if((NULL == reg) || (wfi_tim > 0xFFF))
return false;
else
{
*ret &= 0x000fffff;
*reg = (*ret) | (wfi_tim << 20);
return true;
}
}
bool sysctl_pwr_set_tim(sysctl_pwr_domain_e powerdomain, sysctl_pwr_tim_e timtype, uint32_t tim_value)
{
volatile uint32_t *pwr_reg = NULL;
volatile uint32_t *lpi_reg = NULL;
volatile uint32_t *wfi_reg = NULL;
if((powerdomain >= SYSCTL_PD_MAX) || (timtype >= SYSCTL_PWR_MAX_TIM))
return false;
switch(powerdomain)
{
case SYSCTL_PD_CPU1:
{
pwr_reg = (volatile uint32_t *)&sysctl_pwr->cpu1_pwr_tim;
lpi_reg = (volatile uint32_t *)&sysctl_pwr->cpu1_lpi_tim;
wfi_reg = (volatile uint32_t *)&sysctl_pwr->cpu1_pwr_tim;
break;
}
case SYSCTL_PD_AI:
{
pwr_reg = (volatile uint32_t *)&sysctl_pwr->ai_pwr_tim;
lpi_reg = (volatile uint32_t *)&sysctl_pwr->ai_lpi_tim;
break;
}
case SYSCTL_PD_DISP:
{
pwr_reg = (volatile uint32_t *)&sysctl_pwr->disp_pwr_tim;
lpi_reg = (volatile uint32_t *)&sysctl_pwr->disp_lpi_tim;
break;
}
case SYSCTL_PD_VPU:
{
pwr_reg = (volatile uint32_t *)&sysctl_pwr->vpu_pwr_tim;
lpi_reg = (volatile uint32_t *)&sysctl_pwr->vpu_lpi_tim;
break;
}
case SYSCTL_PD_DPU:
{
pwr_reg = (volatile uint32_t *)&sysctl_pwr->dpu_pwr_tim;
lpi_reg = (volatile uint32_t *)&sysctl_pwr->dpu_lpi_tim;
break;
}
default:
return false;
}
switch(timtype)
{
case SYSCTL_PWR_ACK_TO_TIM:
return sysctl_pwr_set_ack_to_tim(pwr_reg, tim_value);
case SYSCTL_PWR_IDLE_TO_TIM:
return sysctl_pwr_set_idle_to_tim(pwr_reg, tim_value);
case SYSCTL_PWR_IDLE_HD_TIM:
return sysctl_pwr_set_idle_hd_tim(pwr_reg, tim_value);
case SYSCTL_PWR_ISO_SU_TIM:
return sysctl_pwr_set_iso_su_tim(lpi_reg, tim_value);
case SYSCTL_PWR_PD_HD_TIM:
return sysctl_pwr_set_pd_hd_tim(lpi_reg, tim_value);
case SYSCTL_PWR_SU_TIM:
return sysctl_pwr_set_pwr_su_tim(lpi_reg, tim_value);
case SYSCTL_PWR_WFI_TIM:
return sysctl_pwr_set_wfi_tim(wfi_reg,tim_value);
default:
return false;
}
}
/*****************************************************************************************
* GET POWER DOMAIN'S TIME
* powerdomain:power domain
* timtype: idleReq_to_idleAck, idleAck_to_idle.....
* tim_value: ack_to_tim, idle_to_tim......
*****************************************************************************************/
/* ack timeout value, lpi idleReq to idleAck */
bool sysctl_pwr_get_ack_to_tim(volatile uint32_t *reg, uint32_t *ack_to_tim)
{
if((NULL == reg) || (NULL == ack_to_tim))
return false;
*ack_to_tim = ((*reg) >> 0) & 0x1F;
return true;
}
/* idle timeout value, lpi idleAck to idle */
bool sysctl_pwr_get_idle_to_tim(volatile uint32_t *reg, uint32_t *idle_to_tim)
{
if((NULL == reg) || (NULL == idle_to_tim))
return false;
*idle_to_tim = ((*reg) >> 8) & 0x1F;
return true;
}
/* NOC power controller in idle min time, idle to idelReq(inactive) */
bool sysctl_pwr_get_idle_hd_tim(volatile uint32_t *reg, uint32_t *idle_hd_tim)
{
if((NULL == reg) || (NULL == idle_hd_tim))
return false;
*idle_hd_tim = ((*reg) >> 16) & 0x3F;
return true;
}
/*
* After turning ISO on/off, you need to wait for a while to ensure that the
* isolation cells in the power domain are actually enabled/disabled.
*/
bool sysctl_pwr_get_iso_su_tim(volatile uint32_t *reg, uint32_t *iso_su_tim)
{
if((NULL == reg) || (NULL == iso_su_tim))
return false;
*iso_su_tim = ((*reg) >> 0) & 0xF;
return true;
}
/*
* After powering off a power domain, it takes some time to exit the power-off
* state.
*/
bool sysctl_pwr_get_pd_hd_tim(volatile uint32_t *reg, uint32_t *pd_hd_tim)
{
if((NULL == reg) || (NULL == pd_hd_tim))
return false;
*pd_hd_tim = ((*reg) >> 4) & 0xFF;
return true;
}
/*
* After restoring the power supply of a power domain (bringup), you need to
* wait for a period of time to ensure that the power supply of the power domain
* is fully restored.
*/
bool sysctl_pwr_get_pwr_su_tim(volatile uint32_t *reg, uint32_t *pwr_su_tim)
{
if((NULL == reg) || (NULL == pwr_su_tim))
return false;
*pwr_su_tim = ((*reg) >> 12) & 0xFF;
return true;
}
/* cpu1 wait for interrupt time */
bool sysctl_pwr_get_wfi_tim(volatile uint32_t *reg, uint32_t *wfi_tim)
{
if((NULL == reg) || (NULL == wfi_tim))
return false;
*wfi_tim = (*reg >> 20) & 0xFFF;
return true;
}
bool sysctl_pwr_get_tim(sysctl_pwr_domain_e powerdomain, sysctl_pwr_tim_e timtype, uint32_t *tim_value)
{
volatile uint32_t *pwr_reg = NULL;
volatile uint32_t *lpi_reg = NULL;
volatile uint32_t *wfi_reg = NULL;
if((powerdomain >= SYSCTL_PD_MAX) || (timtype >= SYSCTL_PWR_MAX_TIM))
return false;
switch(powerdomain)
{
case SYSCTL_PD_CPU1:
{
pwr_reg = (volatile uint32_t *)&sysctl_pwr->cpu1_pwr_tim;
lpi_reg = (volatile uint32_t *)&sysctl_pwr->cpu1_lpi_tim;
wfi_reg = (volatile uint32_t *)&sysctl_pwr->cpu1_pwr_tim;
break;
}
case SYSCTL_PD_AI:
{
pwr_reg = (volatile uint32_t *)&sysctl_pwr->ai_pwr_tim;
lpi_reg = (volatile uint32_t *)&sysctl_pwr->ai_lpi_tim;
break;
}
case SYSCTL_PD_DISP:
{
pwr_reg = (volatile uint32_t *)&sysctl_pwr->disp_pwr_tim;
lpi_reg = (volatile uint32_t *)&sysctl_pwr->disp_lpi_tim;
break;
}
case SYSCTL_PD_VPU:
{
pwr_reg = (volatile uint32_t *)&sysctl_pwr->vpu_pwr_tim;
lpi_reg = (volatile uint32_t *)&sysctl_pwr->vpu_lpi_tim;
break;
}
case SYSCTL_PD_DPU:
{
pwr_reg = (volatile uint32_t *)&sysctl_pwr->dpu_pwr_tim;
lpi_reg = (volatile uint32_t *)&sysctl_pwr->dpu_lpi_tim;
break;
}
default:
return false;
}
switch(timtype)
{
case SYSCTL_PWR_ACK_TO_TIM:
return sysctl_pwr_get_ack_to_tim(pwr_reg, tim_value);
case SYSCTL_PWR_IDLE_TO_TIM:
return sysctl_pwr_get_idle_to_tim(pwr_reg, tim_value);
case SYSCTL_PWR_IDLE_HD_TIM:
return sysctl_pwr_get_idle_hd_tim(pwr_reg, tim_value);
case SYSCTL_PWR_ISO_SU_TIM:
return sysctl_pwr_get_iso_su_tim(lpi_reg, tim_value);
case SYSCTL_PWR_PD_HD_TIM:
return sysctl_pwr_get_pd_hd_tim(lpi_reg, tim_value);
case SYSCTL_PWR_SU_TIM:
return sysctl_pwr_get_pwr_su_tim(lpi_reg, tim_value);
case SYSCTL_PWR_WFI_TIM:
return sysctl_pwr_get_wfi_tim(wfi_reg,tim_value);
default:
return false;
}
}
/*****************************************************************************************
* CPU1 KEEP RESET IN POWEROFF MODE
* powerdomain: power domain
* enable: poweron, keep reset; poweroff, remove reset
*****************************************************************************************/
/* It will not be powered off when not working and can be in a reset state */
bool sysctl_pwr_set_poweroff_keep_reset(sysctl_pwr_domain_e powerdomain, bool enable)
{
volatile uint32_t ret;
if(SYSCTL_PD_CPU1 == powerdomain)
{
ret = sysctl_pwr->cpu1_pwr_lpi_ctl;
ret &= 0xfff7fff7;
if(true == enable)
{
sysctl_pwr->cpu1_pwr_lpi_ctl = ret | ((1 << 3) | (1 << 19));
}
else
{
sysctl_pwr->cpu1_pwr_lpi_ctl = ret | ((0 << 3) | (1 << 19));
}
return true;
}
else
{
return false;
}
}
bool sysctl_pwr_get_poweroff_keep_reset(sysctl_pwr_domain_e powerdomain, bool *enable)
{
if(SYSCTL_PD_CPU1 == powerdomain)
{
if(sysctl_pwr->cpu1_pwr_lpi_ctl & (1 << 3))
*enable = true;
else
*enable = false;
return true;
}
else
{
return false;
}
}
/*****************************************************************************************
* CPU1 AUTO POWERUP OR POWERDOWN
* powerdomain: power domain
* enable: poweron, enable power control unit auto control mode; poweroff, disable auto
*****************************************************************************************/
/*
* In MAIX3, CPU0 and CPU1 power domains support automatic power on and off
* management.
*/
bool sysctl_pwr_set_auto_pwr(sysctl_pwr_domain_e powerdomain, bool enable)
{
volatile uint32_t ret;
if(SYSCTL_PD_CPU1 == powerdomain)
{
ret = sysctl_pwr->cpu1_pwr_lpi_ctl;
ret &= 0xfffbfffb;
if(true == enable)
{
sysctl_pwr->cpu1_pwr_lpi_ctl = ret | ((1 << 2) | (1 << 18));
}
else
{
sysctl_pwr->cpu1_pwr_lpi_ctl = ret | ((0 << 2) | (1 << 18));
}
return true;
}
else
{
return false;
}
}
bool sysctl_pwr_get_auto_pwr(sysctl_pwr_domain_e powerdomain, bool *enable)
{
if(SYSCTL_PD_CPU1 == powerdomain)
{
if(sysctl_pwr->cpu1_pwr_lpi_ctl & (1 << 2))
*enable = true;
else
*enable = false;
return true;
}
else
{
return false;
}
}
/*****************************************************************************************
* POWER DOMAIN REPAIR
* powerdomain: power domain
*****************************************************************************************/
/* When powering up, set the power domain to repair */
bool sysctl_pwr_set_repair_enable(sysctl_pwr_domain_e powerdomain)
{
switch(powerdomain)
{
case SYSCTL_PD_AI:
sysctl_pwr->ai_pwr_lpi_ctl |= (1 << 4) | (1 << 20);
return true;
default:
return false;
}
}
bool sysctl_pwr_check_repair_done(sysctl_pwr_domain_e powerdomain)
{
switch(powerdomain)
{
case SYSCTL_PD_AI:
return (sysctl_pwr->repair_status & (1 << 1)) ? true:false;
case SYSCTL_PD_MAX:
return (sysctl_pwr->repair_status & (1 << 2)) ? true:false;
default:
return false;
}
}
/*****************************************************************************************
* NOC POWER CONTROLLER
* powerdomain: power domain
* enable: true, connect noc, exit idle mode; false, disconnect noc, go idle mode.
*****************************************************************************************/
/*
* Set different power domains to disconnect/connect to NOC and enter/leave
* idle state.
*/
bool sysctl_pwr_set_lpi(sysctl_pwr_domain_e powerdomain, bool enable)
{
switch(powerdomain)
{
case SYSCTL_PD_CPU1:
{
sysctl_pwr->cpu1_pwr_lpi_ctl |= (true == enable) ? ((1 << 5) | (1 << 21)) : ((1 << 4) | (1 << 20));
/* usleep(500); */
rt_thread_delay(1);
if(true == enable)
return (sysctl_pwr->cpu1_pwr_lpi_state & (1 << 3)) ? true:false;
else
return (sysctl_pwr->cpu1_pwr_lpi_state & (1 << 2)) ? true:false;
}
case SYSCTL_PD_AI:
{
sysctl_pwr->ai_pwr_lpi_ctl |= (true == enable) ? ((1 << 3) | (1 << 19)) : ((1 << 2) | (1 << 18));
/* usleep(500); */
rt_thread_delay(1);
if(true == enable)
return (sysctl_pwr->ai_pwr_lpi_state & (1 << 3)) ? true:false;
else
return (sysctl_pwr->ai_pwr_lpi_state & (1 << 2)) ? true:false;
}
case SYSCTL_PD_DISP:
{
sysctl_pwr->disp_lpi_ctl |= (true == enable) ? ((1 << 3) | (1 << 19)) : ((1 << 2) | (1 << 18));
/* usleep(500); */
rt_thread_delay(1);
if(true == enable)
return (sysctl_pwr->disp_lpi_state & (1 << 3)) ? true:false;
else
return (sysctl_pwr->disp_lpi_state & (1 << 2)) ? true:false;
}
case SYSCTL_PD_VPU:
{
sysctl_pwr->vpu_pwr_lpi_ctl |= (true == enable) ? ((1 << 3) | (1 << 19)) : ((1 << 2) | (1 << 18));
/* usleep(500); */
rt_thread_delay(1);
if(true == enable)
return (sysctl_pwr->vpu_lpi_state & (1 << 3)) ? true:false;
else
return (sysctl_pwr->vpu_lpi_state & (1 << 2)) ? true:false;
}
case SYSCTL_PD_DPU:
{
sysctl_pwr->dpu_pwr_lpi_ctl |= (true == enable) ? ((1 << 3) | (1 << 19)) : ((1 << 2) | (1 << 18));
/* usleep(500); */
rt_thread_delay(1);
if(true == enable)
return (sysctl_pwr->dpu_pwr_lpi_state & (1 << 3)) ? true:false;
else
return (sysctl_pwr->dpu_pwr_lpi_state & (1 << 2)) ? true:false;
}
default:
return false;
}
}
/*****************************************************************************************
* POWER DOMAIN ON OR OFF
* powerdomain: power domain
* enable: true for powerup, false for poweroff.
*****************************************************************************************/
bool sysctl_pwr_set_pwr_reg(volatile uint32_t *regctl, volatile uint32_t *regsta, bool enable)
{
/* enable==true, power on; enable==false, power off */
uint32_t mask;
mask = enable ? 0x2 : 0x1;
if (*regsta & mask)
return true;
*regctl = (0x30000 | mask);
for (int i = 0; i < 100; i++)
{
if (*regsta & mask)
return true;
for (int j = 0; j < 5000; j++);
}
return false;
}
bool sysctl_pwr_set_power(sysctl_pwr_domain_e powerdomain, bool enable)
{
volatile uint32_t *pwr_ctl_reg = NULL;
volatile uint32_t *pwr_sta_reg = NULL;
switch(powerdomain)
{
case SYSCTL_PD_CPU1:
{
pwr_ctl_reg = (volatile uint32_t *)&sysctl_pwr->cpu1_pwr_lpi_ctl;
pwr_sta_reg = (volatile uint32_t *)&sysctl_pwr->cpu1_pwr_lpi_state;
break;
}
case SYSCTL_PD_AI:
{
pwr_ctl_reg = (volatile uint32_t *)&sysctl_pwr->ai_pwr_lpi_ctl;
pwr_sta_reg = (volatile uint32_t *)&sysctl_pwr->ai_pwr_lpi_state;
break;
}
case SYSCTL_PD_DISP:
{
pwr_ctl_reg = (volatile uint32_t *)&sysctl_pwr->disp_lpi_ctl;
pwr_sta_reg = (volatile uint32_t *)&sysctl_pwr->disp_lpi_state;
break;
}
case SYSCTL_PD_VPU:
{
pwr_ctl_reg = (volatile uint32_t *)&sysctl_pwr->vpu_pwr_lpi_ctl;
pwr_sta_reg = (volatile uint32_t *)&sysctl_pwr->vpu_lpi_state;
break;
}
case SYSCTL_PD_DPU:
{
pwr_ctl_reg = (volatile uint32_t *)&sysctl_pwr->dpu_pwr_lpi_ctl;
pwr_sta_reg = (volatile uint32_t *)&sysctl_pwr->dpu_pwr_lpi_state;
break;
}
default:
return false;
}
/* repair powerdomain */
/* only powerup need repair */
if(true == enable)
{
(void)sysctl_pwr_set_repair_enable(powerdomain);
}
return sysctl_pwr_set_pwr_reg(pwr_ctl_reg, pwr_sta_reg, enable);
}
bool sysctl_pwr_set_power_multi(sysctl_pwr_domain_e powerdomain, bool enable)
{
bool ret = true;
rt_base_t level;
static uint32_t ref_count[SYSCTL_PD_MAX];
/*
1. enable step for non-DISP power domains:
a. disable interrupt
b. judge ref_count, if == 0, execute sysctl_pwr_set_pwr_reg
c. ref_count++, limit UINT32_MAX
d. enable interrupt
2. disable step for non-DISP power domains:
a. disable interrupt
b. judge ref_count, if == 0, go step d
c. ref_count--, judge ref_count, if == 0, execute sysctl_pwr_set_pwr_reg
d. enable interrupt
3. enable step for DISP power domains:
a. disable interrupt
b. judge ref_count, if == 0, execute
b.1 get HARDLOCK_DISP
b.2 get HARDLOCK_DISP_CPU1
b.3 execute sysctl_pwr_set_pwr_reg
b.4 put HARDLOCK_DISP
c. ref_count++, limit UINT32_MAX
d. enable interrupt
4. disable step for DISP power domains:
a. disable interrupt
b. judge ref_count, if == 0, go step e
c. ref_count--, judge ref_count, if == 0, execute
c.1 get HARDLOCK_DISP
c.2 qeury HARDLOCK_DISP_CPU0, if no get, go step c.4
c.3 put HARDLOCK_DISP_CPU0, execute sysctl_pwr_set_pwr_reg
c.4 put HARDLOCK_DISP_CPU1
c.5 put HARDLOCK_DISP
d. enable interrupt
*/
level = rt_hw_interrupt_disable();
if (enable == true)
{
if (ref_count[powerdomain] == 0)
{
if (powerdomain == SYSCTL_PD_DISP)
{
while (kd_hardlock_lock(HARDLOCK_DISP));
kd_hardlock_lock(HARDLOCK_DISP_CPU1);
ret = sysctl_pwr_set_power(powerdomain, enable);
kd_hardlock_unlock(HARDLOCK_DISP);
} else {
ret = sysctl_pwr_set_power(powerdomain, enable);
}
}
ref_count[powerdomain]++;
if (ref_count[powerdomain] == UINT32_MAX)
rt_kprintf("error: enable too many times\n");
} else if (ref_count[powerdomain])
{
ref_count[powerdomain]--;
if (ref_count[powerdomain] == 0)
{
if (powerdomain == SYSCTL_PD_DISP)
{
while (kd_hardlock_lock(HARDLOCK_DISP));
if (kd_hardlock_lock(HARDLOCK_DISP_CPU0) == 0)
{
kd_hardlock_unlock(HARDLOCK_DISP_CPU0);
ret = sysctl_pwr_set_power(powerdomain, enable);
}
kd_hardlock_unlock(HARDLOCK_DISP_CPU1);
kd_hardlock_unlock(HARDLOCK_DISP);
} else {
ret = sysctl_pwr_set_power(powerdomain, enable);
}
}
}
rt_hw_interrupt_enable(level);
return ret;
}
/* Power Domain Power-up */
bool sysctl_pwr_up(sysctl_pwr_domain_e powerdomain)
{
return sysctl_pwr_set_power_multi(powerdomain, true);
}
/* Power off a power domain */
bool sysctl_pwr_off(sysctl_pwr_domain_e powerdomain)
{
return sysctl_pwr_set_power_multi(powerdomain, false);
}
int rt_hw_sysctl_pwr_init(void)
{
sysctl_pwr = rt_ioremap((void*)PWR_BASE_ADDR, PWR_IO_SIZE);
if(!sysctl_pwr)
{
rt_kprintf("sysctl_pwr ioremap error\n");
return -1;
}
return 0;
}
INIT_BOARD_EXPORT(rt_hw_sysctl_pwr_init);

View File

@ -0,0 +1,174 @@
/* Copyright (c) 2023, Canaan Bright Sight Co., Ltd
*
* 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.
*
* 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 HOLDER 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.
*/
#ifndef __SYSCTL_PWR_H__
#define __SYSCTL_PWR_H__
/* created by yangfan */
#include <stdint.h>
#include <stdbool.h>
/* See TRM 2.3.4 Table 2-3-3 */
typedef struct
{
volatile uint32_t cpu0_pwr_tim; /* 0x00 */
volatile uint32_t cpu0_lpi_tim; /* 0x04 */
volatile uint32_t cpu0_pwr_lpi_ctl; /* 0x08 */
volatile uint32_t cpu0_pwr_lpi_state; /* 0x0c */
volatile uint32_t cpu1_pwr_tim; /* 0x10 */
volatile uint32_t cpu1_lpi_tim; /* 0x14 */
volatile uint32_t cpu1_pwr_lpi_ctl; /* 0x18 */
volatile uint32_t cpu1_pwr_lpi_state; /* 0x1c */
volatile uint32_t ai_pwr_tim; /* 0x20 */
volatile uint32_t ai_lpi_tim; /* 0x24 */
volatile uint32_t ai_pwr_lpi_ctl; /* 0x28 */
volatile uint32_t ai_pwr_lpi_state; /* 0x2c */
volatile uint32_t disp_pwr_tim; /* 0x30 */
volatile uint32_t disp_lpi_tim; /* 0x34 */
volatile uint32_t disp_gpu_tim; /* 0x38 */
volatile uint32_t disp_lpi_ctl; /* 0x3c */
volatile uint32_t disp_lpi_state; /* 0x40 */
volatile uint32_t disp_reserved[7]; /* 0x44-0x4c, 0x50-0x5c */
volatile uint32_t shrm_pwr_tim; /* 0x60 */
volatile uint32_t shrm_lpi_tim; /* 0x64 */
volatile uint32_t shrm_pwr_lpi_ctl; /* 0x68 */
volatile uint32_t shrm_pwr_lpi_state; /* 0x6c */
volatile uint32_t vpu_pwr_tim; /* 0x70 */
volatile uint32_t vpu_lpi_tim; /* 0x74 */
volatile uint32_t vpu_qch_tim; /* 0x78 */
volatile uint32_t vpu_pwr_lpi_ctl; /* 0x7c */
volatile uint32_t vpu_lpi_state; /* 0x80 */
volatile uint32_t vpu_reserved[3]; /* 0x84-0x8c */
volatile uint32_t mctl_pwr_tim0; /* 0x90 */
volatile uint32_t mctl_noc_lpi_tim; /* 0x94 */
volatile uint32_t mctl_axi_lpi_tim; /* 0x98 */
volatile uint32_t mctl_pwr_lpi_ctl; /* 0x9c */
volatile uint32_t mctl_clock_switch; /* 0xa0 */
volatile uint32_t mctl_lpi_state; /* 0xa4 */
volatile uint32_t mctl_reserved[22]; /* 0xa8-0xac, 0xb0-0xbc, 0xc0-0xcc, 0xd0-0xdc, 0xe0-0xec, 0xf0-0xfc */
volatile uint32_t dpu_pwr_tim; /* 0x100 */
volatile uint32_t dpu_lpi_tim; /* 0x104 */
volatile uint32_t dpu_pwr_lpi_ctl; /* 0x108 */
volatile uint32_t dpu_pwr_lpi_state; /* 0x10c */
volatile uint32_t hi_pwr_tim; /* 0x110 */
volatile uint32_t hi_lpi_tim; /* 0x114 */
volatile uint32_t hi_pwr_lpi_ctl; /* 0x118 */
volatile uint32_t hi_lpi_state; /* 0x11c */
volatile uint32_t ls_pwr_tim; /* 0x120 */
volatile uint32_t ls_lpi_tim; /* 0x124 */
volatile uint32_t ls_pwr_lpi_ctl; /* 0x128 */
volatile uint32_t ls_lpi_state; /* 0x12c */
volatile uint32_t sec_pwr_tim; /* 0x130 */
volatile uint32_t sec_lpi_tim; /* 0x134 */
volatile uint32_t sec_pwr_lpi_ctl; /* 0x138 */
volatile uint32_t sec_pwr_lpi_state; /* 0x13c */
volatile uint32_t isp_pwr_tim; /* 0x140 */
volatile uint32_t isp_lpi_tim; /* 0x144 */
volatile uint32_t isp_pwr_lpi_ctl; /* 0x148 */
volatile uint32_t isp_pwr_lpi_state; /* 0x14c */
volatile uint32_t pmu_pwr_tim; /* 0x150 */
volatile uint32_t pmu_lpi_tim; /* 0x154 */
volatile uint32_t pmu_pwr_lpi_ctl; /* 0x158 */
volatile uint32_t pmu_pwr_lpi_state; /* 0x15c */
volatile uint32_t repair_status; /* 0x160 */
volatile uint32_t sram0_repair_tim; /* 0x164 */
volatile uint32_t ssys_ctl_gpio_ctl; /* 0x168 */
volatile uint32_t ssys_reserved; /* 0x16c */
volatile uint32_t ssys_ctl_gpio_en0; /* 0x170 */
volatile uint32_t ssys_ctl_gpio_en1; /* 0x174 */
volatile uint32_t cpu_repair_tim; /* 0x178 */
} sysctl_pwr_s;
/* See TRM 2.3.1 Table 2-3-1 */
typedef enum
{
SYSCTL_PD_CPU1,
SYSCTL_PD_AI,
SYSCTL_PD_DISP,
SYSCTL_PD_VPU,
SYSCTL_PD_DPU,
SYSCTL_PD_MAX,
} sysctl_pwr_domain_e;
typedef enum
{
SYSCTL_PWR_ACK_TO_TIM, /* idleReq to idleAck max time */
SYSCTL_PWR_IDLE_TO_TIM, /* idleAck to idle max time */
SYSCTL_PWR_IDLE_HD_TIM, /* idle hold tim, from idle to cancel idleReq min time */
SYSCTL_PWR_ISO_SU_TIM, /* isolation setup tim */
SYSCTL_PWR_PD_HD_TIM, /* power done hardware tim */
SYSCTL_PWR_SU_TIM, /* Power bringup tim */
SYSCTL_PWR_WFI_TIM, /* wait for interrupt tim*/
SYSCTL_PWR_MAX_TIM,
} sysctl_pwr_tim_e;
bool sysctl_pwr_set_iso_su_tim(volatile uint32_t *reg, uint32_t iso_su_tim);
bool sysctl_pwr_set_pd_hd_tim(volatile uint32_t *reg, uint32_t pd_hd_tim);
bool sysctl_pwr_set_pwr_su_tim(volatile uint32_t *reg, uint32_t pwr_su_tim);
bool sysctl_pwr_set_ack_to_tim(volatile uint32_t *reg, uint32_t ack_to_tim);
bool sysctl_pwr_set_idle_to_tim(volatile uint32_t *reg, uint32_t idle_to_tim);
bool sysctl_pwr_set_idle_hd_tim(volatile uint32_t *reg, uint32_t idle_hd_tim);
bool sysctl_pwr_set_wfi_tim(volatile uint32_t *reg, uint32_t wfi_tim);
bool sysctl_pwr_set_tim(sysctl_pwr_domain_e powerdomain, sysctl_pwr_tim_e timtype, uint32_t tim_value);
bool sysctl_pwr_get_iso_su_tim(volatile uint32_t *reg, uint32_t *iso_su_tim);
bool sysctl_pwr_get_pd_hd_tim(volatile uint32_t *reg, uint32_t *pd_hd_tim);
bool sysctl_pwr_get_pwr_su_tim(volatile uint32_t *reg, uint32_t *pwr_su_tim);
bool sysctl_pwr_get_ack_to_tim(volatile uint32_t *reg, uint32_t *ack_to_tim);
bool sysctl_pwr_get_idle_to_tim(volatile uint32_t *reg, uint32_t *idle_to_tim);
bool sysctl_pwr_get_idle_hd_tim(volatile uint32_t *reg, uint32_t *idle_hd_tim);
bool sysctl_pwr_get_wfi_tim(volatile uint32_t *reg, uint32_t *wfi_tim);
bool sysctl_pwr_get_tim(sysctl_pwr_domain_e powerdomain, sysctl_pwr_tim_e timtype, uint32_t *tim_value);
bool sysctl_pwr_set_poweroff_keep_reset(sysctl_pwr_domain_e powerdomain, bool enable);
bool sysctl_pwr_get_poweroff_keep_reset(sysctl_pwr_domain_e powerdomain, bool *enable);
bool sysctl_pwr_set_auto_pwr(sysctl_pwr_domain_e powerdomain, bool enable);
bool sysctl_pwr_get_auto_pwr(sysctl_pwr_domain_e powerdomain, bool *enable);
bool sysctl_pwr_set_repair_enable(sysctl_pwr_domain_e powerdomain);
bool sysctl_pwr_check_repair_done(sysctl_pwr_domain_e powerdomain);
bool sysctl_pwr_set_lpi(sysctl_pwr_domain_e powerdomain, bool enable);
bool sysctl_pwr_set_pwr_reg(volatile uint32_t *regctl, volatile uint32_t *regsta, bool enable);
bool sysctl_pwr_set_power(sysctl_pwr_domain_e powerdomain, bool enable);
/* Following two APIs are used to control the power on and off of the SOC power domain */
bool sysctl_pwr_up(sysctl_pwr_domain_e powerdomain);
bool sysctl_pwr_off(sysctl_pwr_domain_e powerdomain);
#endif

View File

@ -0,0 +1,19 @@
# RT-Thread building script for component
from building import *
cwd = GetCurrentDir()
src = Glob('*.c')
CPPPATH = [cwd]
group = DefineGroup('Sysctl_reset', src, depend = [''], CPPPATH = CPPPATH)
objs = [group]
file_list = os.listdir(cwd)
for item in file_list:
if os.path.isfile(os.path.join(cwd, item, 'SConscript')):
objs = objs + SConscript(os.path.join(item, 'SConscript'))
Return('objs')

View File

@ -0,0 +1,635 @@
/* Copyright (c) 2023, Canaan Bright Sight Co., Ltd
*
* 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.
*
* 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 HOLDER 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.
*/
#include <rtthread.h>
#include <stdbool.h>
#include "sysctl_rst.h"
#include "ioremap.h"
#include "board.h"
volatile sysctl_rst_t* sysctl_rst = (volatile sysctl_rst_t*)RMU_BASE_ADDR;
static bool sysctl_reset_cpu(volatile uint32_t *reset_reg, uint8_t reset_bit, uint8_t done_bit)
{
/* clear done bit */
*reset_reg |= (1 << done_bit);
*reset_reg |= (1 << (done_bit + 0x10)); /* write enable */
/* usleep(100); */
rt_thread_delay(1);
/* set reset bit */
*reset_reg |= (1 << reset_bit);
*reset_reg |= (1 << (reset_bit + 0x10)); /* write enable */
/* usleep(100); */
rt_thread_delay(1);
/* clear reset bit */
if(0x9110100c == (uint64_t)reset_reg)
{
*reset_reg &= ~(1 << reset_bit);
*reset_reg |= (1 << (reset_bit + 0x10)); /* write enable */
}
/* usleep(100); */
rt_thread_delay(1);
/* check done bit */
if(*reset_reg & (1 << done_bit))
return true;
else
return false;
}
static bool sysctl_reset_hw_done(volatile uint32_t *reset_reg, uint8_t reset_bit, uint8_t done_bit)
{
*reset_reg |= (1 << done_bit); /* clear done bit */
/* usleep(100); */
rt_thread_delay(1);
*reset_reg |= (1 << reset_bit); /* set reset bit */
/* usleep(100); */
rt_thread_delay(1);
/* check done bit */
if(*reset_reg & (1 << done_bit))
return true;
else
return false;
}
static bool sysctl_reset_sw_done(volatile uint32_t *reset_reg, uint8_t reset_bit, uint32_t reset_en)
{
if(0 == reset_en)
{
if((0x91101020 == (uint64_t)reset_reg) || (0x91101024 == (uint64_t)reset_reg) || (0x91101080 == (uint64_t)reset_reg) || (0x91101064 == (uint64_t)reset_reg))
{
*reset_reg &= ~(1 << reset_bit); /* set reset bit, 0 is assert */
}
else
{
*reset_reg |= (1 << reset_bit); /* set reset bit, 1 is assert */
}
}
else
{
*reset_reg |= (1 << reset_bit) | (1 << reset_en); /* set reset bit */
}
/* usleep(100); */
rt_thread_delay(1);
if((0x91101004 != (uint64_t)reset_reg) && (0x9110100c != (uint64_t)reset_reg))
{
if(0x911010a8 == (uint64_t)reset_reg)
{
*reset_reg &= ~(1 << reset_bit); /* clear reset bit, 0 is clear */
}
else
{
*reset_reg |= (1 << reset_bit); /* clear reset bit, 1 is clear */
}
}
/* usleep(100); */
rt_thread_delay(1);
return true;
}
bool sysctl_reset(sysctl_reset_e reset)
{
switch(reset)
{
case SYSCTL_RESET_CPU0_CORE:
return sysctl_reset_cpu((volatile uint32_t *)&sysctl_rst->cpu0_rst_ctl, 0, 12);
case SYSCTL_RESET_CPU1_CORE:
return sysctl_reset_cpu((volatile uint32_t *)&sysctl_rst->cpu1_rst_ctl, 0, 12);
case SYSCTL_RESET_AI:
return sysctl_reset_hw_done((volatile uint32_t *)&sysctl_rst->ai_rst_ctl, 0, 31);
case SYSCTL_RESET_VPU:
return sysctl_reset_hw_done((volatile uint32_t *)&sysctl_rst->vpu_rst_ctl, 0, 31);
case SYSCTL_RESET_HS:
return sysctl_reset_hw_done((volatile uint32_t *)&sysctl_rst->hisys_rst_ctl, 0, 4);
case SYSCTL_RESET_HS_AHB:
return sysctl_reset_hw_done((volatile uint32_t *)&sysctl_rst->hisys_rst_ctl, 1, 5);
case SYSCTL_RESET_SDIO0:
return sysctl_reset_hw_done((volatile uint32_t *)&sysctl_rst->sdc_rst_ctl, 0, 28);
case SYSCTL_RESET_SDIO1:
return sysctl_reset_hw_done((volatile uint32_t *)&sysctl_rst->sdc_rst_ctl, 1, 29);
case SYSCTL_RESET_SDIO_AXI:
return sysctl_reset_hw_done((volatile uint32_t *)&sysctl_rst->sdc_rst_ctl, 2, 30);
case SYSCTL_RESET_USB0:
return sysctl_reset_hw_done((volatile uint32_t *)&sysctl_rst->usb_rst_ctl, 0, 28);
case SYSCTL_RESET_USB1:
return sysctl_reset_hw_done((volatile uint32_t *)&sysctl_rst->usb_rst_ctl, 1, 29);
case SYSCTL_RESET_USB0_AHB:
return sysctl_reset_hw_done((volatile uint32_t *)&sysctl_rst->usb_rst_ctl, 0, 30);
case SYSCTL_RESET_USB1_AHB:
return sysctl_reset_hw_done((volatile uint32_t *)&sysctl_rst->usb_rst_ctl, 1, 31);
case SYSCTL_RESET_SPI0:
return sysctl_reset_hw_done((volatile uint32_t *)&sysctl_rst->spi_rst_ctl, 0, 28);
case SYSCTL_RESET_SPI1:
return sysctl_reset_hw_done((volatile uint32_t *)&sysctl_rst->spi_rst_ctl, 1, 29);
case SYSCTL_RESET_SPI2:
return sysctl_reset_hw_done((volatile uint32_t *)&sysctl_rst->spi_rst_ctl, 2, 30);
case SYSCTL_RESET_SEC:
return sysctl_reset_hw_done((volatile uint32_t *)&sysctl_rst->sec_rst_ctl, 0, 31);
case SYSCTL_RESET_PDMA:
return sysctl_reset_hw_done((volatile uint32_t *)&sysctl_rst->dma_rst_ctl, 0, 28);
case SYSCTL_RESET_SDMA:
return sysctl_reset_hw_done((volatile uint32_t *)&sysctl_rst->dma_rst_ctl, 1, 29);
case SYSCTL_RESET_DECOMPRESS:
return sysctl_reset_hw_done((volatile uint32_t *)&sysctl_rst->decompress_rst_ctl, 0, 31);
case SYSCTL_RESET_SRAM:
return sysctl_reset_hw_done((volatile uint32_t *)&sysctl_rst->sram_rst_ctl, 0, 28);
case SYSCTL_RESET_SHRM_AXIM:
return sysctl_reset_hw_done((volatile uint32_t *)&sysctl_rst->sram_rst_ctl, 2, 30);
case SYSCTL_RESET_SHRM_AXIS:
return sysctl_reset_hw_done((volatile uint32_t *)&sysctl_rst->sram_rst_ctl, 3, 31);
case SYSCTL_RESET_NONAI2D:
return sysctl_reset_hw_done((volatile uint32_t *)&sysctl_rst->nonai2d_rst_ctl, 0, 31);
case SYSCTL_RESET_MCTL:
return sysctl_reset_hw_done((volatile uint32_t *)&sysctl_rst->mctl_rst_ctl, 0, 31);
case SYSCTL_RESET_ISP:
return sysctl_reset_hw_done((volatile uint32_t *)&sysctl_rst->isp_rst_ctl, 6, 29);
case SYSCTL_RESET_ISP_DW:
return sysctl_reset_hw_done((volatile uint32_t *)&sysctl_rst->isp_rst_ctl, 5, 28);
case SYSCTL_RESET_DPU:
return sysctl_reset_hw_done((volatile uint32_t *)&sysctl_rst->dpu_rst_ctl, 0, 31);
case SYSCTL_RESET_DISP:
return sysctl_reset_hw_done((volatile uint32_t *)&sysctl_rst->disp_rst_ctl, 0, 31);
case SYSCTL_RESET_GPU:
return sysctl_reset_hw_done((volatile uint32_t *)&sysctl_rst->v2p5d_rst_ctl, 0, 31);
case SYSCTL_RESET_AUDIO:
return sysctl_reset_hw_done((volatile uint32_t *)&sysctl_rst->audio_rst_ctl, 0, 31);
case SYSCTL_RESET_TIMER0:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->soc_ctl_rst_ctl, 0, 0);
case SYSCTL_RESET_TIMER1:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->soc_ctl_rst_ctl, 1, 0);
case SYSCTL_RESET_TIMER2:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->soc_ctl_rst_ctl, 2, 0);
case SYSCTL_RESET_TIMER3:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->soc_ctl_rst_ctl, 3, 0);
case SYSCTL_RESET_TIMER4:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->soc_ctl_rst_ctl, 4, 0);
case SYSCTL_RESET_TIMER5:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->soc_ctl_rst_ctl, 5, 0);
case SYSCTL_RESET_TIMER_APB:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->soc_ctl_rst_ctl, 6, 0);
case SYSCTL_RESET_HDI:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->soc_ctl_rst_ctl, 7, 0);
case SYSCTL_RESET_WDT0:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->soc_ctl_rst_ctl, 12, 0);
case SYSCTL_RESET_WDT1:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->soc_ctl_rst_ctl, 13, 0);
case SYSCTL_RESET_WDT0_APB:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->soc_ctl_rst_ctl, 14, 0);
case SYSCTL_RESET_WDT1_APB:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->soc_ctl_rst_ctl, 15, 0);
case SYSCTL_RESET_TS_APB:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->soc_ctl_rst_ctl, 16, 0);
case SYSCTL_RESET_MAILBOX:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->soc_ctl_rst_ctl, 17, 0);
case SYSCTL_RESET_STC:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->soc_ctl_rst_ctl, 18, 0);
case SYSCTL_RESET_PMU:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->soc_ctl_rst_ctl, 19, 0);
case SYSCTL_RESET_LS_APB:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->losys_rst_ctl, 0, 0);
case SYSCTL_RESET_UART0:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->losys_rst_ctl, 1, 0);
case SYSCTL_RESET_UART1:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->losys_rst_ctl, 2, 0);
case SYSCTL_RESET_UART2:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->losys_rst_ctl, 3, 0);
case SYSCTL_RESET_UART3:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->losys_rst_ctl, 4, 0);
case SYSCTL_RESET_UART4:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->losys_rst_ctl, 5, 0);
case SYSCTL_RESET_I2C0:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->losys_rst_ctl, 6, 0);
case SYSCTL_RESET_I2C1:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->losys_rst_ctl, 7, 0);
case SYSCTL_RESET_I2C2:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->losys_rst_ctl, 8, 0);
case SYSCTL_RESET_I2C3:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->losys_rst_ctl, 9, 0);
case SYSCTL_RESET_I2C4:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->losys_rst_ctl, 10, 0);
case SYSCTL_RESET_JAMLINK0_APB:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->losys_rst_ctl, 11, 0);
case SYSCTL_RESET_JAMLINK1_APB:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->losys_rst_ctl, 12, 0);
case SYSCTL_RESET_JAMLINK2_APB:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->losys_rst_ctl, 13, 0);
case SYSCTL_RESET_JAMLINK3_APB:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->losys_rst_ctl, 14, 0);
case SYSCTL_RESET_CODEC_APB:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->losys_rst_ctl, 17, 0);
case SYSCTL_RESET_GPIO_DB:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->losys_rst_ctl, 18, 0);
case SYSCTL_RESET_GPIO_APB:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->losys_rst_ctl, 19, 0);
case SYSCTL_RESET_ADC:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->losys_rst_ctl, 20, 0);
case SYSCTL_RESET_ADC_APB:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->losys_rst_ctl, 21, 0);
case SYSCTL_RESET_PWM_APB:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->losys_rst_ctl, 22, 0);
case SYSCTL_RESET_CPU0_FLUSH:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->cpu0_rst_ctl, 4, 20);
case SYSCTL_RESET_CPU1_FLUSH:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->cpu1_rst_ctl, 4, 20);
case SYSCTL_RESET_SHRM_APB:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->sram_rst_ctl, 1, 0);
case SYSCTL_RESET_CSI0_APB:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->isp_rst_ctl, 0, 0);
case SYSCTL_RESET_CSI1_APB:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->isp_rst_ctl, 1, 0);
case SYSCTL_RESET_CSI2_APB:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->isp_rst_ctl, 2, 0);
case SYSCTL_RESET_CSI_DPHY_APB:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->isp_rst_ctl, 3, 0);
case SYSCTL_RESET_ISP_AHB:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->isp_rst_ctl, 4, 0);
case SYSCTL_RESET_M0:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->isp_rst_ctl, 7, 0);
case SYSCTL_RESET_M1:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->isp_rst_ctl, 8, 0);
case SYSCTL_RESET_M2:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->isp_rst_ctl, 9, 0);
case SYSCTL_RESET_SPI2AXI:
return sysctl_reset_sw_done((volatile uint32_t *)&sysctl_rst->spi2axi_rst_ctl, 0, 0);
default:
return false;
}
}
bool sysctl_set_reset_time(sysctl_reset_time_e reset, uint32_t tim0, uint32_t tim1, uint32_t tim2)
{
volatile uint32_t ret;
switch(reset)
{
case SYSCTL_RESET_TIME_CPU0:
{
if((tim1 > 0xF) || (tim2 > 0xF))
{
return false;
}
else
{
ret = sysctl_rst->cpu0_rst_tim;
ret &= 0xf0000fff;
sysctl_rst->cpu0_rst_tim = ret | ((tim1 << 12) | (tim2 << 20));
return true;
}
}
case SYSCTL_RESET_TIME_CPU0_APB:
{
if((tim1 > 0xF) || (tim2 > 0xF))
{
return false;
}
else
{
ret = sysctl_rst->cpu0_rst_tim;
ret &= 0xfffff00f;
sysctl_rst->cpu0_rst_tim = ret | ((tim1 << 4) | (tim2 << 8));
return true;
}
}
case SYSCTL_RESET_TIME_CPU1:
{
if((tim1 > 0xF) || (tim2 > 0xF))
{
return false;
}
else
{
ret = sysctl_rst->cpu1_rst_tim;
ret &= 0xfff00fff;
sysctl_rst->cpu1_rst_tim = ret | ((tim1 << 12) | (tim2 << 16));
return true;
}
}
case SYSCTL_RESET_TIME_CPU1_APB:
{
if((tim1 > 0xF) || (tim2 > 0xF))
{
return false;
}
else
{
ret = sysctl_rst->cpu1_rst_tim;
ret &= 0xfffff00f;
sysctl_rst->cpu1_rst_tim = ret | ((tim1 << 4) | (tim2 << 8));
return true;
}
}
case SYSCTL_RESET_TIME_AI:
{
if((tim1 > 0xF) || (tim2 > 0xF))
{
return false;
}
else
{
ret = sysctl_rst->ai_rst_tim;
ret &= 0xfffff00f;
sysctl_rst->ai_rst_tim = ret | ((tim1 << 4) | (tim2 << 8));
return true;
}
}
case SYSCTL_RESET_TIME_VPU:
{
if((tim1 > 0xF) || (tim2 > 0xF))
{
return false;
}
else
{
ret = sysctl_rst->vpu_rst_tim;
ret &= 0xfffff00f;
sysctl_rst->vpu_rst_tim = ret | ((tim1 << 4) | (tim2 << 8));
return true;
}
}
case SYSCTL_RESET_TIME_HS_HCLK:
{
if((tim1 > 0x1F) || (tim2 > 0xF))
{
return false;
}
else
{
ret = sysctl_rst->hisys_hclk_tim;
ret &= 0xfff0f0ff;
sysctl_rst->hisys_hclk_tim = ret | ((tim1 << 8) | (tim2 << 16));
return true;
}
}
case SYSCTL_RESET_TIME_SDCTL:
{
if((tim1 > 0x1F) || (tim2 > 0xF))
{
return false;
}
else
{
ret = sysctl_rst->sdctl_rst_tim;
ret &= 0xfff0f0ff;
sysctl_rst->sdctl_rst_tim = ret | ((tim1 << 8) | (tim2 << 16));
return true;
}
}
case SYSCTL_RESET_TIME_USB:
{
if((tim1 > 0xF) || (tim2 > 0xF))
{
return false;
}
else
{
ret = sysctl_rst->usb_rst_tim;
ret &= 0xffffff00;
sysctl_rst->usb_rst_tim = ret | ((tim1 << 0) | (tim2 << 4));
return true;
}
}
case SYSCTL_RESET_TIME_USB_AHB:
{
if((tim1 > 0xF) || (tim2 > 0xF))
{
return false;
}
else
{
ret = sysctl_rst->usb_rst_tim;
ret &= 0xff0000ff;
sysctl_rst->usb_rst_tim = ret | ((tim1 << 8) | (tim2 << 16));
return true;
}
}
case SYSCTL_RESET_TIME_SPI:
{
if((tim1 > 0x3F) || (tim2 > 0xF))
{
return false;
}
else
{
ret = sysctl_rst->spi_rst_tim;
ret &= 0xfff0f0ff;
sysctl_rst->spi_rst_tim = ret | ((tim1 << 8) | (tim2 << 16));
return true;
}
}
case SYSCTL_RESET_TIME_SEC_SYS:
{
if((tim1 > 0xFF) || (tim2 > 0xF))
{
return false;
}
else
{
ret = sysctl_rst->sec_sys_rst_tim;
ret &= 0xfff0f0ff;
sysctl_rst->sec_sys_rst_tim = ret | ((tim1 << 8) | (tim2 << 16));
return true;
}
}
case SYSCTL_RESET_TIME_DMAC:
{
if((tim1 > 0x7) || (tim2 > 0x7))
{
return false;
}
else
{
ret = sysctl_rst->dmac_rst_tim;
ret &= 0xfff0f0ff;
sysctl_rst->dmac_rst_tim = ret | ((tim1 << 8) | (tim2 << 16));
return true;
}
}
case SYSCTL_RESET_TIME_DECOMPRESS:
{
if((tim1 > 0x7) || (tim2 > 0x7))
{
return false;
}
else
{
ret = sysctl_rst->decompress_rst_tim;
ret &= 0xfff0f0ff;
sysctl_rst->decompress_rst_tim = ret | ((tim1 << 8) | (tim2 << 16));
return true;
}
}
case SYSCTL_RESET_TIME_SRAM:
{
if((tim1 > 0xF) || (tim2 > 0xF))
{
return false;
}
else
{
ret = sysctl_rst->sram_rst_tim;
ret &= 0xfff0f0ff;
sysctl_rst->sram_rst_tim = ret | ((tim1 << 8) | (tim2 << 16));
return true;
}
}
case SYSCTL_RESET_TIME_NONAI2D:
{
if((tim1 > 0xF) || (tim2 > 0xF))
{
return false;
}
else
{
ret = sysctl_rst->nonai2d_rst_tim;
ret &= 0xfff0f0ff;
sysctl_rst->nonai2d_rst_tim = ret | ((tim1 << 8) | (tim2 << 16));
return true;
}
}
case SYSCTL_RESET_TIME_MCTL:
{
if(tim0 > 0xF)
{
return false;
}
else
{
ret = sysctl_rst->mctl_rst_tim;
ret &= 0xffffffc0;
sysctl_rst->mctl_rst_tim = ret | (tim0 << 0);
return true;
}
}
case SYSCTL_RESET_TIME_ISP:
{
if((tim0 > 0xFF) || (tim1 > 0xF) || (tim2 > 0xF))
{
return false;
}
else
{
ret = sysctl_rst->isp_rst_tim;
ret &= 0xfff0f0f0;
sysctl_rst->isp_rst_tim = ret | ((tim0 << 0) | (tim1 << 8) | (tim2 << 16));
return true;
}
}
case SYSCTL_RESET_TIME_ISP_DW:
{
if((tim0 > 0xFF) || (tim1 > 0xF) || (tim2 > 0xF))
{
return false;
}
else
{
ret = sysctl_rst->isp_dw_rst_tim;
ret &= 0xfff0f0f0;
sysctl_rst->isp_dw_rst_tim = ret | ((tim0 << 0) | (tim1 << 8) | (tim2 << 16));
return true;
}
}
case SYSCTL_RESET_TIME_DPU:
{
if((tim1 > 0xF) || (tim2 > 0xF))
{
return false;
}
else
{
ret = sysctl_rst->dpu_rst_tim;
ret &= 0xfff0f0ff;
sysctl_rst->dpu_rst_tim = ret | ((tim1 << 8) | (tim2 << 16));
return true;
}
}
case SYSCTL_RESET_TIME_DISP_SYS:
{
if((tim0 > 0xFF) || (tim1 > 0xFF) || (tim2 > 0xF))
{
return false;
}
else
{
ret = sysctl_rst->disp_sys_rst_tim;
ret &= 0xfff0f0f0;
sysctl_rst->disp_sys_rst_tim = ret | ((tim0 << 0) | (tim1 << 8) | (tim2 << 16));
return true;
}
}
case SYSCTL_RESET_TIME_V2P5D_SYS:
{
if((tim0 > 0xFF) || (tim1 > 0xFF) || (tim2 > 0xF))
{
return false;
}
else
{
ret = sysctl_rst->v2p5d_sys_rst_tim;
ret &= 0xfff0f0f0;
sysctl_rst->v2p5d_sys_rst_tim = ret | ((tim0 << 0) | (tim1 << 8) | (tim2 << 16));
return true;
}
}
case SYSCTL_RESET_TIME_AUDIO:
{
if((tim1 > 0xF) || (tim2 > 0xF))
{
return false;
}
else
{
ret = sysctl_rst->audio_rst_tim;
ret &= 0xfffff00f;
sysctl_rst->audio_rst_tim = ret | ((tim1 << 4) | (tim2 << 8));
return true;
}
}
default:
return false;
}
}
int rt_hw_sysctl_rst_init(void)
{
sysctl_rst = rt_ioremap((void*)RMU_BASE_ADDR, RMU_IO_SIZE);
if(!sysctl_rst)
{
rt_kprintf("sysctl_rst ioremap error\n");
return -1;
}
return 0;
}
INIT_BOARD_EXPORT(rt_hw_sysctl_rst_init);

View File

@ -0,0 +1,199 @@
/* Copyright (c) 2023, Canaan Bright Sight Co., Ltd
*
* 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.
*
* 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 HOLDER 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.
*/
#ifndef __SYSCTL_RST_H__
#define __SYSCTL_RST_H__
/* created by yangfan */
#include <stdint.h>
#include "stdbool.h"
typedef enum
{
SYSCTL_RESET_CPU0_CORE,
/* SYSCTL_RESET_CPU0_APB, */
/* SYSCTL_RESET_CPU0_TDI, */
SYSCTL_RESET_CPU0_FLUSH,
SYSCTL_RESET_CPU1_CORE,
/* SYSCTL_RESET_CPU1_APB, */
SYSCTL_RESET_CPU1_FLUSH,
SYSCTL_RESET_AI,
SYSCTL_RESET_VPU,
SYSCTL_RESET_HS,
SYSCTL_RESET_HS_AHB,
SYSCTL_RESET_SDIO0,
SYSCTL_RESET_SDIO1,
SYSCTL_RESET_SDIO_AXI,
SYSCTL_RESET_USB0,
SYSCTL_RESET_USB1,
SYSCTL_RESET_USB0_AHB,
SYSCTL_RESET_USB1_AHB,
SYSCTL_RESET_SPI0,
SYSCTL_RESET_SPI1,
SYSCTL_RESET_SPI2,
SYSCTL_RESET_SEC,
SYSCTL_RESET_PDMA,
SYSCTL_RESET_SDMA,
SYSCTL_RESET_DECOMPRESS,
SYSCTL_RESET_SRAM,
SYSCTL_RESET_SHRM_AXIM,
SYSCTL_RESET_SHRM_AXIS,
SYSCTL_RESET_SHRM_APB,
SYSCTL_RESET_NONAI2D,
SYSCTL_RESET_MCTL,
SYSCTL_RESET_ISP,
SYSCTL_RESET_ISP_DW,
SYSCTL_RESET_CSI0_APB,
SYSCTL_RESET_CSI1_APB,
SYSCTL_RESET_CSI2_APB,
SYSCTL_RESET_CSI_DPHY_APB,
SYSCTL_RESET_ISP_AHB,
SYSCTL_RESET_M0,
SYSCTL_RESET_M1,
SYSCTL_RESET_M2,
SYSCTL_RESET_DPU,
SYSCTL_RESET_DISP,
SYSCTL_RESET_GPU,
SYSCTL_RESET_AUDIO,
SYSCTL_RESET_TIMER0,
SYSCTL_RESET_TIMER1,
SYSCTL_RESET_TIMER2,
SYSCTL_RESET_TIMER3,
SYSCTL_RESET_TIMER4,
SYSCTL_RESET_TIMER5,
SYSCTL_RESET_TIMER_APB,
SYSCTL_RESET_HDI,
SYSCTL_RESET_WDT0,
SYSCTL_RESET_WDT1,
SYSCTL_RESET_WDT0_APB,
SYSCTL_RESET_WDT1_APB,
SYSCTL_RESET_TS_APB,
SYSCTL_RESET_MAILBOX,
SYSCTL_RESET_STC,
SYSCTL_RESET_PMU,
SYSCTL_RESET_LS_APB,
SYSCTL_RESET_UART0,
SYSCTL_RESET_UART1,
SYSCTL_RESET_UART2,
SYSCTL_RESET_UART3,
SYSCTL_RESET_UART4,
SYSCTL_RESET_I2C0,
SYSCTL_RESET_I2C1,
SYSCTL_RESET_I2C2,
SYSCTL_RESET_I2C3,
SYSCTL_RESET_I2C4,
SYSCTL_RESET_JAMLINK0_APB,
SYSCTL_RESET_JAMLINK1_APB,
SYSCTL_RESET_JAMLINK2_APB,
SYSCTL_RESET_JAMLINK3_APB,
SYSCTL_RESET_CODEC_APB,
SYSCTL_RESET_GPIO_DB,
SYSCTL_RESET_GPIO_APB,
SYSCTL_RESET_ADC,
SYSCTL_RESET_ADC_APB,
SYSCTL_RESET_PWM_APB,
SYSCTL_RESET_SPI2AXI,
} sysctl_reset_e;
typedef enum
{
SYSCTL_RESET_TIME_CPU0,
SYSCTL_RESET_TIME_CPU0_APB,
SYSCTL_RESET_TIME_CPU1,
SYSCTL_RESET_TIME_CPU1_APB,
SYSCTL_RESET_TIME_AI,
SYSCTL_RESET_TIME_VPU,
SYSCTL_RESET_TIME_HS_HCLK,
SYSCTL_RESET_TIME_SDCTL,
SYSCTL_RESET_TIME_USB,
SYSCTL_RESET_TIME_USB_AHB,
SYSCTL_RESET_TIME_SPI,
SYSCTL_RESET_TIME_SEC_SYS,
SYSCTL_RESET_TIME_DMAC,
SYSCTL_RESET_TIME_DECOMPRESS,
SYSCTL_RESET_TIME_SRAM,
SYSCTL_RESET_TIME_NONAI2D,
SYSCTL_RESET_TIME_MCTL,
SYSCTL_RESET_TIME_ISP,
SYSCTL_RESET_TIME_ISP_DW,
SYSCTL_RESET_TIME_DPU,
SYSCTL_RESET_TIME_DISP_SYS,
SYSCTL_RESET_TIME_V2P5D_SYS,
SYSCTL_RESET_TIME_AUDIO,
} sysctl_reset_time_e;
/* See TRM 2.1.4, Table 2-1-2 */
typedef struct {
volatile uint32_t cpu0_rst_tim; /* 0x00 */
volatile uint32_t cpu0_rst_ctl; /* 0x04 */
volatile uint32_t cpu1_rst_tim; /* 0x08 */
volatile uint32_t cpu1_rst_ctl; /* 0x0c */
volatile uint32_t ai_rst_tim; /* 0x10 */
volatile uint32_t ai_rst_ctl; /* 0x14 */
volatile uint32_t vpu_rst_tim; /* 0x18 */
volatile uint32_t vpu_rst_ctl; /* 0x1c */
volatile uint32_t soc_ctl_rst_ctl; /* 0x20 */
volatile uint32_t losys_rst_ctl; /* 0x24 */
volatile uint32_t hisys_hclk_tim; /* 0x28 */
volatile uint32_t hisys_rst_ctl; /* 0x2c */
volatile uint32_t sdctl_rst_tim; /* 0x30 */
volatile uint32_t sdc_rst_ctl; /* 0x34 */
volatile uint32_t usb_rst_tim; /* 0x38 */
volatile uint32_t usb_rst_ctl; /* 0x3c */
volatile uint32_t spi_rst_tim; /* 0x40 */
volatile uint32_t spi_rst_ctl; /* 0x44 */
volatile uint32_t sec_sys_rst_tim; /* 0x48 */
volatile uint32_t sec_rst_ctl; /* 0x4c */
volatile uint32_t dmac_rst_tim; /* 0x50 */
volatile uint32_t dma_rst_ctl; /* 0x54 */
volatile uint32_t decompress_rst_tim; /* 0x58 */
volatile uint32_t decompress_rst_ctl; /* 0x5c */
volatile uint32_t sram_rst_tim; /* 0x60 */
volatile uint32_t sram_rst_ctl; /* 0x64 */
volatile uint32_t nonai2d_rst_tim; /* 0x68 */
volatile uint32_t nonai2d_rst_ctl; /* 0x6c */
volatile uint32_t mctl_rst_tim; /* 0x70 */
volatile uint32_t mctl_rst_ctl; /* 0x74 */
volatile uint32_t isp_rst_tim; /* 0x78 */
volatile uint32_t isp_dw_rst_tim; /* 0x7c */
volatile uint32_t isp_rst_ctl; /* 0x80 */
volatile uint32_t dpu_rst_tim; /* 0x84 */
volatile uint32_t dpu_rst_ctl; /* 0x88 */
volatile uint32_t disp_sys_rst_tim; /* 0x8c */
volatile uint32_t disp_rst_ctl; /* 0x90 */
volatile uint32_t v2p5d_sys_rst_tim; /* 0x94 */
volatile uint32_t v2p5d_rst_ctl; /* 0x98 */
volatile uint32_t reserved; /* 0x9c */
volatile uint32_t audio_rst_tim; /* 0xa0 */
volatile uint32_t audio_rst_ctl; /* 0xa4 */
volatile uint32_t spi2axi_rst_ctl; /* 0xa8 */
} sysctl_rst_t;
/* Just call this API to reset */
bool sysctl_reset(sysctl_reset_e reset);
bool sysctl_set_reset_time(sysctl_reset_time_e reset, uint32_t tim0, uint32_t tim1, uint32_t tim2);
#endif