From 703fb5d8c234a607f22ab242def660ff15e351ef Mon Sep 17 00:00:00 2001 From: jzlv Date: Sat, 29 Oct 2022 13:33:23 +0800 Subject: [PATCH] [update][lhal] update lhal and demos --- drivers/lhal/CMakeLists.txt | 14 +- drivers/lhal/config/bl602/device_table.c | 7 + drivers/lhal/config/bl616/device_table.c | 7 + drivers/lhal/config/bl702/device_table.c | 7 + drivers/lhal/config/bl808/device_table.c | 7 + .../lhal/include/arch/risc-v/t-head/rv_hpm.h | 44 +- drivers/lhal/include/bflb_adc.h | 1 + drivers/lhal/include/bflb_cks.h | 27 + drivers/lhal/include/bflb_clock.h | 3 +- drivers/lhal/include/bflb_common.h | 2 +- drivers/lhal/include/bflb_core.h | 7 +- drivers/lhal/include/bflb_dma.h | 50 +- drivers/lhal/include/bflb_gpio.h | 65 +- drivers/lhal/include/bflb_i2c.h | 44 +- drivers/lhal/include/bflb_l1c.h | 4 +- drivers/lhal/include/bflb_mtimer.h | 5 +- drivers/lhal/include/bflb_pwm_v1.h | 2 +- drivers/lhal/include/bflb_pwm_v2.h | 2 +- drivers/lhal/include/bflb_sec_aes.h | 88 +++ drivers/lhal/include/bflb_sec_ecdsa.h | 43 ++ drivers/lhal/include/bflb_sec_pka.h | 269 ++++++++ drivers/lhal/include/bflb_sec_sha.h | 64 +- drivers/lhal/include/bflb_sec_trng.h | 7 +- drivers/lhal/include/bflb_spi.h | 5 +- drivers/lhal/include/bflb_timer.h | 38 +- drivers/lhal/include/bflb_uart.h | 51 +- drivers/lhal/include/bflb_wdg.h | 7 + drivers/lhal/include/hardware/adc_reg.h | 6 +- drivers/lhal/include/hardware/cks_reg.h | 64 ++ drivers/lhal/include/hardware/gpio_reg.h | 2 +- drivers/lhal/include/hardware/i2c_reg.h | 2 +- drivers/lhal/include/hardware/spi_reg.h | 8 + drivers/lhal/include/hardware/timer_reg.h | 6 +- drivers/lhal/src/bflb_adc.c | 18 +- drivers/lhal/src/bflb_cks.c | 34 + drivers/lhal/src/bflb_common.c | 1 + drivers/lhal/src/bflb_dac.c | 2 +- drivers/lhal/src/bflb_dma.c | 9 +- drivers/lhal/src/bflb_emac.c | 8 +- drivers/lhal/src/bflb_gpio.c | 71 ++- drivers/lhal/src/bflb_i2c.c | 89 ++- drivers/lhal/src/bflb_irq.c | 4 +- drivers/lhal/src/bflb_mtimer.c | 14 +- drivers/lhal/src/bflb_pwm_v1.c | 6 +- drivers/lhal/src/bflb_pwm_v2.c | 6 +- drivers/lhal/src/bflb_sec_aes.c | 141 ++++- drivers/lhal/src/bflb_sec_sha.c | 594 +++++++++++------- drivers/lhal/src/bflb_sec_trng.c | 72 ++- drivers/lhal/src/bflb_spi.c | 12 +- drivers/lhal/src/bflb_timer.c | 54 +- drivers/lhal/src/bflb_uart.c | 127 +++- drivers/lhal/src/bflb_usb_v2.c | 35 +- drivers/lhal/src/bflb_wdg.c | 13 +- drivers/lhal/src/pka/libpka.a | Bin 0 -> 586636 bytes .../{timer => cks/cks_dma}/CMakeLists.txt | 2 +- examples/peripherals/cks/cks_dma/Makefile | 13 + examples/peripherals/cks/cks_dma/main.c | 152 +++++ .../{timer => cks/cks_dma}/proj.conf | 0 .../peripherals/cks/cks_normal/CMakeLists.txt | 9 + examples/peripherals/cks/cks_normal/Makefile | 13 + examples/peripherals/cks/cks_normal/main.c | 260 ++++++++ examples/peripherals/cks/cks_normal/proj.conf | 1 + .../peripherals/i2c/i2c_10_bit/CMakeLists.txt | 9 + .../{timer => i2c/i2c_10_bit}/Makefile | 2 +- examples/peripherals/i2c/i2c_10_bit/main.c | 49 ++ examples/peripherals/i2c/i2c_10_bit/proj.conf | 1 + examples/peripherals/i2c/i2c_eeprom/main.c | 44 +- .../i2c/i2c_eeprom_dma/CMakeLists.txt | 9 + .../peripherals/i2c/i2c_eeprom_dma/Makefile | 13 + .../peripherals/i2c/i2c_eeprom_dma/main.c | 150 +++++ .../peripherals/i2c/i2c_eeprom_dma/proj.conf | 1 + .../i2c/i2c_eeprom_interrupt/CMakeLists.txt | 9 + .../i2c/i2c_eeprom_interrupt/Makefile | 13 + .../i2c/i2c_eeprom_interrupt/main.c | 132 ++++ .../i2c/i2c_eeprom_interrupt/proj.conf | 1 + .../sec_eng_aes_link_sw_key/CMakeLists.txt | 9 + .../sec_eng/sec_eng_aes_link_sw_key/Makefile | 13 + .../sec_eng/sec_eng_aes_link_sw_key/main.c | 365 +++++++++++ .../sec_eng/sec_eng_aes_link_sw_key/proj.conf | 1 + .../sec_eng/sec_eng_aes_sw_key/main.c | 3 + .../sec_eng/sec_eng_ecdh/CMakeLists.txt | 9 + .../peripherals/sec_eng/sec_eng_ecdh/Makefile | 13 + .../peripherals/sec_eng/sec_eng_ecdh/main.c | 228 +++++++ .../sec_eng/sec_eng_ecdh/proj.conf | 1 + .../sec_eng/sec_eng_ecdsa/CMakeLists.txt | 9 + .../sec_eng/sec_eng_ecdsa/Makefile | 13 + .../peripherals/sec_eng/sec_eng_ecdsa/main.c | 156 +++++ .../sec_eng/sec_eng_ecdsa/proj.conf | 1 + .../peripherals/sec_eng/sec_eng_sha/main.c | 3 + .../sec_eng/sec_eng_sha_link/CMakeLists.txt | 9 + .../sec_eng/sec_eng_sha_link/Makefile | 13 + .../sec_eng/sec_eng_sha_link/main.c | 123 ++++ .../sec_eng/sec_eng_sha_link/proj.conf | 1 + examples/peripherals/timer/main.c | 53 -- .../timer/timer_int/CMakeLists.txt | 9 + examples/peripherals/timer/timer_int/Makefile | 13 + examples/peripherals/timer/timer_int/main.c | 93 +++ .../peripherals/timer/timer_int/proj.conf | 1 + .../uart/uart_auto_baudrate/main.c | 19 +- examples/peripherals/uart/uart_cts_rts/main.c | 5 +- examples/peripherals/uart/uart_dma/main.c | 1 - .../uart/uart_fifo_interrupt/main.c | 1 - examples/peripherals/uart/uart_rs485/main.c | 3 +- examples/peripherals/wdg/wdg_int/main.c | 2 +- examples/peripherals/wdg/wdg_reset/main.c | 2 +- 105 files changed, 3765 insertions(+), 558 deletions(-) create mode 100644 drivers/lhal/include/bflb_cks.h create mode 100644 drivers/lhal/include/bflb_sec_ecdsa.h create mode 100644 drivers/lhal/include/bflb_sec_pka.h create mode 100644 drivers/lhal/include/hardware/cks_reg.h create mode 100644 drivers/lhal/src/bflb_cks.c create mode 100644 drivers/lhal/src/pka/libpka.a rename examples/peripherals/{timer => cks/cks_dma}/CMakeLists.txt (89%) create mode 100644 examples/peripherals/cks/cks_dma/Makefile create mode 100644 examples/peripherals/cks/cks_dma/main.c rename examples/peripherals/{timer => cks/cks_dma}/proj.conf (100%) create mode 100644 examples/peripherals/cks/cks_normal/CMakeLists.txt create mode 100644 examples/peripherals/cks/cks_normal/Makefile create mode 100644 examples/peripherals/cks/cks_normal/main.c create mode 100644 examples/peripherals/cks/cks_normal/proj.conf create mode 100644 examples/peripherals/i2c/i2c_10_bit/CMakeLists.txt rename examples/peripherals/{timer => i2c/i2c_10_bit}/Makefile (82%) create mode 100644 examples/peripherals/i2c/i2c_10_bit/main.c create mode 100644 examples/peripherals/i2c/i2c_10_bit/proj.conf create mode 100644 examples/peripherals/i2c/i2c_eeprom_dma/CMakeLists.txt create mode 100644 examples/peripherals/i2c/i2c_eeprom_dma/Makefile create mode 100644 examples/peripherals/i2c/i2c_eeprom_dma/main.c create mode 100644 examples/peripherals/i2c/i2c_eeprom_dma/proj.conf create mode 100644 examples/peripherals/i2c/i2c_eeprom_interrupt/CMakeLists.txt create mode 100644 examples/peripherals/i2c/i2c_eeprom_interrupt/Makefile create mode 100644 examples/peripherals/i2c/i2c_eeprom_interrupt/main.c create mode 100644 examples/peripherals/i2c/i2c_eeprom_interrupt/proj.conf create mode 100644 examples/peripherals/sec_eng/sec_eng_aes_link_sw_key/CMakeLists.txt create mode 100644 examples/peripherals/sec_eng/sec_eng_aes_link_sw_key/Makefile create mode 100644 examples/peripherals/sec_eng/sec_eng_aes_link_sw_key/main.c create mode 100644 examples/peripherals/sec_eng/sec_eng_aes_link_sw_key/proj.conf create mode 100644 examples/peripherals/sec_eng/sec_eng_ecdh/CMakeLists.txt create mode 100644 examples/peripherals/sec_eng/sec_eng_ecdh/Makefile create mode 100644 examples/peripherals/sec_eng/sec_eng_ecdh/main.c create mode 100644 examples/peripherals/sec_eng/sec_eng_ecdh/proj.conf create mode 100644 examples/peripherals/sec_eng/sec_eng_ecdsa/CMakeLists.txt create mode 100644 examples/peripherals/sec_eng/sec_eng_ecdsa/Makefile create mode 100644 examples/peripherals/sec_eng/sec_eng_ecdsa/main.c create mode 100644 examples/peripherals/sec_eng/sec_eng_ecdsa/proj.conf create mode 100644 examples/peripherals/sec_eng/sec_eng_sha_link/CMakeLists.txt create mode 100644 examples/peripherals/sec_eng/sec_eng_sha_link/Makefile create mode 100644 examples/peripherals/sec_eng/sec_eng_sha_link/main.c create mode 100644 examples/peripherals/sec_eng/sec_eng_sha_link/proj.conf delete mode 100644 examples/peripherals/timer/main.c create mode 100644 examples/peripherals/timer/timer_int/CMakeLists.txt create mode 100644 examples/peripherals/timer/timer_int/Makefile create mode 100644 examples/peripherals/timer/timer_int/main.c create mode 100644 examples/peripherals/timer/timer_int/proj.conf diff --git a/drivers/lhal/CMakeLists.txt b/drivers/lhal/CMakeLists.txt index 4f2e3aae..ce0c1d30 100644 --- a/drivers/lhal/CMakeLists.txt +++ b/drivers/lhal/CMakeLists.txt @@ -3,9 +3,11 @@ sdk_generate_library() sdk_library_add_sources(src/bflb_common.c) sdk_library_add_sources(src/bflb_adc.c) +if((NOT ("${CHIP}" STREQUAL "bl702l"))) sdk_library_add_sources(src/bflb_dac.c) +endif() sdk_library_add_sources(src/bflb_dma.c) -if((NOT ("${CHIP}" STREQUAL "bl602"))) +if((NOT ("${CHIP}" STREQUAL "bl602")) AND (NOT ("${CHIP}" STREQUAL "bl702l"))) sdk_library_add_sources(src/bflb_emac.c) endif() sdk_library_add_sources(src/bflb_gpio.c) @@ -17,10 +19,9 @@ sdk_library_add_sources(src/bflb_rtc.c) sdk_library_add_sources(src/bflb_sec_aes.c) sdk_library_add_sources(src/bflb_sec_sha.c) sdk_library_add_sources(src/bflb_sec_trng.c) -# sdk_library_add_sources(src/bflb_sec_pka.c) sdk_library_add_sources(src/bflb_timer.c) sdk_library_add_sources(src/bflb_wdg.c) - +sdk_library_add_sources(src/bflb_cks.c) # sdk_library_add_sources(src/bflb_clock.c) if(("${CHIP}" STREQUAL "bl702") OR ("${CHIP}" STREQUAL "bl602")) @@ -37,7 +38,6 @@ if("${CHIP}" STREQUAL "bl702") sdk_library_add_sources(src/bflb_usb_v1.c) elseif(("${CHIP}" STREQUAL "bl602") OR ("${CHIP}" STREQUAL "bl702l")) # no usb -else() sdk_library_add_sources(src/bflb_usb_v2.c) endif() endif() @@ -65,4 +65,8 @@ sdk_add_compile_definitions(-D${CHIPNAME}) if(CPU_ID) string(TOUPPER ${CPU_ID} CPU_ID_NAME) sdk_add_compile_definitions(-DCPU_${CPU_ID_NAME}) -endif() \ No newline at end of file +endif() + +sdk_add_link_libraries(${CMAKE_CURRENT_SOURCE_DIR}/src/pka/libpka.a) +sdk_add_link_options(-ubflb_trng_readlen) +#add_subdirectory(src/pka) \ No newline at end of file diff --git a/drivers/lhal/config/bl602/device_table.c b/drivers/lhal/config/bl602/device_table.c index cd9c382d..7c410f5f 100644 --- a/drivers/lhal/config/bl602/device_table.c +++ b/drivers/lhal/config/bl602/device_table.c @@ -155,6 +155,13 @@ struct bflb_device_s bl602_device_table[] = { .sub_idx = 0, .dev_type = BFLB_DEVICE_TYPE_TRNG, .user_data = NULL }, + { .name = "pka", + .reg_base = SEC_ENG_BASE, + .irq_num = 0xff, + .idx = 0, + .sub_idx = 0, + .dev_type = BFLB_DEVICE_TYPE_PKA, + .user_data = NULL }, }; struct bflb_device_s *bflb_device_get_by_name(const char *name) diff --git a/drivers/lhal/config/bl616/device_table.c b/drivers/lhal/config/bl616/device_table.c index 03bc69e2..35d5a080 100644 --- a/drivers/lhal/config/bl616/device_table.c +++ b/drivers/lhal/config/bl616/device_table.c @@ -156,6 +156,13 @@ struct bflb_device_s bl616_device_table[] = { .sub_idx = 0, .dev_type = BFLB_DEVICE_TYPE_TRNG, .user_data = NULL }, + { .name = "pka", + .reg_base = SEC_ENG_BASE, + .irq_num = 0xff, + .idx = 0, + .sub_idx = 0, + .dev_type = BFLB_DEVICE_TYPE_PKA, + .user_data = NULL }, { .name = "emac0", .reg_base = EMAC_BASE, .irq_num = BL616_IRQ_EMAC, diff --git a/drivers/lhal/config/bl702/device_table.c b/drivers/lhal/config/bl702/device_table.c index ba03fc45..4df8a243 100644 --- a/drivers/lhal/config/bl702/device_table.c +++ b/drivers/lhal/config/bl702/device_table.c @@ -155,6 +155,13 @@ struct bflb_device_s bl702_device_table[] = { .sub_idx = 0, .dev_type = BFLB_DEVICE_TYPE_TRNG, .user_data = NULL }, + { .name = "pka", + .reg_base = SEC_ENG_BASE, + .irq_num = 0xff, + .idx = 0, + .sub_idx = 0, + .dev_type = BFLB_DEVICE_TYPE_PKA, + .user_data = NULL }, { .name = "emac0", .reg_base = EMAC_BASE, .irq_num = BL702_IRQ_EMAC, diff --git a/drivers/lhal/config/bl808/device_table.c b/drivers/lhal/config/bl808/device_table.c index dbe5b2a1..4f57e6e0 100644 --- a/drivers/lhal/config/bl808/device_table.c +++ b/drivers/lhal/config/bl808/device_table.c @@ -156,6 +156,13 @@ struct bflb_device_s bl808_device_table[] = { .sub_idx = 0, .dev_type = BFLB_DEVICE_TYPE_TRNG, .user_data = NULL }, + { .name = "pka", + .reg_base = SEC_ENG_BASE, + .irq_num = 0xff, + .idx = 0, + .sub_idx = 0, + .dev_type = BFLB_DEVICE_TYPE_PKA, + .user_data = NULL }, { .name = "emac0", .reg_base = EMAC_BASE, .irq_num = BL808_IRQ_EMAC, diff --git a/drivers/lhal/include/arch/risc-v/t-head/rv_hpm.h b/drivers/lhal/include/arch/risc-v/t-head/rv_hpm.h index b4466058..78311671 100644 --- a/drivers/lhal/include/arch/risc-v/t-head/rv_hpm.h +++ b/drivers/lhal/include/arch/risc-v/t-head/rv_hpm.h @@ -5,7 +5,7 @@ #if (__riscv_xlen == 32) -#define RV_HPM_SET_CPUNTER(name, val) \ +#define RV_HPM_SET_COUNTER(name, val) \ do { \ uint32_t value = (uint32_t)val; \ __asm volatile("csrw " #name ", %0" \ @@ -46,7 +46,7 @@ #else -#define RV_HPM_SET_CPUNTER(name, val) \ +#define RV_HPM_SET_COUNTER(name, val) \ do { \ uint64_t value = val; \ __asm volatile("csrw " #name ", %0" \ @@ -114,8 +114,8 @@ inline __attribute__((always_inline)) void RV_HPM_L1_ICache_Miss_Init_M(void) : : : "memory"); - RV_HPM_SET_CPUNTER(mhpmcounter3, 0); - RV_HPM_SET_CPUNTER(mhpmcounter4, 0); + RV_HPM_SET_COUNTER(mhpmcounter3, 0); + RV_HPM_SET_COUNTER(mhpmcounter4, 0); } /* M-mode: L1 ICache Miss rate measure end */ @@ -142,8 +142,8 @@ inline __attribute__((always_inline)) void RV_HPM_L1_BrPredict_Miss_Init_M(void) : : : "memory"); - RV_HPM_SET_CPUNTER(mhpmcounter8, 0); - RV_HPM_SET_CPUNTER(mhpmcounter9, 0); + RV_HPM_SET_COUNTER(mhpmcounter8, 0); + RV_HPM_SET_COUNTER(mhpmcounter9, 0); #endif #ifdef CPU_D0 __asm volatile("csrw mhpmevent9, 6" @@ -154,8 +154,8 @@ inline __attribute__((always_inline)) void RV_HPM_L1_BrPredict_Miss_Init_M(void) : : : "memory"); - RV_HPM_SET_CPUNTER(mhpmcounter9, 0); - RV_HPM_SET_CPUNTER(mhpmcounter10, 0); + RV_HPM_SET_COUNTER(mhpmcounter9, 0); + RV_HPM_SET_COUNTER(mhpmcounter10, 0); #endif } @@ -187,8 +187,8 @@ inline __attribute__((always_inline)) void RV_HPM_L1_DCache_RdMiss_Init_M(void) : : : "memory"); - RV_HPM_SET_CPUNTER(mhpmcounter14, 0); - RV_HPM_SET_CPUNTER(mhpmcounter15, 0); + RV_HPM_SET_COUNTER(mhpmcounter14, 0); + RV_HPM_SET_COUNTER(mhpmcounter15, 0); #endif #ifdef CPU_D0 __asm volatile("csrw mhpmevent5, 12" @@ -199,8 +199,8 @@ inline __attribute__((always_inline)) void RV_HPM_L1_DCache_RdMiss_Init_M(void) : : : "memory"); - RV_HPM_SET_CPUNTER(mhpmcounter5, 0); - RV_HPM_SET_CPUNTER(mhpmcounter6, 0); + RV_HPM_SET_COUNTER(mhpmcounter5, 0); + RV_HPM_SET_COUNTER(mhpmcounter6, 0); #endif } @@ -232,8 +232,8 @@ inline __attribute__((always_inline)) void RV_HPM_L1_DCache_WrMiss_Init_M(void) : : : "memory"); - RV_HPM_SET_CPUNTER(mhpmcounter16, 0); - RV_HPM_SET_CPUNTER(mhpmcounter17, 0); + RV_HPM_SET_COUNTER(mhpmcounter16, 0); + RV_HPM_SET_COUNTER(mhpmcounter17, 0); #endif #ifdef CPU_D0 __asm volatile("csrw mhpmevent7, 14" @@ -244,8 +244,8 @@ inline __attribute__((always_inline)) void RV_HPM_L1_DCache_WrMiss_Init_M(void) : : : "memory"); - RV_HPM_SET_CPUNTER(mhpmcounter7, 0); - RV_HPM_SET_CPUNTER(mhpmcounter8, 0); + RV_HPM_SET_COUNTER(mhpmcounter7, 0); + RV_HPM_SET_COUNTER(mhpmcounter8, 0); #endif } @@ -280,9 +280,9 @@ inline __attribute__((always_inline)) void RV_HPM_TLB_Miss_Init_M(void) : : : "memory"); - RV_HPM_SET_CPUNTER(mhpmcounter5, 0); - RV_HPM_SET_CPUNTER(mhpmcounter6, 0); - RV_HPM_SET_CPUNTER(mhpmcounter7, 0); + RV_HPM_SET_COUNTER(mhpmcounter5, 0); + RV_HPM_SET_COUNTER(mhpmcounter6, 0); + RV_HPM_SET_COUNTER(mhpmcounter7, 0); } /* M-mode: TLB miss count measure end */ @@ -307,7 +307,7 @@ inline __attribute__((always_inline)) void RV_HPM_Store_Insn_Init_M(void) : : : "memory"); - RV_HPM_SET_CPUNTER(mhpmcounter13, 0); + RV_HPM_SET_COUNTER(mhpmcounter13, 0); } /* M-mode: Store Instruction counter measure end */ @@ -323,7 +323,7 @@ inline __attribute__((always_inline)) void RV_HPM_Store_Insn_Stop_M(uint64_t *sc /* M-Mode: Set cycle counter */ inline __attribute__((always_inline)) void RV_HPM_Cycle_Init_M(void) { - RV_HPM_SET_CPUNTER(mcycle, 0); + RV_HPM_SET_COUNTER(mcycle, 0); } /* M-Mode: Get cycle counter */ @@ -338,7 +338,7 @@ inline __attribute__((always_inline)) void RV_HPM_Cycle_Get_M(uint64_t *cycle) /* M-Mode: Set minstret counter */ inline __attribute__((always_inline)) void RV_HPM_Instret_Init_M(void) { - RV_HPM_SET_CPUNTER(minstret, 0); + RV_HPM_SET_COUNTER(minstret, 0); } /* M-Mode: Get minstret counter */ diff --git a/drivers/lhal/include/bflb_adc.h b/drivers/lhal/include/bflb_adc.h index 5cd5e9f0..0da23490 100644 --- a/drivers/lhal/include/bflb_adc.h +++ b/drivers/lhal/include/bflb_adc.h @@ -158,6 +158,7 @@ void bflb_adc_parse_result(struct bflb_device_s *dev, uint32_t *buffer, struct b void bflb_adc_tsen_init(struct bflb_device_s *dev, uint8_t tsen_mod); float bflb_adc_tsen_get_temp(struct bflb_device_s *dev, uint32_t tsen_offset); void bflb_adc_vbat_enable(struct bflb_device_s *dev); +void bflb_adc_vbat_disable(struct bflb_device_s *dev); #ifdef __cplusplus } diff --git a/drivers/lhal/include/bflb_cks.h b/drivers/lhal/include/bflb_cks.h new file mode 100644 index 00000000..77210827 --- /dev/null +++ b/drivers/lhal/include/bflb_cks.h @@ -0,0 +1,27 @@ +#ifndef _BFLB_CKS_H +#define _BFLB_CKS_H + +#include "bflb_core.h" + +/** @defgroup CKS_ENDIAN cks endian definition + * @{ + */ +#define CKS_LITTLE_ENDIAN 0 +#define CKS_BIG_ENDIAN 1 +/** + * @} + */ + +#ifdef __cplusplus +extern "C" { +#endif + +void bflb_cks_reset(struct bflb_device_s *dev); +void bflb_cks_set_endian(struct bflb_device_s *dev, uint8_t endian); +uint16_t bflb_cks_compute(struct bflb_device_s *dev, uint8_t *data, uint32_t length); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/drivers/lhal/include/bflb_clock.h b/drivers/lhal/include/bflb_clock.h index 55bdef12..a480e098 100644 --- a/drivers/lhal/include/bflb_clock.h +++ b/drivers/lhal/include/bflb_clock.h @@ -8,9 +8,8 @@ #define BFLB_SYSTEM_PBCLK 2 #define BFLB_SYSTEM_XCLK 3 #define BFLB_SYSTEM_32K_CLK 4 -#define BFLB_SYSTEM_1K_CLK 5 -#if defined(BL702) || defined(BL602) +#if defined(BL702) || defined(BL602) || defined(BL702L) #define BFLB_GLB_CGEN1_BASE (0x40000000 + 0x24) #elif defined(BL616) || defined(BL606P) || defined(BL808) || defined(BL628) #define BFLB_GLB_CGEN1_BASE (0x20000000 + 0x584) diff --git a/drivers/lhal/include/bflb_common.h b/drivers/lhal/include/bflb_common.h index 5cd19b89..8e0ca16d 100644 --- a/drivers/lhal/include/bflb_common.h +++ b/drivers/lhal/include/bflb_common.h @@ -1,7 +1,7 @@ #ifndef _BFLB_COMMON_H #define _BFLB_COMMON_H -#include "bflb_core.h" +#include "stdint.h" #ifdef __cplusplus extern "C" { diff --git a/drivers/lhal/include/bflb_core.h b/drivers/lhal/include/bflb_core.h index 3a5f73ef..3a081f97 100644 --- a/drivers/lhal/include/bflb_core.h +++ b/drivers/lhal/include/bflb_core.h @@ -12,8 +12,11 @@ #include #include #include "bflb_list.h" +#include "bflb_mtimer.h" +#include "bflb_common.h" -#if !defined(BL602) && !defined(BL702) && !defined(BL616) && !defined(BL606P) && !defined(BL808) && !defined(BL628) +#if !defined(BL602) && !defined(BL702) && !defined(BL702L) && \ + !defined(BL616) && !defined(BL606P) && !defined(BL808) && !defined(BL628) #error please define a supported chip #endif @@ -56,6 +59,8 @@ void assert_func(uint8_t *file, uint32_t line, uint8_t *function, uint8_t *strin #define BFLB_DEVICE_TYPE_SHA 29 #define BFLB_DEVICE_TYPE_MD5 30 #define BFLB_DEVICE_TYPE_TRNG 31 +#define BFLB_DEVICE_TYPE_PKA 32 +#define BFLB_DEVICE_TYPE_CKS 33 struct bflb_device_s { const char *name; diff --git a/drivers/lhal/include/bflb_dma.h b/drivers/lhal/include/bflb_dma.h index b4ab0987..19c038bd 100644 --- a/drivers/lhal/include/bflb_dma.h +++ b/drivers/lhal/include/bflb_dma.h @@ -194,6 +194,54 @@ * @} */ +#elif defined(BL628) +/** @defgroup DMA_PERIPHERAL_REGBASE dma peripheral data register address definition + * @{ + */ +#define DMA_ADDR_UART0_TDR (0x20010000 + 0x88) +#define DMA_ADDR_UART0_RDR (0x20010000 + 0x8C) +#define DMA_ADDR_UART1_TDR (0x20011000 + 0x88) +#define DMA_ADDR_UART1_RDR (0x20011000 + 0x8C) +#define DMA_ADDR_UART2_TDR (0x20012000 + 0x88) +#define DMA_ADDR_UART2_RDR (0x20012000 + 0x8C) +#define DMA_ADDR_I2C0_TDR (0x20014000 + 0x88) +#define DMA_ADDR_I2C0_RDR (0x20014000 + 0x8C) +#define DMA_ADDR_I2C1_TDR (0x20015000 + 0x88) +#define DMA_ADDR_I2C1_RDR (0x20015000 + 0x8C) +#define DMA_ADDR_SPI0_TDR (0x20018000 + 0x88) +#define DMA_ADDR_SPI0_RDR (0x20018000 + 0x8C) +#define DMA_ADDR_I2S_TDR (0x2001E000 + 0x88) +#define DMA_ADDR_I2S_RDR (0x2001E000 + 0x8C) +#define DMA_ADDR_ADC_RDR (0x20002000 + 0x04) +#define DMA_ADDR_DAC_TDR (0x20002000 + 0x48) +/** + * @} + */ + +/** @defgroup DMA_PERIPHERAL_REQUEST dma peripheral request definition + * @{ + */ +#define DMA_REQUEST_NONE 0x00000000 +#define DMA_REQUEST_UART0_RX 0x00000000 +#define DMA_REQUEST_UART0_TX 0x00000001 +#define DMA_REQUEST_UART1_RX 0x00000002 +#define DMA_REQUEST_UART1_TX 0x00000003 +#define DMA_REQUEST_UART2_RX 0x00000004 +#define DMA_REQUEST_UART2_TX 0x00000005 +#define DMA_REQUEST_I2C0_RX 0x00000006 +#define DMA_REQUEST_I2C0_TX 0x00000007 +#define DMA_REQUEST_I2C1_RX 0x00000008 +#define DMA_REQUEST_I2C1_TX 0x00000009 +#define DMA_REQUEST_SPI0_RX 0x0000000A +#define DMA_REQUEST_SPI0_TX 0x0000000B +#define DMA_REQUEST_I2S_RX 0x00000010 +#define DMA_REQUEST_I2S_TX 0x00000011 +#define DMA_REQUEST_ADC 0x00000016 +#define DMA_REQUEST_DAC 0x00000017 +/** + * @} + */ + #endif /** @defgroup DMA_CMD dma feature control cmd definition @@ -294,7 +342,7 @@ int bflb_dma_channel_lli_reload(struct bflb_device_s *dev, struct bflb_dma_channel_lli_pool_s *lli_pool, uint32_t max_lli_count, struct bflb_dma_channel_lli_transfer_s *transfer, uint32_t count); -void bflb_dma_feature_control(struct bflb_device_s *dev, int cmd, size_t arg); +int bflb_dma_feature_control(struct bflb_device_s *dev, int cmd, size_t arg); /* Not use */ void bflb_dma_channel_tcint_mask(struct bflb_device_s *dev, bool mask); diff --git a/drivers/lhal/include/bflb_gpio.h b/drivers/lhal/include/bflb_gpio.h index 31c9dfae..8f853c43 100644 --- a/drivers/lhal/include/bflb_gpio.h +++ b/drivers/lhal/include/bflb_gpio.h @@ -83,18 +83,24 @@ #define GPIO_FUNC_CAM (9 << GPIO_FUNC_SHIFT) #define GPIO_FUNC_JTAG (14 << GPIO_FUNC_SHIFT) #define GPIO_FUNC_EMAC (19 << GPIO_FUNC_SHIFT) +#elif defined(BL702L) +#define GPIO_FUNC_SPI0 (4 << GPIO_FUNC_SHIFT) +#define GPIO_FUNC_I2C0 (6 << GPIO_FUNC_SHIFT) +#define GPIO_FUNC_PWM0 (8 << GPIO_FUNC_SHIFT) +#define GPIO_FUNC_KEYSCAN (13 << GPIO_FUNC_SHIFT) +#define GPIO_FUNC_JTAG (14 << GPIO_FUNC_SHIFT) #elif defined(BL616) -#define GPIO_FUNC_SDH (0 << GPIO_FUNC_SHIFT) -#define GPIO_FUNC_SPI0 (1 << GPIO_FUNC_SHIFT) -#define GPIO_FUNC_I2S (3 << GPIO_FUNC_SHIFT) -#define GPIO_FUNC_PDM (4 << GPIO_FUNC_SHIFT) -#define GPIO_FUNC_I2C0 (5 << GPIO_FUNC_SHIFT) -#define GPIO_FUNC_I2C1 (6 << GPIO_FUNC_SHIFT) -#define GPIO_FUNC_EMAC (8 << GPIO_FUNC_SHIFT) -#define GPIO_FUNC_CAM (9 << GPIO_FUNC_SHIFT) -#define GPIO_FUNC_SDU (12 << GPIO_FUNC_SHIFT) -#define GPIO_FUNC_PWM0 (16 << GPIO_FUNC_SHIFT) -#define GPIO_FUNC_JTAG (26 << GPIO_FUNC_SHIFT) +#define GPIO_FUNC_SDH (0 << GPIO_FUNC_SHIFT) +#define GPIO_FUNC_SPI0 (1 << GPIO_FUNC_SHIFT) +#define GPIO_FUNC_I2S (3 << GPIO_FUNC_SHIFT) +#define GPIO_FUNC_PDM (4 << GPIO_FUNC_SHIFT) +#define GPIO_FUNC_I2C0 (5 << GPIO_FUNC_SHIFT) +#define GPIO_FUNC_I2C1 (6 << GPIO_FUNC_SHIFT) +#define GPIO_FUNC_EMAC (8 << GPIO_FUNC_SHIFT) +#define GPIO_FUNC_CAM (9 << GPIO_FUNC_SHIFT) +#define GPIO_FUNC_SDU (12 << GPIO_FUNC_SHIFT) +#define GPIO_FUNC_PWM0 (16 << GPIO_FUNC_SHIFT) +#define GPIO_FUNC_JTAG (26 << GPIO_FUNC_SHIFT) #define GPIO_FUNC_CLKOUT (31 << GPIO_FUNC_SHIFT) #elif defined(BL606P) || defined(BL808) #define GPIO_FUNC_SDH (0 << GPIO_FUNC_SHIFT) @@ -118,19 +124,20 @@ #define GPIO_FUNC_JTAG_M0 (26 << GPIO_FUNC_SHIFT) #define GPIO_FUNC_JTAG_D0 (27 << GPIO_FUNC_SHIFT) #elif defined(BL628) -#define GPIO_FUNC_SDH (0 << GPIO_FUNC_SHIFT) -#define GPIO_FUNC_SPI0 (1 << GPIO_FUNC_SHIFT) -#define GPIO_FUNC_I2S (3 << GPIO_FUNC_SHIFT) -#define GPIO_FUNC_PDM (4 << GPIO_FUNC_SHIFT) -#define GPIO_FUNC_I2C0 (5 << GPIO_FUNC_SHIFT) -#define GPIO_FUNC_I2C1 (6 << GPIO_FUNC_SHIFT) -#define GPIO_FUNC_UART (7 << GPIO_FUNC_SHIFT) -#define GPIO_FUNC_EMAC (8 << GPIO_FUNC_SHIFT) -#define GPIO_FUNC_CAM (9 << GPIO_FUNC_SHIFT) -#define GPIO_FUNC_SDU (12 << GPIO_FUNC_SHIFT) -#define GPIO_FUNC_PWM0 (16 << GPIO_FUNC_SHIFT) -#define GPIO_FUNC_DBI_B (22 << GPIO_FUNC_SHIFT) -#define GPIO_FUNC_DBI_C (23 << GPIO_FUNC_SHIFT) +#define GPIO_FUNC_SDH (0 << GPIO_FUNC_SHIFT) +#define GPIO_FUNC_SPI0 (1 << GPIO_FUNC_SHIFT) +#define GPIO_FUNC_I2S (3 << GPIO_FUNC_SHIFT) +#define GPIO_FUNC_PDM (4 << GPIO_FUNC_SHIFT) +#define GPIO_FUNC_I2C0 (5 << GPIO_FUNC_SHIFT) +#define GPIO_FUNC_I2C1 (6 << GPIO_FUNC_SHIFT) +#define GPIO_FUNC_UART (7 << GPIO_FUNC_SHIFT) +#define GPIO_FUNC_EMAC (8 << GPIO_FUNC_SHIFT) +#define GPIO_FUNC_CAM (9 << GPIO_FUNC_SHIFT) +#define GPIO_FUNC_SDU (12 << GPIO_FUNC_SHIFT) +#define GPIO_FUNC_PWM0 (16 << GPIO_FUNC_SHIFT) +#define GPIO_FUNC_DBI_B (22 << GPIO_FUNC_SHIFT) +#define GPIO_FUNC_DBI_C (23 << GPIO_FUNC_SHIFT) +#define GPIO_FUNC_CLKOUT (31 << GPIO_FUNC_SHIFT) #endif #define GPIO_MODE_SHIFT (5) /* Bits 5-6: Port Mode */ @@ -190,6 +197,14 @@ #define GPIO_UART_FUNC_UART2_RX 11 #endif +/** @defgroup GPIO_CMD gpio feature control cmd definition + * @{ + */ +#define GPIO_CMD_GET_GPIO_FUN (0x01) +/** + * @} + */ + #ifdef __cplusplus extern "C" { #endif @@ -206,7 +221,7 @@ void bflb_gpio_int_clear(struct bflb_device_s *dev, uint8_t pin); void bflb_gpio_uart_init(struct bflb_device_s *dev, uint8_t pin, uint8_t uart_func); -void bflb_gpio_feature_control(struct bflb_device_s *dev, int cmd, size_t arg); +int bflb_gpio_feature_control(struct bflb_device_s *dev, int cmd, size_t arg); #ifdef __cplusplus } diff --git a/drivers/lhal/include/bflb_i2c.h b/drivers/lhal/include/bflb_i2c.h index cc4bfc6b..434f8ab9 100644 --- a/drivers/lhal/include/bflb_i2c.h +++ b/drivers/lhal/include/bflb_i2c.h @@ -36,16 +36,51 @@ #define I2C_M_READ 0x0001 /* Read data, from slave to master */ #define I2C_M_TEN 0x0002 /* Ten bit address */ +#define I2C_M_DMA 0x0004 /* Enable dma mode */ #define I2C_M_NOSTOP 0x0040 /* Message should not end with a STOP */ #define I2C_M_NOSTART 0x0080 /* Message should not begin with a START */ -/* I2c bus speed */ +/* I2C bus speed */ #define I2C_SPEED_STANDARD 100000 /* Standard speed (100Khz) */ #define I2C_SPEED_FAST 400000 /* Fast speed (400Khz) */ #define I2C_SPEED_FAST_PLUS 1000000 /* Fast+ speed ( 1Mhz) */ #define I2C_SPEED_HIGH 3400000 /* High speed (3.4Mhz) */ +/** @defgroup I2C_INTSTS i2c interrupt status definition + * @{ + */ +#define I2C_INTSTS_END (1 << 0) /* Transfer end interrupt */ +#define I2C_INTSTS_TX_FIFO (1 << 1) /* TX FIFO ready interrupt */ +#define I2C_INTSTS_RX_FIFO (1 << 2) /* RX FIFO ready interrupt */ +#define I2C_INTSTS_NACK (1 << 3) /* NACK interrupt */ +#define I2C_INTSTS_ARB (1 << 4) /* Arbitration lost interrupt */ +#define I2C_INTSTS_FER (1 << 5) /* TX/RX FIFO error interrupt */ +/** + * @} + */ + +/** @defgroup I2C_INTCLR i2c interrupt clear definition + * @{ + */ +#define I2C_INTCLR_END (1 << 0) /* Transfer end interrupt */ +#define I2C_INTCLR_TX_FIFO (1 << 1) /* TX FIFO ready interrupt */ +#define I2C_INTCLR_RX_FIFO (1 << 2) /* RX FIFO ready interrupt */ +#define I2C_INTCLR_NACK (1 << 3) /* NACK interrupt */ +#define I2C_INTCLR_ARB (1 << 4) /* Arbitration lost interrupt */ +#define I2C_INTCLR_FER (1 << 5) /* TX/RX FIFO error interrupt */ +/** + * @} + */ + +/* I2C interrupt type */ +#define I2C_INT_END (1 << 0) /* Transfer end interrupt */ +#define I2C_INT_TX_FIFO (1 << 1) /* TX FIFO ready interrupt */ +#define I2C_INT_RX_FIFO (1 << 2) /* RX FIFO ready interrupt */ +#define I2C_INT_NACK (1 << 3) /* NACK interrupt */ +#define I2C_INT_ARB (1 << 4) /* Arbitration lost interrupt */ +#define I2C_INT_FER (1 << 5) /* TX/RX FIFO error interrupt */ + /** * @brief I2C message structure * @@ -70,11 +105,14 @@ void bflb_i2c_deinit(struct bflb_device_s *dev); void bflb_i2c_link_txdma(struct bflb_device_s *dev, bool enable); void bflb_i2c_link_rxdma(struct bflb_device_s *dev, bool enable); int bflb_i2c_transfer(struct bflb_device_s *dev, struct bflb_i2c_msg_s *msgs, int count); +void bflb_i2c_int_mask(struct bflb_device_s *dev, uint32_t int_type, bool mask); +void bflb_i2c_int_clear(struct bflb_device_s *dev, uint32_t int_clear); +uint32_t bflb_i2c_get_intstatus(struct bflb_device_s *dev); -void bflb_i2c_feature_control(struct bflb_device_s *dev, int cmd, size_t arg); +int bflb_i2c_feature_control(struct bflb_device_s *dev, int cmd, size_t arg); #ifdef __cplusplus } #endif -#endif \ No newline at end of file +#endif diff --git a/drivers/lhal/include/bflb_l1c.h b/drivers/lhal/include/bflb_l1c.h index 404b92d0..bb0b48cc 100644 --- a/drivers/lhal/include/bflb_l1c.h +++ b/drivers/lhal/include/bflb_l1c.h @@ -3,10 +3,11 @@ #include "bflb_core.h" -#if defined(BL616) || defined(BL606P) || defined(BL808) +#if defined(BL616) || defined(BL606P) || defined(BL808) || defined(BL628) #include "csi_core.h" #define bflb_l1c_icache_enable() csi_icache_enable() #define bflb_l1c_icache_disable() csi_icache_disable() +#define bflb_l1c_icache_invalid_all() csi_icache_invalid() #define bflb_l1c_dcache_enable() csi_dcache_enable() #define bflb_l1c_dcache_disable() csi_dcache_disable() #define bflb_l1c_dcache_clean_all() csi_dcache_clean() @@ -18,6 +19,7 @@ #else #define bflb_l1c_icache_enable() #define bflb_l1c_icache_disable() +#define bflb_l1c_icache_invalid_all() #define bflb_l1c_dcache_enable() #define bflb_l1c_dcache_disable() #define bflb_l1c_dcache_clean_all() diff --git a/drivers/lhal/include/bflb_mtimer.h b/drivers/lhal/include/bflb_mtimer.h index acb565af..2654374b 100644 --- a/drivers/lhal/include/bflb_mtimer.h +++ b/drivers/lhal/include/bflb_mtimer.h @@ -1,14 +1,15 @@ #ifndef _BFLB_MTIMER_H #define _BFLB_MTIMER_H -#include "bflb_core.h" -#include "bflb_irq.h" +#include "stdint.h" +#include "stdio.h" #ifdef __cplusplus extern "C" { #endif void bflb_mtimer_config(uint64_t ticks, void (*interruptfun)(void)); +uint32_t bflb_mtimer_get_freq(void); void bflb_mtimer_delay_ms(uint32_t time); void bflb_mtimer_delay_us(uint32_t time); uint64_t bflb_mtimer_get_time_us(); diff --git a/drivers/lhal/include/bflb_pwm_v1.h b/drivers/lhal/include/bflb_pwm_v1.h index 96577281..02f32188 100644 --- a/drivers/lhal/include/bflb_pwm_v1.h +++ b/drivers/lhal/include/bflb_pwm_v1.h @@ -90,7 +90,7 @@ void bflb_pwm_v1_int_enable(struct bflb_device_s *dev, uint8_t ch, bool enable); uint32_t bflb_pwm_v1_get_intstatus(struct bflb_device_s *dev); void bflb_pwm_v1_int_clear(struct bflb_device_s *dev, uint32_t int_clear); -void bflb_pwm_v1_feature_control(struct bflb_device_s *dev, uint8_t ch, int cmd, size_t arg); +int bflb_pwm_v1_feature_control(struct bflb_device_s *dev, uint8_t ch, int cmd, size_t arg); #ifdef __cplusplus } diff --git a/drivers/lhal/include/bflb_pwm_v2.h b/drivers/lhal/include/bflb_pwm_v2.h index 31b32d3f..0dbdba15 100644 --- a/drivers/lhal/include/bflb_pwm_v2.h +++ b/drivers/lhal/include/bflb_pwm_v2.h @@ -174,7 +174,7 @@ void bflb_pwm_v2_int_enable(struct bflb_device_s *dev, uint32_t int_en, bool ena uint32_t bflb_pwm_v2_get_intstatus(struct bflb_device_s *dev); void bflb_pwm_v2_int_clear(struct bflb_device_s *dev, uint32_t int_clear); -void bflb_pwm_v2_feature_control(struct bflb_device_s *dev, int cmd, size_t arg); +int bflb_pwm_v2_feature_control(struct bflb_device_s *dev, int cmd, size_t arg); #ifdef __cplusplus } diff --git a/drivers/lhal/include/bflb_sec_aes.h b/drivers/lhal/include/bflb_sec_aes.h index 368d9a2d..5d018116 100644 --- a/drivers/lhal/include/bflb_sec_aes.h +++ b/drivers/lhal/include/bflb_sec_aes.h @@ -8,12 +8,88 @@ #define AES_MODE_CBC 2 #define AES_MODE_XTS 3 +#define AES_LINK_KEY_128BITS 0 +#define AES_LINK_KEY_192BITS 1 +#define AES_LINK_KEY_256BITS 2 +#define AES_LINK_KEY_DOUBLE_128BITS 3 + +struct bflb_aes_link_s { + uint32_t : 3; /*!< [2:0]Reserved */ + uint32_t aes_key : 2; /*!< [4:3]128-bit/256-bit/192-bit/128-bit-double key mode select */ + uint32_t aes_dec_en : 1; /*!< [5]Encode or decode */ + uint32_t aes_newkey_dis : 1; /*!< [6]Use new key or use same key as last one */ + uint32_t aes_hwkey_en : 1; /*!< [7]Enable or disable using hardware hey */ + uint32_t : 1; /*!< [8]Reserved */ + uint32_t aes_intclr : 1; /*!< [9]Clear interrupt */ + uint32_t aes_intset : 1; /*!< [10]Set interrupt */ + uint32_t : 1; /*!< [11]Reserved */ + uint32_t aes_mode : 2; /*!< [13:12]ECB/CTR/CBC mode select */ + uint32_t aes_newiv_dis : 1; /*!< [14]Use new iv or use same iv as last one */ + uint32_t aes_xts : 1; /*!< [15]XTS mode select */ + uint32_t aes_msglen : 16; /*!< [31:16]Number of 128-bit block */ + uint32_t aes_srcaddr; /*!< Message source address */ + uint32_t aes_dstaddr; /*!< Message destination address */ + uint32_t aes_iv0; /*!< Big endian initial vector(MSB) */ + uint32_t aes_iv1; /*!< Big endian initial vector */ + uint32_t aes_iv2; /*!< Big endian initial vector */ + uint32_t aes_iv3; /*!< Big endian initial vector(LSB)(CTR mode:counter initial value) */ + uint32_t aes_key0; /*!< Big endian aes key(aes-128/256 key MSB) */ + uint32_t aes_key1; /*!< Big endian aes key */ + uint32_t aes_key2; /*!< Big endian aes key */ + uint32_t aes_key3; /*!< Big endian aes key(aes-128 key LSB) */ + uint32_t aes_key4; /*!< Big endian aes key */ + uint32_t aes_key5; /*!< Big endian aes key */ + uint32_t aes_key6; /*!< Big endian aes key */ + uint32_t aes_key7; /*!< Big endian aes key(aes-256 key LSB) */ +} __attribute__((aligned(4))); + +struct bflb_aes_xts_link_s { + uint32_t : 3; /*!< [2:0]Reserved */ + uint32_t aes_key : 2; /*!< [4:3]128-bit/256-bit/192-bit/128-bit-double key mode select */ + uint32_t aes_dec_en : 1; /*!< [5]Encode or decode */ + uint32_t aes_newkey_dis : 1; /*!< [6]Use new key or use same key as last one */ + uint32_t aes_hwkey_en : 1; /*!< [7]Enable or disable using hardware hey */ + uint32_t : 1; /*!< [8]Reserved */ + uint32_t aes_intclr : 1; /*!< [9]Clear interrupt */ + uint32_t aes_intset : 1; /*!< [10]Set interrupt */ + uint32_t : 1; /*!< [11]Reserved */ + uint32_t aes_mode : 2; /*!< [13:12]ECB/CTR/CBC mode select */ + uint32_t aes_newiv_dis : 1; /*!< [14]Use new iv or use same iv as last one */ + uint32_t aes_xts : 1; /*!< [15]XTS mode select */ + uint32_t aes_msglen : 16; /*!< [31:16]Number of 128-bit block */ + uint32_t aes_srcaddr; /*!< Message source address */ + uint32_t aes_dstaddr; /*!< Message destination address */ + uint32_t aes_iv0; /*!< Big endian initial vector(MSB) */ + uint32_t aes_iv1; /*!< Big endian initial vector */ + uint32_t aes_iv2; /*!< Big endian initial vector */ + uint32_t aes_iv3; /*!< Big endian initial vector(LSB)(CTR mode:counter initial value) */ + uint32_t aes_key10; /*!< Big endian aes key(aes-128/256 key MSB) */ + uint32_t aes_key11; /*!< Big endian aes key1 */ + uint32_t aes_key12; /*!< Big endian aes key1 */ + uint32_t aes_key13; /*!< Big endian aes key1(aes-128 key LSB) */ + uint32_t aes_key14; /*!< Big endian aes key1 */ + uint32_t aes_key15; /*!< Big endian aes key1 */ + uint32_t aes_key16; /*!< Big endian aes key1 */ + uint32_t aes_key17; /*!< Big endian aes key1(aes-256 key LSB) */ + uint32_t : 16; /*!< [15:0]Reserved */ + uint32_t aes_unitlen : 16; /*!< [31:16]Big endian aes unit len */ + uint32_t aes_key20; /*!< Big endian aes key2(aes-128/256 key MSB) */ + uint32_t aes_key21; /*!< Big endian aes key2 */ + uint32_t aes_key22; /*!< Big endian aes key2 */ + uint32_t aes_key23; /*!< Big endian aes key2(aes-128 key LSB) */ + uint32_t aes_key24; /*!< Big endian aes key2 */ + uint32_t aes_key25; /*!< Big endian aes key2 */ + uint32_t aes_key26; /*!< Big endian aes key2 */ + uint32_t aes_key27; /*!< Big endian aes key2(aes-256 key LSB) */ +} __attribute__((aligned(4))); + #ifdef __cplusplus extern "C" { #endif void bflb_aes_init(struct bflb_device_s *dev); void bflb_aes_deinit(struct bflb_device_s *dev); +void bflb_aes_set_hwkey(uint8_t keysel); void bflb_aes_set_mode(struct bflb_device_s *dev, uint8_t mode); void bflb_aes_setkey(struct bflb_device_s *dev, const uint8_t *key, uint16_t keybits); int bflb_aes_encrypt(struct bflb_device_s *dev, @@ -27,6 +103,18 @@ int bflb_aes_decrypt(struct bflb_device_s *dev, uint8_t *output, uint32_t len); +void bflb_aes_link_init(struct bflb_device_s *dev); +void bflb_aes_link_deinit(struct bflb_device_s *dev); +int bflb_aes_link_update(struct bflb_device_s *dev, + uint32_t link_addr, + const uint8_t *input, + uint8_t *output, + uint32_t len); + +void bflb_group0_request_aes_access(struct bflb_device_s *dev); +void bflb_group0_release_aes_access(struct bflb_device_s *dev); +void bflb_aes_set_hwkey_source(struct bflb_device_s *dev, uint8_t source); + #ifdef __cplusplus } #endif diff --git a/drivers/lhal/include/bflb_sec_ecdsa.h b/drivers/lhal/include/bflb_sec_ecdsa.h new file mode 100644 index 00000000..5cfcb5e0 --- /dev/null +++ b/drivers/lhal/include/bflb_sec_ecdsa.h @@ -0,0 +1,43 @@ +#ifndef _BFLB_SEC_ECDSA_H +#define _BFLB_SEC_ECDSA_H + +#include "bflb_core.h" + +#define ECP_SECP256R1 0 +#define ECP_SECP256K1 1 + +struct bflb_ecdsa_s { + uint8_t ecpId; + uint32_t *privateKey; + uint32_t *publicKeyx; + uint32_t *publicKeyy; +}; + +struct bflb_ecdh_s { + uint8_t ecpId; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +int bflb_sec_ecdsa_init(struct bflb_ecdsa_s *handle, uint8_t id); +int bflb_sec_ecdsa_deinit(struct bflb_ecdsa_s *handle); +int bflb_sec_ecdsa_sign(struct bflb_ecdsa_s *handle, const uint32_t *random_k, const uint32_t *hash, uint32_t hashLenInWord, uint32_t *r, uint32_t *s); +int bflb_sec_ecdsa_verify(struct bflb_ecdsa_s *handle, const uint32_t *hash, uint32_t hashLen, const uint32_t *r, const uint32_t *s); +int bflb_sec_ecdsa_get_private_key(struct bflb_ecdsa_s *handle, uint32_t *private_key); +int bflb_sec_ecdsa_get_public_key(struct bflb_ecdsa_s *handle, const uint32_t *private_key, const uint32_t *pRx, const uint32_t *pRy); + +int bflb_sec_ecdh_init(struct bflb_ecdh_s *handle, uint8_t id); +int bflb_sec_ecdh_deinit(struct bflb_ecdh_s *handle); +int bflb_sec_ecdh_get_encrypt_key(struct bflb_ecdh_s *handle, const uint32_t *pkX, const uint32_t *pkY, const uint32_t *private_key, const uint32_t *pRx, const uint32_t *pRy); +int bflb_sec_ecdh_get_public_key(struct bflb_ecdh_s *handle, const uint32_t *private_key, const uint32_t *pRx, const uint32_t *pRy); +int bflb_sec_ecc_get_random_value(uint32_t *data, uint32_t *max_ref, uint32_t size); + +#define SEC_CODEPATH_STATE_SIGN 0x48672386 + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/drivers/lhal/include/bflb_sec_pka.h b/drivers/lhal/include/bflb_sec_pka.h new file mode 100644 index 00000000..2a3e7364 --- /dev/null +++ b/drivers/lhal/include/bflb_sec_pka.h @@ -0,0 +1,269 @@ +#ifndef _BFLB_SEC_PKA_H +#define _BFLB_SEC_PKA_H + +#include "bflb_core.h" + +#define SEC_ENG_PKA_REG_SIZE_8 1 +#define SEC_ENG_PKA_REG_SIZE_16 2 +#define SEC_ENG_PKA_REG_SIZE_32 3 +#define SEC_ENG_PKA_REG_SIZE_64 4 +#define SEC_ENG_PKA_REG_SIZE_96 5 +#define SEC_ENG_PKA_REG_SIZE_128 6 +#define SEC_ENG_PKA_REG_SIZE_192 7 +#define SEC_ENG_PKA_REG_SIZE_256 8 +#define SEC_ENG_PKA_REG_SIZE_384 9 +#define SEC_ENG_PKA_REG_SIZE_512 10 + +#define SEC_ENG_PKA_OP_PPSEL 0x00 +#define SEC_ENG_PKA_OP_LMOD2N 0x11 +#define SEC_ENG_PKA_OP_LDIV2N 0x12 +#define SEC_ENG_PKA_OP_LMUL2N 0x13 +#define SEC_ENG_PKA_OP_LDIV 0x14 +#define SEC_ENG_PKA_OP_LSQR 0x15 +#define SEC_ENG_PKA_OP_LMUL 0x16 +#define SEC_ENG_PKA_OP_LSUB 0x17 +#define SEC_ENG_PKA_OP_LADD 0x18 +#define SEC_ENG_PKA_OP_LCMP 0x19 +#define SEC_ENG_PKA_OP_MDIV2 0x21 +#define SEC_ENG_PKA_OP_MINV 0x22 +#define SEC_ENG_PKA_OP_MEXP 0x23 +#define SEC_ENG_PKA_OP_MSQR 0x24 +#define SEC_ENG_PKA_OP_MMUL 0x25 +#define SEC_ENG_PKA_OP_MREM 0x26 +#define SEC_ENG_PKA_OP_MSUB 0x27 +#define SEC_ENG_PKA_OP_MADD 0x28 +#define SEC_ENG_PKA_OP_RESIZE 0x31 +#define SEC_ENG_PKA_OP_MOVDAT 0x32 +#define SEC_ENG_PKA_OP_NLIR 0x33 +#define SEC_ENG_PKA_OP_SLIR 0x34 +#define SEC_ENG_PKA_OP_CLIR 0x35 +#define SEC_ENG_PKA_OP_CFLIRI_BUFFER 0x36 +#define SEC_ENG_PKA_OP_CTLIRI_PLD 0x37 +#define SEC_ENG_PKA_OP_CFLIR_BUFFER 0x38 +#define SEC_ENG_PKA_OP_CTLIR_PLD 0x39 + +#ifdef __cplusplus +extern "C" { +#endif + +void bflb_pka_init(struct bflb_device_s *dev); +void bflb_pka_deinit(struct bflb_device_s *dev); + +void bflb_pka_lmod2n(struct bflb_device_s *dev, + uint8_t s0_regindex, + uint8_t s0_regsize, + uint8_t d0_regindex, + uint8_t d0_regsize, + uint16_t bit_shift, + uint8_t lastop); + +void bflb_pka_ldiv2n(struct bflb_device_s *dev, + uint8_t s0_regindex, + uint8_t s0_regsize, + uint8_t d0_regindex, + uint8_t d0_regsize, + uint16_t bit_shift, + uint8_t lastop); + +void bflb_pka_lmul2n(struct bflb_device_s *dev, + uint8_t s0_regindex, + uint8_t s0_regsize, + uint8_t d0_regindex, + uint8_t d0_regsize, + uint16_t bit_shift, + uint8_t lastop); + +void bflb_pka_ldiv(struct bflb_device_s *dev, + uint8_t s0_regindex, + uint8_t s0_regsize, + uint8_t d0_regindex, + uint8_t d0_regsize, + uint8_t s2_regindex, + uint8_t s2_regsize, + uint8_t lastop); + +void bflb_pka_lsqr(struct bflb_device_s *dev, + uint8_t s0_regindex, + uint8_t s0_regsize, + uint8_t d0_regindex, + uint8_t d0_regsize, + uint8_t lastop); + +void bflb_pka_lmul(struct bflb_device_s *dev, + uint8_t s0_regindex, + uint8_t s0_regsize, + uint8_t d0_regindex, + uint8_t d0_regsize, + uint8_t s1_regindex, + uint8_t s1_regsize, + uint8_t lastop); + +void bflb_pka_lsub(struct bflb_device_s *dev, + uint8_t s0_regindex, + uint8_t s0_regsize, + uint8_t d0_regindex, + uint8_t d0_regsize, + uint8_t s1_regindex, + uint8_t s1_regsize, + uint8_t lastop); + +void bflb_pka_ladd(struct bflb_device_s *dev, + uint8_t s0_regindex, + uint8_t s0_regsize, + uint8_t d0_regindex, + uint8_t d0_regsize, + uint8_t s1_regindex, + uint8_t s1_regsize, + uint8_t lastop); + +uint8_t bflb_pka_lcmp(struct bflb_device_s *dev, + uint8_t s0_regindex, + uint8_t s0_regsize, + uint8_t s1_regindex, + uint8_t s1_regsize); + +void bflb_pka_minv(struct bflb_device_s *dev, + uint8_t s0_regindex, + uint8_t s0_regsize, + uint8_t d0_regindex, + uint8_t d0_regsize, + uint8_t s2_regindex, + uint8_t s2_regsize, + uint8_t lastop); + +void bflb_pka_mexp(struct bflb_device_s *dev, + uint8_t s0_regindex, + uint8_t s0_regsize, + uint8_t d0_regindex, + uint8_t d0_regsize, + uint8_t s1_regindex, + uint8_t s1_regsize, + uint8_t s2_regindex, + uint8_t s2_regsize, + uint8_t lastop); + +void bflb_pka_msqr(struct bflb_device_s *dev, + uint8_t s0_regindex, + uint8_t s0_regsize, + uint8_t d0_regindex, + uint8_t d0_regsize, + uint8_t s2_regindex, + uint8_t s2_regsize, + uint8_t lastop); + +void bflb_pka_mmul(struct bflb_device_s *dev, + uint8_t s0_regindex, + uint8_t s0_regsize, + uint8_t d0_regindex, + uint8_t d0_regsize, + uint8_t s1_regindex, + uint8_t s1_regsize, + uint8_t s2_regindex, + uint8_t s2_regsize, + uint8_t lastop); + +void bflb_pka_mrem(struct bflb_device_s *dev, + uint8_t s0_regindex, + uint8_t s0_regsize, + uint8_t d0_regindex, + uint8_t d0_regsize, + uint8_t s2_regindex, + uint8_t s2_regsize, + uint8_t lastop); + +void bflb_pka_msub(struct bflb_device_s *dev, + uint8_t s0_regindex, + uint8_t s0_regsize, + uint8_t d0_regindex, + uint8_t d0_regsize, + uint8_t s1_regindex, + uint8_t s1_regsize, + uint8_t s2_regindex, + uint8_t s2_regsize, + uint8_t lastop); + +void bflb_pka_madd(struct bflb_device_s *dev, + uint8_t s0_regindex, + uint8_t s0_regsize, + uint8_t d0_regindex, + uint8_t d0_regsize, + uint8_t s1_regindex, + uint8_t s1_regsize, + uint8_t s2_regindex, + uint8_t s2_regsize, + uint8_t lastop); + +void bflb_pka_regsize(struct bflb_device_s *dev, + uint8_t s0_regindex, + uint8_t s0_regsize, + uint8_t d0_regindex, + uint8_t d0_regsize, + uint8_t lastop); + +void bflb_pka_movdat(struct bflb_device_s *dev, + uint8_t s0_regindex, + uint8_t s0_regsize, + uint8_t d0_regindex, + uint8_t d0_regsize, + uint8_t lastop); + +void bflb_pka_nlir(struct bflb_device_s *dev, + uint8_t s0_regindex, + uint8_t s0_regsize, + uint8_t d0_regindex, + uint8_t d0_regsize, + uint8_t lastop); + +void bflb_pka_slir(struct bflb_device_s *dev, + uint8_t regindex, + uint8_t regsize, + uint32_t data, + uint8_t lastop); + +void bflb_pka_clir(struct bflb_device_s *dev, + uint8_t regindex, + uint8_t regsize, + uint16_t size, + uint8_t lastop); + +void bflb_pka_write(struct bflb_device_s *dev, + uint8_t regindex, + uint8_t regsize, + const uint32_t *data, + uint16_t size, + uint8_t lastop); + +void bflb_pka_read(struct bflb_device_s *dev, + uint8_t regindex, + uint8_t regsize, + uint32_t *data, + uint16_t size); + +void bflb_pka_gf2mont(struct bflb_device_s *dev, + uint8_t s_regindex, + uint8_t s_regsize, + uint8_t d_regindex, + uint8_t d_regsize, + uint8_t t_regindex, + uint8_t t_regsize, + uint8_t p_regindex, + uint8_t p_regsize, + uint32_t size); + +void bflb_pka_mont2gf(struct bflb_device_s *dev, + uint8_t s_regindex, + uint8_t s_regsize, + uint8_t d_regindex, + uint8_t d_regsize, + uint8_t invt_regindex, + uint8_t invt_regsize, + uint8_t t_regindex, + uint8_t t_regsize, + uint8_t p_regindex, + uint8_t p_regsize); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/drivers/lhal/include/bflb_sec_sha.h b/drivers/lhal/include/bflb_sec_sha.h index 7d179665..a1a96540 100644 --- a/drivers/lhal/include/bflb_sec_sha.h +++ b/drivers/lhal/include/bflb_sec_sha.h @@ -3,11 +3,13 @@ #include "bflb_core.h" -#define SHA_MODE_SHA1 0 -#define SHA_MODE_SHA224 1 -#define SHA_MODE_SHA256 2 -#define SHA_MODE_SHA384 3 -#define SHA_MODE_SHA512 4 +#define SHA_MODE_SHA256 0 +#define SHA_MODE_SHA224 1 +#define SHA_MODE_SHA1 2 +#define SHA_MODE_SHA512 4 +#define SHA_MODE_SHA384 5 +#define SHA_MODE_SHA512T224 6 +#define SHA_MODE_SHA512T256 7 struct bflb_sha1_ctx_s { uint32_t total[2]; /*!< Number of bytes processed */ @@ -30,6 +32,22 @@ struct bflb_sha512_ctx_s { uint8_t sha_feed; /*!< Sha has feed data */ }; +struct bflb_sha_link_s { + uint32_t : 2; /*!< [1:0]Reserved */ + uint32_t sha_mode : 3; /*!< [4:2]Sha-256/sha-224/sha-1/sha-1/sha-512/sha-384/sha-512T224/sha-512T256 */ + uint32_t : 1; /*!< [5]Reserved */ + uint32_t sha_newhash_dis : 1; /*!< [6]New hash or accumulate last hash */ + uint32_t : 2; /*!< [8:7]Reserved */ + uint32_t sha_intclr : 1; /*!< [9]Clear interrupt */ + uint32_t sha_intset : 1; /*!< [10]Set interrupt */ + uint32_t : 1; /*!< [11]Reserved */ + uint32_t sha_mode_ext : 2; /*!< [13:12]Extention,0:sha 1:md5 2:crc16 3:crc32 */ + uint32_t : 2; /*!< [15:14]Reserved */ + uint32_t sha_msglen : 16; /*!< [31:16]Number of 512-bit block */ + uint32_t sha_srcaddr; /*!< Message source address */ + uint32_t result[16]; /*!< Result of SHA */ +}; + #ifdef __cplusplus extern "C" { #endif @@ -45,6 +63,42 @@ void bflb_sha1_finish(struct bflb_device_s *dev, struct bflb_sha1_ctx_s *ctx, ui void bflb_sha256_finish(struct bflb_device_s *dev, struct bflb_sha256_ctx_s *ctx, uint8_t *output); void bflb_sha512_finish(struct bflb_device_s *dev, struct bflb_sha512_ctx_s *ctx, uint8_t *output); +void bflb_sha_link_init(struct bflb_device_s *dev); +void bflb_sha_link_deinit(struct bflb_device_s *dev); +void bflb_sha1_link_start(struct bflb_device_s *dev, struct bflb_sha1_ctx_s *ctx); +void bflb_sha256_link_start(struct bflb_device_s *dev, struct bflb_sha256_ctx_s *ctx); +void bflb_sha512_link_start(struct bflb_device_s *dev, struct bflb_sha512_ctx_s *ctx); +int bflb_sha1_link_update(struct bflb_device_s *dev, + struct bflb_sha1_ctx_s *ctx, + uint32_t link_addr, + const uint8_t *input, + uint32_t len); +int bflb_sha256_link_update(struct bflb_device_s *dev, + struct bflb_sha256_ctx_s *ctx, + uint32_t link_addr, + const uint8_t *input, + uint32_t len); +int bflb_sha512_link_update(struct bflb_device_s *dev, + struct bflb_sha512_ctx_s *ctx, + uint32_t link_addr, + const uint8_t *input, + uint32_t len); +void bflb_sha1_link_finish(struct bflb_device_s *dev, + struct bflb_sha1_ctx_s *ctx, + uint32_t link_addr, + uint8_t *output); +void bflb_sha256_link_finish(struct bflb_device_s *dev, + struct bflb_sha256_ctx_s *ctx, + uint32_t link_addr, + uint8_t *output); +void bflb_sha512_link_finish(struct bflb_device_s *dev, + struct bflb_sha512_ctx_s *ctx, + uint32_t link_addr, + uint8_t *output); + +void bflb_group0_request_sha_access(struct bflb_device_s *dev); +void bflb_group0_release_sha_access(struct bflb_device_s *dev); + #ifdef __cplusplus } #endif diff --git a/drivers/lhal/include/bflb_sec_trng.h b/drivers/lhal/include/bflb_sec_trng.h index 165f6116..badca279 100644 --- a/drivers/lhal/include/bflb_sec_trng.h +++ b/drivers/lhal/include/bflb_sec_trng.h @@ -7,7 +7,12 @@ extern "C" { #endif -void bflb_trng_read(struct bflb_device_s *dev, uint8_t data[32]); +int bflb_trng_read(struct bflb_device_s *dev, uint8_t data[32]); +int bflb_trng_readlen(uint8_t *data, uint32_t len); +long random(void); + +void bflb_group0_request_trng_access(struct bflb_device_s *dev); +void bflb_group0_release_trng_access(struct bflb_device_s *dev); #ifdef __cplusplus } diff --git a/drivers/lhal/include/bflb_spi.h b/drivers/lhal/include/bflb_spi.h index cc557df1..c3cbad04 100644 --- a/drivers/lhal/include/bflb_spi.h +++ b/drivers/lhal/include/bflb_spi.h @@ -70,7 +70,7 @@ * @} */ -/** @defgroup SPI_CMD uart feature control cmd definition +/** @defgroup SPI_CMD spi feature control cmd definition * @{ */ #define SPI_CMD_SET_DATA_WIDTH (0x01) @@ -78,7 +78,6 @@ #define SPI_CMD_CLEAR_TX_FIFO (0x03) #define SPI_CMD_CLEAR_RX_FIFO (0x04) #define SPI_CMD_SET_CS_INTERVAL (0x05) - /** * @} */ @@ -116,7 +115,7 @@ void bflb_spi_link_txdma(struct bflb_device_s *dev, bool enable); void bflb_spi_link_rxdma(struct bflb_device_s *dev, bool enable); uint32_t bflb_spi_poll_send(struct bflb_device_s *dev, uint32_t data); int bflb_spi_poll_exchange(struct bflb_device_s *dev, const void *txbuffer, void *rxbuffer, size_t nbytes); -int bflb_spi_isbusy(struct bflb_device_s *dev); +bool bflb_spi_isbusy(struct bflb_device_s *dev); void bflb_spi_txint_mask(struct bflb_device_s *dev, bool mask); void bflb_spi_rxint_mask(struct bflb_device_s *dev, bool mask); void bflb_spi_errint_mask(struct bflb_device_s *dev, bool mask); diff --git a/drivers/lhal/include/bflb_timer.h b/drivers/lhal/include/bflb_timer.h index d52335d2..c04cbe8b 100644 --- a/drivers/lhal/include/bflb_timer.h +++ b/drivers/lhal/include/bflb_timer.h @@ -4,6 +4,19 @@ #include "bflb_core.h" #include "bflb_clock.h" +/** @defgroup TIMER_CLK_SOURCE timer clock source definition + * @{ + */ +#define TIMER_CLKSRC_BCLK 0 +#define TIMER_CLKSRC_32K 1 +#define TIMER_CLKSRC_1K 2 +#define TIMER_CLKSRC_XTAL 3 +#define TIMER_CLKSRC_GPIO 4 +#define TIMER_CLKSRC_NO 5 +/** + * @} + */ + /** @defgroup TIMER_COUNTER_MODE timer counter mode definition * @{ */ @@ -24,11 +37,20 @@ * @} */ +/** @defgroup TIMER_CAPTURE_POLARITY timer capture polarity definition + * @{ + */ +#define TIMER_CAPTURE_POLARITY_RISING 0 +#define TIMER_CAPTURE_POLARITY_FALLING 1 +/** + * @} + */ + /** * @brief TIMER configuration structure * * @param counter_mode Timer counter mode, use @ref TIMER_COUNTER_MODE - * @param clock_source Timer clock source, use BFLB_SYSTEM_* definition + * @param clock_source Timer clock source, use @ref TIMER_CLK_SOURCE * @param clock_div Timer clock divison value, from 0 to 255 * @param trigger_comp_id Timer count register preload trigger source slelect, use @ref TIMER_COMP_ID * @param comp0_val Timer compare 0 value @@ -47,6 +69,17 @@ struct bflb_timer_config_s { uint32_t preload_val; }; +/** + * @brief TIMER capture configuration structure + * + * @param pin Timer capture pin + * @param polarity Timer capture polarity, use @ref TIMER_CAPTURE_POLARITY + */ +struct bflb_timer_capture_config_s { + uint8_t pin; + uint8_t polarity; +}; + #ifdef __cplusplus extern "C" { #endif @@ -63,8 +96,9 @@ void bflb_timer_compint_mask(struct bflb_device_s *dev, uint8_t cmp_no, bool mas bool bflb_timer_get_compint_status(struct bflb_device_s *dev, uint8_t cmp_no); void bflb_timer_compint_clear(struct bflb_device_s *dev, uint8_t cmp_no); +void bflb_timer_capture_init(struct bflb_device_s *dev, const struct bflb_timer_capture_config_s *config); + #ifdef __cplusplus } #endif - #endif \ No newline at end of file diff --git a/drivers/lhal/include/bflb_uart.h b/drivers/lhal/include/bflb_uart.h index 1e687a37..996361b3 100644 --- a/drivers/lhal/include/bflb_uart.h +++ b/drivers/lhal/include/bflb_uart.h @@ -87,6 +87,9 @@ #define UART_INTSTS_RX_ADS (1 << 10) #define UART_INTSTS_RX_AD5 (1 << 11) #endif +/** + * @} + */ /** @defgroup UART_INTCLR uart interrupt clear definition * @{ @@ -103,7 +106,6 @@ #define UART_INTCLR_RX_ADS (1 << 10) #define UART_INTCLR_RX_AD5 (1 << 11) #endif - /** * @} */ @@ -111,27 +113,26 @@ /** @defgroup UART_CMD uart feature control cmd definition * @{ */ -#define UART_CMD_SET_BAUD_RATE (0x01) -#define UART_CMD_SET_DATA_BITS (0x02) -#define UART_CMD_SET_STOP_BITS (0x03) -#define UART_CMD_SET_PARITY_BITS (0x04) -#define UART_CMD_CLR_TX_FIFO (0x05) -#define UART_CMD_CLR_RX_FIFO (0x06) -#define UART_CMD_SET_RTO_VALUE (0x07) -#define UART_CMD_SET_RTS_VALUE (0x08) -#define UART_CMD_GET_TX_FIFO_CNT (0x09) -#define UART_CMD_GET_RX_FIFO_CNT (0x0a) -#define UART_CMD_SET_AUTO_BAUD (0x0b) -#define UART_CMD_GET_AUTO_BAUD (0x0c) -#define UART_CMD_SET_BREAK_VALUE (0x0d) -#define UART_CMD_SET_TX_LIN_VALUE (0x0e) -#define UART_CMD_SET_RX_LIN_VALUE (0x0f) -#define UART_CMD_SET_TX_RX_EN (0x10) -#if !defined(BL602) && !defined(BL702) -#define UART_CMD_SET_TX_RS485_EN (0x11) -#define UART_CMD_SET_TX_RS485_POL (0x12) -#endif -#define UART_CMD_SET_ABR_PW_VALUE (0x13) +#define UART_CMD_SET_BAUD_RATE (0x01) +#define UART_CMD_SET_DATA_BITS (0x02) +#define UART_CMD_SET_STOP_BITS (0x03) +#define UART_CMD_SET_PARITY_BITS (0x04) +#define UART_CMD_CLR_TX_FIFO (0x05) +#define UART_CMD_CLR_RX_FIFO (0x06) +#define UART_CMD_SET_RTO_VALUE (0x07) +#define UART_CMD_SET_RTS_VALUE (0x08) +#define UART_CMD_GET_TX_FIFO_CNT (0x09) +#define UART_CMD_GET_RX_FIFO_CNT (0x0a) +#define UART_CMD_SET_AUTO_BAUD (0x0b) +#define UART_CMD_GET_AUTO_BAUD (0x0c) +#define UART_CMD_SET_BREAK_VALUE (0x0d) +#define UART_CMD_SET_TX_LIN_VALUE (0x0e) +#define UART_CMD_SET_RX_LIN_VALUE (0x0f) +#define UART_CMD_SET_TX_RX_EN (0x10) +#define UART_CMD_SET_TX_RS485_EN (0x11) +#define UART_CMD_SET_TX_RS485_POLARITY (0x12) +#define UART_CMD_SET_ABR_ALLOWABLE_ERROR (0x13) +#define UART_CMD_SET_SW_RTS_CONTROL (0x14) /** * @} */ @@ -170,10 +171,14 @@ extern "C" { void bflb_uart_init(struct bflb_device_s *dev, const struct bflb_uart_config_s *config); void bflb_uart_deinit(struct bflb_device_s *dev); +void bflb_uart_enable(struct bflb_device_s *dev); +void bflb_uart_disable(struct bflb_device_s *dev); void bflb_uart_link_txdma(struct bflb_device_s *dev, bool enable); void bflb_uart_link_rxdma(struct bflb_device_s *dev, bool enable); void bflb_uart_putchar(struct bflb_device_s *dev, int ch); int bflb_uart_getchar(struct bflb_device_s *dev); +void bflb_uart_put(struct bflb_device_s *dev, uint8_t *data, uint32_t len); +int bflb_uart_get(struct bflb_device_s *dev, uint8_t *data, uint32_t len); bool bflb_uart_txready(struct bflb_device_s *dev); bool bflb_uart_txempty(struct bflb_device_s *dev); bool bflb_uart_rxavailable(struct bflb_device_s *dev); @@ -183,7 +188,7 @@ void bflb_uart_errint_mask(struct bflb_device_s *dev, bool mask); uint32_t bflb_uart_get_intstatus(struct bflb_device_s *dev); void bflb_uart_int_clear(struct bflb_device_s *dev, uint32_t int_clear); -void bflb_uart_feature_control(struct bflb_device_s *dev, int cmd, size_t arg); +int bflb_uart_feature_control(struct bflb_device_s *dev, int cmd, size_t arg); #ifdef __cplusplus } diff --git a/drivers/lhal/include/bflb_wdg.h b/drivers/lhal/include/bflb_wdg.h index 22301308..e05124b8 100644 --- a/drivers/lhal/include/bflb_wdg.h +++ b/drivers/lhal/include/bflb_wdg.h @@ -4,6 +4,13 @@ #include "bflb_core.h" #include "bflb_clock.h" +#define WDG_CLKSRC_BCLK 0 +#define WDG_CLKSRC_32K 1 +#define WDG_CLKSRC_1K 2 +#define WDG_CLKSRC_XTAL 3 +#define WDG_CLKSRC_GPIO 4 +#define WDG_CLKSRC_NO 5 + /** @defgroup WDG_MODE Watch-dog reset/interrupt mode definition * @{ */ diff --git a/drivers/lhal/include/hardware/adc_reg.h b/drivers/lhal/include/hardware/adc_reg.h index 3eee688f..3bdc3623 100644 --- a/drivers/lhal/include/hardware/adc_reg.h +++ b/drivers/lhal/include/hardware/adc_reg.h @@ -72,7 +72,7 @@ #define GPIP_GPADC_RDY (1 << 4U) #define GPIP_GPADC_FIFO_OVERRUN (1 << 5U) #define GPIP_GPADC_FIFO_UNDERRUN (1 << 6U) -#if defined(BL702) +#if defined(BL702) || defined(BL702L) #define GPIP_GPADC_FIFO_RDY (1 << 7U) #endif #define GPIP_GPADC_RDY_CLR (1 << 8U) @@ -81,7 +81,7 @@ #define GPIP_GPADC_RDY_MASK (1 << 12U) #define GPIP_GPADC_FIFO_OVERRUN_MASK (1 << 13U) #define GPIP_GPADC_FIFO_UNDERRUN_MASK (1 << 14U) -#if defined(BL702) +#if defined(BL702) || defined(BL702L) #define GPIP_GPADC_FIFO_RDY_MASK (1 << 15U) #endif #define GPIP_GPADC_FIFO_DATA_COUNT_SHIFT (16U) @@ -127,7 +127,7 @@ #if defined(BL616) || defined(BL606P) || defined(BL808) || defined(BL628) #define AON_GPADC_SEN_SEL_MASK (0x7 << AON_GPADC_SEN_SEL_SHIFT) #define AON_GPADC_SEN_TEST_EN (1 << 31U) -#elif defined(BL702) || defined(BL602) +#elif defined(BL702) || defined(BL602) || defined(BL702L) #define AON_GPADC_SEN_SEL_MASK (0x3 << AON_GPADC_SEN_SEL_SHIFT) #define AON_GPADC_SEN_TEST_EN (1 << 30U) #endif diff --git a/drivers/lhal/include/hardware/cks_reg.h b/drivers/lhal/include/hardware/cks_reg.h new file mode 100644 index 00000000..323bb5c9 --- /dev/null +++ b/drivers/lhal/include/hardware/cks_reg.h @@ -0,0 +1,64 @@ +/** + ****************************************************************************** + * @file cks_reg.h + * @version V1.0 + * @date 2022-10-25 + * @brief This file is the description of.IP register + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2020 Bouffalo Lab

+ * + * 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. + * 3. Neither the name of Bouffalo Lab nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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 __CKS_REG_H__ +#define __CKS_REG_H__ + +/**************************************************************************** + * Pre-processor Definitions +****************************************************************************/ + +/* Register offsets *********************************************************/ + +#define CKS_CONFIG_OFFSET (0x0)/* cks_config */ +#define CKS_DATA_IN_OFFSET (0x4)/* data_in */ +#define CKS_OUT_OFFSET (0x8)/* cks_out */ + +/* Register Bitfield definitions *****************************************************/ + +/* 0x0 : cks_config */ +#define CKS_CR_CKS_CLR (1<<0U) +#define CKS_CR_CKS_BYTE_SWAP (1<<1U) + +/* 0x4 : data_in */ +#define CKS_DATA_IN_SHIFT (0U) +#define CKS_DATA_IN_MASK (0xff< 1) { - return -1; + return -EINVAL; } regval = getreg32(reg_base + AON_GPADC_REG_CMD_OFFSET); @@ -587,4 +587,16 @@ void bflb_adc_vbat_enable(struct bflb_device_s *dev) regval = getreg32(reg_base + AON_GPADC_REG_CONFIG2_OFFSET); regval |= AON_GPADC_VBAT_EN; putreg32(regval, reg_base + AON_GPADC_REG_CONFIG2_OFFSET); +} + +void bflb_adc_vbat_disable(struct bflb_device_s *dev) +{ + uint32_t regval; + uint32_t reg_base; + + reg_base = dev->reg_base; + + regval = getreg32(reg_base + AON_GPADC_REG_CONFIG2_OFFSET); + regval &= ~AON_GPADC_VBAT_EN; + putreg32(regval, reg_base + AON_GPADC_REG_CONFIG2_OFFSET); } \ No newline at end of file diff --git a/drivers/lhal/src/bflb_cks.c b/drivers/lhal/src/bflb_cks.c new file mode 100644 index 00000000..830702ae --- /dev/null +++ b/drivers/lhal/src/bflb_cks.c @@ -0,0 +1,34 @@ +#include "bflb_cks.h" +#include "hardware/cks_reg.h" + +void bflb_cks_reset(struct bflb_device_s *dev) +{ + uint32_t regval; + uint32_t reg_base; + + reg_base = dev->reg_base; + regval = getreg32(reg_base + CKS_CONFIG_OFFSET); + regval |= CKS_CR_CKS_CLR; + putreg32(regval, reg_base + CKS_CONFIG_OFFSET); +} + +void bflb_cks_set_endian(struct bflb_device_s *dev, uint8_t endian) +{ + uint32_t reg_base; + + reg_base = dev->reg_base; + putreg32(endian << 1, reg_base + CKS_CONFIG_OFFSET); +} + +uint16_t bflb_cks_compute(struct bflb_device_s *dev, uint8_t *data, uint32_t length) +{ + uint32_t reg_base; + uint32_t i; + + reg_base = dev->reg_base; + for (i = 0; i < length; i++) { + putreg32(data[i], reg_base + CKS_DATA_IN_OFFSET); + } + + return ((uint16_t)(getreg32(reg_base + CKS_OUT_OFFSET) & 0xffff)); +} diff --git a/drivers/lhal/src/bflb_common.c b/drivers/lhal/src/bflb_common.c index 556ea3a9..39e6545e 100644 --- a/drivers/lhal/src/bflb_common.c +++ b/drivers/lhal/src/bflb_common.c @@ -1,4 +1,5 @@ #include "bflb_common.h" +#include "bflb_core.h" void *ATTR_TCM_SECTION arch_memcpy(void *dst, const void *src, uint32_t n) { diff --git a/drivers/lhal/src/bflb_dac.c b/drivers/lhal/src/bflb_dac.c index 1f20196b..be0a7ba0 100644 --- a/drivers/lhal/src/bflb_dac.c +++ b/drivers/lhal/src/bflb_dac.c @@ -1,7 +1,7 @@ #include "bflb_dac.h" #include "hardware/dac_reg.h" -#if defined(BL702) || defined(BL602) +#if defined(BL702) || defined(BL602) || defined(BL702L) #define DAC_GPIP_BASE ((uint32_t)0x40002000) #elif defined(BL616) || defined(BL606P) || defined(BL808) || defined(BL628) #define DAC_GPIP_BASE ((uint32_t)0x20002000) diff --git a/drivers/lhal/src/bflb_dma.c b/drivers/lhal/src/bflb_dma.c index c623a011..89d64565 100644 --- a/drivers/lhal/src/bflb_dma.c +++ b/drivers/lhal/src/bflb_dma.c @@ -8,7 +8,7 @@ struct bflb_dma_irq_callback { void *arg; }; -#if defined(BL702) || defined(BL602) +#if defined(BL702) || defined(BL602) || defined(BL702L) const uint32_t dma_base[] = { 0x4000C000 }; struct bflb_dma_irq_callback dma_callback[1][8]; #elif defined(BL616) @@ -246,7 +246,7 @@ int bflb_dma_channel_lli_reload(struct bflb_device_s *dev, struct bflb_dma_chann lli_count_used_offset += current_lli_count; if (lli_count_used_offset > max_lli_count) { - return -2; + return -ENOMEM; } } @@ -365,8 +365,9 @@ void bflb_dma_channel_tcint_clear(struct bflb_device_s *dev) putreg32(1 << dev->sub_idx, dma_base[dev->idx] + DMA_INTTCCLEAR_OFFSET); } -void bflb_dma_feature_control(struct bflb_device_s *dev, int cmd, size_t arg) +int bflb_dma_feature_control(struct bflb_device_s *dev, int cmd, size_t arg) { + int ret = 0; uint32_t regval; uint32_t channel_base; @@ -394,6 +395,8 @@ void bflb_dma_feature_control(struct bflb_device_s *dev, int cmd, size_t arg) break; default: + ret = -EPERM; break; } + return ret; } \ No newline at end of file diff --git a/drivers/lhal/src/bflb_emac.c b/drivers/lhal/src/bflb_emac.c index 4bd25f9a..12bd5ef2 100644 --- a/drivers/lhal/src/bflb_emac.c +++ b/drivers/lhal/src/bflb_emac.c @@ -34,12 +34,9 @@ ****************************************************************************** */ #include "bflb_core.h" -#include "bflb_common.h" #include "bflb_emac.h" #include "bflb_clock.h" -#include "bflb_mtimer.h" #include "bflb_l1c.h" - #include "hardware/emac_reg.h" /* private definition */ @@ -634,6 +631,7 @@ int bflb_emac_phy_reg_write(struct bflb_device_s *dev, uint16_t phy_reg, uint16_ */ int bflb_emac_feature_control(struct bflb_device_s *dev, int cmd, size_t arg) { + int ret = 0; uint32_t reg_val; uint32_t reg_base; @@ -748,10 +746,10 @@ int bflb_emac_feature_control(struct bflb_device_s *dev, int cmd, size_t arg) break; default: - return -1; + ret = -EPERM; break; } - return 0; + return ret; } /** diff --git a/drivers/lhal/src/bflb_gpio.c b/drivers/lhal/src/bflb_gpio.c index 7221b3e6..95fcabcd 100644 --- a/drivers/lhal/src/bflb_gpio.c +++ b/drivers/lhal/src/bflb_gpio.c @@ -16,7 +16,7 @@ void bflb_gpio_init(struct bflb_device_s *dev, uint8_t pin, uint32_t cfgset) mode = (cfgset & GPIO_MODE_MASK); drive = (cfgset & GPIO_DRV_MASK) >> GPIO_DRV_SHIFT; -#if defined(BL702) || defined(BL602) +#if defined(BL702) || defined(BL602) || defined(BL702L) uint32_t regval; uint8_t is_odd = 0; @@ -61,7 +61,10 @@ void bflb_gpio_init(struct bflb_device_s *dev, uint8_t pin, uint32_t cfgset) cfg |= (drive << (is_odd * 16 + 2)); cfg |= (function << (is_odd * 16 + 8)); - +#if defined(BL702L) + /* configure output mode:set and clr mode */ + cfg |= (1 << (is_odd * 16 + 15)); +#endif #elif defined(BL616) || defined(BL808) || defined(BL606P) || defined(BL628) cfg_address = reg_base + GLB_GPIO_CFG0_OFFSET + (pin << 2); cfg = 0; @@ -106,7 +109,7 @@ void bflb_gpio_deinit(struct bflb_device_s *dev, uint8_t pin) void bflb_gpio_set(struct bflb_device_s *dev, uint8_t pin) { -#if defined(BL702) || defined(BL602) +#if defined(BL702) || defined(BL602) || defined(BL702L) putreg32(1 << (pin & 0x1f), dev->reg_base + GLB_GPIO_CFGCTL32_OFFSET); #elif defined(BL616) || defined(BL808) || defined(BL606P) || defined(BL628) putreg32(1 << (pin & 0x1f), dev->reg_base + GLB_GPIO_CFG138_OFFSET + ((pin >> 5) << 2)); @@ -115,7 +118,7 @@ void bflb_gpio_set(struct bflb_device_s *dev, uint8_t pin) void bflb_gpio_reset(struct bflb_device_s *dev, uint8_t pin) { -#if defined(BL702) || defined(BL602) +#if defined(BL702) || defined(BL602) || defined(BL702L) putreg32(0 << (pin & 0x1f), dev->reg_base + GLB_GPIO_CFGCTL32_OFFSET); #elif defined(BL616) || defined(BL808) || defined(BL606P) || defined(BL628) putreg32(1 << (pin & 0x1f), dev->reg_base + GLB_GPIO_CFG140_OFFSET + ((pin >> 5) << 2)); @@ -124,7 +127,7 @@ void bflb_gpio_reset(struct bflb_device_s *dev, uint8_t pin) bool bflb_gpio_read(struct bflb_device_s *dev, uint8_t pin) { -#if defined(BL702) || defined(BL602) +#if defined(BL702) || defined(BL602) || defined(BL702L) return (getreg32(dev->reg_base + GLB_GPIO_CFGCTL30_OFFSET) & (1 << pin)); #elif defined(BL616) || defined(BL808) || defined(BL606P) || defined(BL628) return (getreg32(dev->reg_base + GLB_GPIO_CFG0_OFFSET + (pin << 2)) & GLB_REG_GPIO_0_I); @@ -144,7 +147,7 @@ void bflb_gpio_int_init(struct bflb_device_s *dev, uint8_t pin, uint8_t trig_mod bflb_gpio_int_mask(dev, pin, true); bflb_gpio_int_clear(dev, pin); -#if defined(BL702) || defined(BL602) +#if defined(BL702) || defined(BL602) || defined(BL702L) cfg_address = reg_base + GLB_GPIO_INT_MODE_SET1_OFFSET + ((pin / 10) << 2); regval = getreg32(cfg_address); regval &= ~(0x07 << ((pin % 10) * 3)); @@ -165,7 +168,7 @@ void bflb_gpio_int_mask(struct bflb_device_s *dev, uint8_t pin, bool mask) uint32_t regval; reg_base = dev->reg_base; -#if defined(BL702) || defined(BL602) +#if defined(BL702) || defined(BL602) || defined(BL702L) cfg_address = reg_base + GLB_GPIO_INT_MASK1_OFFSET; regval = getreg32(cfg_address); @@ -189,7 +192,7 @@ void bflb_gpio_int_mask(struct bflb_device_s *dev, uint8_t pin, bool mask) bool bflb_gpio_get_intstatus(struct bflb_device_s *dev, uint8_t pin) { -#if defined(BL702) || defined(BL602) +#if defined(BL702) || defined(BL602) || defined(BL702L) return (getreg32(dev->reg_base + GLB_GPIO_INT_STAT1_OFFSET) & (1 << pin)); #elif defined(BL616) || defined(BL808) || defined(BL606P) || defined(BL628) return (getreg32(dev->reg_base + GLB_GPIO_CFG0_OFFSET + (pin << 2)) & GLB_GPIO_0_INT_STAT); @@ -203,7 +206,7 @@ void bflb_gpio_int_clear(struct bflb_device_s *dev, uint8_t pin) uint32_t regval; reg_base = dev->reg_base; -#if defined(BL702) || defined(BL602) +#if defined(BL702) || defined(BL602) || defined(BL702L) cfg_address = reg_base + GLB_GPIO_INT_CLR1_OFFSET; regval = getreg32(cfg_address); @@ -249,6 +252,26 @@ void bflb_gpio_uart_init(struct bflb_device_s *dev, uint8_t pin, uint8_t uart_fu } } + putreg32(regval, reg_base + GLB_UART_SIG_SEL_0_OFFSET); +#elif defined(BL702L) +#define GLB_UART_SIG_SEL_0_OFFSET (0xC0) + regval = getreg32(reg_base + GLB_UART_SIG_SEL_0_OFFSET); + + sig = pin % 4; + sig_pos = sig << 2; + + regval &= (~(0x0f << sig_pos)); + regval |= (uart_func << sig_pos); + + for (uint8_t i = 0; i < 4; i++) { + /* reset other sigs which are the same with uart_func */ + sig_pos = i << 2; + if (((regval & (0x0f << sig_pos)) == (uart_func << sig_pos)) && (i != sig) && (uart_func != 0x0f)) { + regval &= (~(0x0f << sig_pos)); + regval |= (0x0f << sig_pos); + } + } + putreg32(regval, reg_base + GLB_UART_SIG_SEL_0_OFFSET); #elif defined(BL616) || defined(BL808) || defined(BL606P) || defined(BL628) #define GLB_UART_CFG1_OFFSET (0x154) @@ -313,4 +336,34 @@ void bflb_gpio_uart_init(struct bflb_device_s *dev, uint8_t pin, uint8_t uart_fu } #endif bflb_gpio_init(dev, pin, (7 << GPIO_FUNC_SHIFT) | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_1); +} + +int bflb_gpio_feature_control(struct bflb_device_s *dev, int cmd, size_t arg) +{ + int ret = 0; + uint32_t reg_base; + uint32_t regval; + uint8_t pin = arg; + + reg_base = dev->reg_base; + switch (cmd) { + case GPIO_CMD_GET_GPIO_FUN: +#if defined(BL702) || defined(BL602) || defined(BL702L) + if ((pin % 2)) { + regval = getreg32(reg_base + GLB_GPIO_CFGCTL0_OFFSET + (pin / 2 * 4)) & GLB_REG_GPIO_0_FUNC_SEL_MASK; + regval >>= GLB_REG_GPIO_0_FUNC_SEL_SHIFT; + } else { + regval = getreg32(reg_base + GLB_GPIO_CFGCTL0_OFFSET + (pin / 2 * 4)) & GLB_REG_GPIO_1_FUNC_SEL_MASK; + regval >>= GLB_REG_GPIO_1_FUNC_SEL_SHIFT; + } +#elif defined(BL616) || defined(BL808) || defined(BL606P) || defined(BL628) + regval = getreg32(reg_base + GLB_GPIO_CFG0_OFFSET + (pin << 2)) & GLB_REG_GPIO_0_FUNC_SEL_MASK; + regval >>= GLB_REG_GPIO_0_FUNC_SEL_SHIFT; +#endif + return regval; + default: + ret = -EPERM; + break; + } + return ret; } \ No newline at end of file diff --git a/drivers/lhal/src/bflb_i2c.c b/drivers/lhal/src/bflb_i2c.c index 9b2f3da1..1de2535f 100644 --- a/drivers/lhal/src/bflb_i2c.c +++ b/drivers/lhal/src/bflb_i2c.c @@ -261,13 +261,14 @@ void bflb_i2c_init(struct bflb_device_s *dev, uint32_t frequency) bflb_i2c_disable(dev); - regval = (I2C_CR_I2C_END_EN | - I2C_CR_I2C_END_MASK | - I2C_CR_I2C_TXF_MASK | - I2C_CR_I2C_RXF_MASK | - I2C_CR_I2C_NAK_MASK | - I2C_CR_I2C_ARB_MASK | - I2C_CR_I2C_FER_MASK); + regval = getreg32(reg_base + I2C_INT_STS_OFFSET); + + regval |= (I2C_CR_I2C_END_MASK | + I2C_CR_I2C_TXF_MASK | + I2C_CR_I2C_RXF_MASK | + I2C_CR_I2C_NAK_MASK | + I2C_CR_I2C_ARB_MASK | + I2C_CR_I2C_FER_MASK); putreg32(regval, reg_base + I2C_INT_STS_OFFSET); @@ -283,12 +284,14 @@ void bflb_i2c_deinit(struct bflb_device_s *dev) bflb_i2c_disable(dev); - regval = (I2C_CR_I2C_END_MASK | - I2C_CR_I2C_TXF_MASK | - I2C_CR_I2C_RXF_MASK | - I2C_CR_I2C_NAK_MASK | - I2C_CR_I2C_ARB_MASK | - I2C_CR_I2C_FER_MASK); + regval = getreg32(reg_base + I2C_INT_STS_OFFSET); + + regval |= (I2C_CR_I2C_END_MASK | + I2C_CR_I2C_TXF_MASK | + I2C_CR_I2C_RXF_MASK | + I2C_CR_I2C_NAK_MASK | + I2C_CR_I2C_ARB_MASK | + I2C_CR_I2C_FER_MASK); putreg32(regval, reg_base + I2C_INT_STS_OFFSET); } @@ -352,17 +355,69 @@ int bflb_i2c_transfer(struct bflb_device_s *dev, struct bflb_i2c_msg_s *msgs, in } if (msgs[i].length > 256) { - return -1; + return -EINVAL; } bflb_i2c_set_datalen(dev, msgs[i].length); if (msgs[i].flags & I2C_M_READ) { bflb_i2c_set_dir(dev, 1); - bflb_i2c_read_bytes(dev, msgs[i].buffer, msgs[i].length); + if ((msgs[i].flags & I2C_M_DMA) == 0) { + bflb_i2c_read_bytes(dev, msgs[i].buffer, msgs[i].length); + } else { + bflb_i2c_enable(dev); + } } else { bflb_i2c_set_dir(dev, 0); - bflb_i2c_write_bytes(dev, msgs[i].buffer, msgs[i].length); + if ((msgs[i].flags & I2C_M_DMA) == 0) { + bflb_i2c_write_bytes(dev, msgs[i].buffer, msgs[i].length); + } else { + bflb_i2c_enable(dev); + } } } return 0; -} \ No newline at end of file +} + +void bflb_i2c_int_mask(struct bflb_device_s *dev, uint32_t int_type, bool mask) +{ + uint32_t reg_base; + uint32_t regval; + + reg_base = dev->reg_base; + regval = getreg32(reg_base + I2C_INT_STS_OFFSET); + regval &= ~((int_type & 0xff) << 8); + if (mask) { + regval |= (int_type & 0xff) << 8; + } + putreg32(regval, reg_base + I2C_INT_STS_OFFSET); +} + +void bflb_i2c_int_clear(struct bflb_device_s *dev, uint32_t int_clear) +{ + uint32_t reg_base; + uint32_t regval; + + reg_base = dev->reg_base; + regval = getreg32(reg_base + I2C_INT_STS_OFFSET); + regval |= (int_clear & 0xff) << 16; + putreg32(regval, reg_base + I2C_INT_STS_OFFSET); +} + +uint32_t bflb_i2c_get_intstatus(struct bflb_device_s *dev) +{ + uint32_t reg_base; + + reg_base = dev->reg_base; + return(getreg32(reg_base + I2C_INT_STS_OFFSET) & 0xff); +} + +int bflb_i2c_feature_control(struct bflb_device_s *dev, int cmd, size_t arg) +{ + int ret = 0; + switch (cmd) { + default: + ret = -EPERM; + break; + } + return ret; +} diff --git a/drivers/lhal/src/bflb_irq.c b/drivers/lhal/src/bflb_irq.c index 82d834df..f4b7d7c8 100644 --- a/drivers/lhal/src/bflb_irq.c +++ b/drivers/lhal/src/bflb_irq.c @@ -46,7 +46,7 @@ void bflb_irq_restore(uint32_t flags) int bflb_irq_attach(int irq, irq_callback isr, void *arg) { if (irq > CONFIG_IRQ_NUM) { - return -1; + return -EINVAL; } g_irqvector[irq].handler = isr; g_irqvector[irq].arg = arg; @@ -56,7 +56,7 @@ int bflb_irq_attach(int irq, irq_callback isr, void *arg) int bflb_irq_detach(int irq) { if (irq > CONFIG_IRQ_NUM) { - return -1; + return -EINVAL; } return 0; } diff --git a/drivers/lhal/src/bflb_mtimer.c b/drivers/lhal/src/bflb_mtimer.c index 95bcc4b7..351d960d 100644 --- a/drivers/lhal/src/bflb_mtimer.c +++ b/drivers/lhal/src/bflb_mtimer.c @@ -1,4 +1,6 @@ #include "bflb_mtimer.h" +#include "bflb_core.h" +#include "bflb_irq.h" #if defined(BL602) || defined(BL702) || defined(BL702L) #include #else @@ -34,6 +36,11 @@ void bflb_mtimer_config(uint64_t ticks, void (*interruptfun)(void)) bflb_irq_enable(7); } +__WEAK uint32_t bflb_mtimer_get_freq(void) +{ + return 1 * 1000 * 1000; +} + uint64_t bflb_mtimer_get_time_us() { volatile uint64_t tmp_low, tmp_high, tmp_low1, tmp_high1; @@ -51,8 +58,11 @@ uint64_t bflb_mtimer_get_time_us() tmp_high1 = (uint64_t)csi_coret_get_valueh(); #endif } while (tmp_low > tmp_low1 || tmp_high != tmp_high1); - - return (uint64_t)((tmp_high1 << 32) + tmp_low1); +#ifdef CONFIG_MTIMER_CUSTOM_FREQUENCE + return ((uint64_t)(((tmp_high1 << 32) + tmp_low1)) * ((uint64_t)(1 * 1000 * 1000)) / bflb_mtimer_get_freq()); +#else + return (uint64_t)(((tmp_high1 << 32) + tmp_low1)); +#endif } uint64_t bflb_mtimer_get_time_ms() diff --git a/drivers/lhal/src/bflb_pwm_v1.c b/drivers/lhal/src/bflb_pwm_v1.c index 16dd3ca0..323cc993 100644 --- a/drivers/lhal/src/bflb_pwm_v1.c +++ b/drivers/lhal/src/bflb_pwm_v1.c @@ -25,6 +25,7 @@ void bflb_pwm_v1_channel_init(struct bflb_device_s *dev, uint8_t ch, const struc regval |= (1 << PWM_REG_CLK_SEL_SHIFT); } else if (config->clk_source == BFLB_SYSTEM_32K_CLK) { regval |= (2 << PWM_REG_CLK_SEL_SHIFT); + } else { } putreg32(regval, reg_base + PWM0_CONFIG_OFFSET + ch * 0x20); @@ -189,8 +190,9 @@ void bflb_pwm_v1_int_clear(struct bflb_device_s *dev, uint32_t int_clear) putreg32(regval, dev->reg_base + PWM_INT_CONFIG_OFFSET); } -void bflb_pwm_v1_feature_control(struct bflb_device_s *dev, uint8_t ch, int cmd, size_t arg) +int bflb_pwm_v1_feature_control(struct bflb_device_s *dev, uint8_t ch, int cmd, size_t arg) { + int ret = 0; uint32_t reg_base; uint32_t regval; @@ -244,6 +246,8 @@ void bflb_pwm_v1_feature_control(struct bflb_device_s *dev, uint8_t ch, int cmd, break; default: + ret = -EPERM; break; } + return ret; } \ No newline at end of file diff --git a/drivers/lhal/src/bflb_pwm_v2.c b/drivers/lhal/src/bflb_pwm_v2.c index e53c96fa..f38786d9 100644 --- a/drivers/lhal/src/bflb_pwm_v2.c +++ b/drivers/lhal/src/bflb_pwm_v2.c @@ -25,6 +25,7 @@ void bflb_pwm_v2_init(struct bflb_device_s *dev, const struct bflb_pwm_v2_config regval |= (1 << PWM_REG_CLK_SEL_SHIFT); } else if (config->clk_source == BFLB_SYSTEM_32K_CLK) { regval |= (2 << PWM_REG_CLK_SEL_SHIFT); + } else { } regval &= ~PWM_CLK_DIV_MASK; regval |= (uint32_t)config->clk_div << PWM_CLK_DIV_SHIFT; @@ -292,8 +293,9 @@ uint32_t bflb_pwm_v2_get_intstatus(struct bflb_device_s *dev) return (regval_sts & ~regval_mask & regval_en); } -void bflb_pwm_v2_feature_control(struct bflb_device_s *dev, int cmd, size_t arg) +int bflb_pwm_v2_feature_control(struct bflb_device_s *dev, int cmd, size_t arg) { + int ret = 0; uint32_t reg_base; uint32_t regval; @@ -354,6 +356,8 @@ void bflb_pwm_v2_feature_control(struct bflb_device_s *dev, int cmd, size_t arg) break; default: + ret = -EPERM; break; } + return ret; } diff --git a/drivers/lhal/src/bflb_sec_aes.c b/drivers/lhal/src/bflb_sec_aes.c index 9a87099d..d6c21443 100644 --- a/drivers/lhal/src/bflb_sec_aes.c +++ b/drivers/lhal/src/bflb_sec_aes.c @@ -2,11 +2,12 @@ #include "hardware/sec_eng_reg.h" #define CONFIG_BFLB_AES_USE_BE -#define CONFIG_BFLB_AES_HW_KEY_SEL 1 #define BFLB_PUT_LE32(p) ((p[3] << 24) | (p[2] << 16) | (p[1] << 8) | (p[0])) #define BFLB_PUT_BE32(p) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3])) +volatile uint8_t hw_key_sel = 1; + void bflb_aes_init(struct bflb_device_s *dev) { uint32_t regval; @@ -37,6 +38,11 @@ void bflb_aes_deinit(struct bflb_device_s *dev) putreg32(regval, reg_base + SEC_ENG_SE_AES_0_CTRL_OFFSET); } +void bflb_aes_set_hwkey(uint8_t keysel) +{ + hw_key_sel = keysel; +} + void bflb_aes_set_mode(struct bflb_device_s *dev, uint8_t mode) { uint32_t regval; @@ -89,12 +95,12 @@ void bflb_aes_setkey(struct bflb_device_s *dev, const uint8_t *key, uint16_t key if (key == NULL) { regval = getreg32(reg_base + SEC_ENG_SE_AES_0_KEY_SEL_OFFSET); regval &= ~SEC_ENG_SE_AES_0_KEY_SEL_MASK; - regval |= (CONFIG_BFLB_AES_HW_KEY_SEL << SEC_ENG_SE_AES_0_KEY_SEL_SHIFT); + regval |= (hw_key_sel << SEC_ENG_SE_AES_0_KEY_SEL_SHIFT); putreg32(regval, reg_base + SEC_ENG_SE_AES_0_KEY_SEL_OFFSET); regval = getreg32(reg_base + SEC_ENG_SE_AES_1_KEY_SEL_OFFSET); regval &= ~SEC_ENG_SE_AES_1_KEY_SEL_MASK; - regval |= (CONFIG_BFLB_AES_HW_KEY_SEL << SEC_ENG_SE_AES_1_KEY_SEL_SHIFT); + regval |= (hw_key_sel << SEC_ENG_SE_AES_1_KEY_SEL_SHIFT); putreg32(regval, reg_base + SEC_ENG_SE_AES_1_KEY_SEL_OFFSET); } else { putreg32(BFLB_PUT_LE32(temp_key), reg_base + SEC_ENG_SE_AES_0_KEY_0_OFFSET); @@ -137,15 +143,11 @@ int bflb_aes_encrypt(struct bflb_device_s *dev, reg_base = dev->reg_base; - regval = getreg32(reg_base + SEC_ENG_SE_AES_0_CTRL_OFFSET); - - if (regval & SEC_ENG_SE_AES_0_BUSY) { - return -1; - } if (len % 16) { - return -2; + return -EINVAL; } + regval = getreg32(reg_base + SEC_ENG_SE_AES_0_CTRL_OFFSET); regval &= ~SEC_ENG_SE_AES_0_TRIG_1T; regval &= ~SEC_ENG_SE_AES_0_IV_SEL; /* Clear aes iv sel to select new iv */ regval &= ~SEC_ENG_SE_AES_0_DEC_EN; /* Set AES encryption */ @@ -202,16 +204,11 @@ int bflb_aes_decrypt(struct bflb_device_s *dev, reg_base = dev->reg_base; - regval = getreg32(reg_base + SEC_ENG_SE_AES_0_CTRL_OFFSET); - - if (regval & SEC_ENG_SE_AES_0_BUSY) { - return -1; - } - if (len % 16) { - return -2; + return -EINVAL; } + regval = getreg32(reg_base + SEC_ENG_SE_AES_0_CTRL_OFFSET); regval &= ~SEC_ENG_SE_AES_0_TRIG_1T; regval &= ~SEC_ENG_SE_AES_0_IV_SEL; /* Clear aes iv sel to select new iv */ regval |= SEC_ENG_SE_AES_0_DEC_EN; /* Set AES decryption */ @@ -254,3 +251,115 @@ int bflb_aes_decrypt(struct bflb_device_s *dev, } return 0; } + +void bflb_aes_link_init(struct bflb_device_s *dev) +{ + uint32_t regval; + uint32_t reg_base; + + reg_base = dev->reg_base; + +#ifdef CONFIG_BFLB_AES_USE_BE + putreg32(0x1f, reg_base + SEC_ENG_SE_AES_0_ENDIAN_OFFSET); +#else + putreg32(0x10, reg_base + SEC_ENG_SE_AES_0_ENDIAN_OFFSET); +#endif + + regval = getreg32(reg_base + SEC_ENG_SE_AES_0_CTRL_OFFSET); + regval |= SEC_ENG_SE_AES_0_LINK_MODE; + regval |= SEC_ENG_SE_AES_0_EN; + putreg32(regval, reg_base + SEC_ENG_SE_AES_0_CTRL_OFFSET); +} + +void bflb_aes_link_deinit(struct bflb_device_s *dev) +{ + uint32_t regval; + uint32_t reg_base; + + reg_base = dev->reg_base; + + regval = getreg32(reg_base + SEC_ENG_SE_AES_0_CTRL_OFFSET); + regval &= ~SEC_ENG_SE_AES_0_LINK_MODE; + regval &= ~SEC_ENG_SE_AES_0_EN; + putreg32(regval, reg_base + SEC_ENG_SE_AES_0_CTRL_OFFSET); +} + +int bflb_aes_link_update(struct bflb_device_s *dev, + uint32_t link_addr, + const uint8_t *input, + uint8_t *output, + uint32_t len) +{ + uint32_t regval; + uint32_t reg_base; + + reg_base = dev->reg_base; + + if ((len % 16) || ((link_addr & 0x03))) { + return -EINVAL; + } + + regval = getreg32(reg_base + SEC_ENG_SE_AES_0_CTRL_OFFSET); + regval &= ~SEC_ENG_SE_AES_0_TRIG_1T; + putreg32(regval, reg_base + SEC_ENG_SE_AES_0_CTRL_OFFSET); + + /* Set link address */ + putreg32(link_addr, reg_base + SEC_ENG_SE_AES_0_LINK_OFFSET); + + /* Change source buffer address and destination buffer address */ + *(uint32_t *)(uintptr_t)(link_addr + 4) = (uint32_t)(uintptr_t)input; + *(uint32_t *)(uintptr_t)(link_addr + 8) = (uint32_t)(uintptr_t)output; + + /* Set data length */ + *((uint16_t *)(uintptr_t)link_addr + 1) = len / 16; + + regval = getreg32(reg_base + SEC_ENG_SE_AES_0_CTRL_OFFSET); + regval |= SEC_ENG_SE_AES_0_TRIG_1T; + putreg32(regval, reg_base + SEC_ENG_SE_AES_0_CTRL_OFFSET); + + __asm volatile("nop"); + __asm volatile("nop"); + + while (getreg32(reg_base + SEC_ENG_SE_AES_0_CTRL_OFFSET) & SEC_ENG_SE_AES_0_BUSY) { + } + + return 0; +} + +void bflb_group0_request_aes_access(struct bflb_device_s *dev) +{ + uint32_t regval; + uint32_t reg_base; + + reg_base = dev->reg_base; + + regval = getreg32(reg_base + SEC_ENG_SE_CTRL_PROT_RD_OFFSET); + if (((regval >> 2) & 0x03) == 0x03) { + putreg32(0x02, reg_base + SEC_ENG_SE_AES_0_CTRL_PROT_OFFSET); + + regval = getreg32(reg_base + SEC_ENG_SE_CTRL_PROT_RD_OFFSET); + if (((regval >> 2) & 0x03) == 0x01) { + } + } +} + +void bflb_group0_release_aes_access(struct bflb_device_s *dev) +{ + uint32_t reg_base; + + reg_base = dev->reg_base; + + putreg32(0x06, reg_base + SEC_ENG_SE_AES_0_CTRL_PROT_OFFSET); +} + +void bflb_aes_set_hwkey_source(struct bflb_device_s *dev, uint8_t source) +{ + uint32_t regval; + uint32_t reg_base; + + reg_base = dev->reg_base; + + regval = getreg32(reg_base + SEC_ENG_SE_AES_0_SBOOT_OFFSET); + regval |= (source << 0); + putreg32(0x02, reg_base + SEC_ENG_SE_AES_0_SBOOT_OFFSET); +} diff --git a/drivers/lhal/src/bflb_sec_sha.c b/drivers/lhal/src/bflb_sec_sha.c index e8923442..53b303d2 100644 --- a/drivers/lhal/src/bflb_sec_sha.c +++ b/drivers/lhal/src/bflb_sec_sha.c @@ -27,14 +27,6 @@ (b)[(i) + 7] = (uint8_t)((n)); \ } -#define SEC_ENG_SHA256 0 -#define SEC_ENG_SHA224 1 -#define SEC_ENG_SHA1 2 -#define SEC_ENG_SHA512 4 -#define SEC_ENG_SHA384 5 -#define SEC_ENG_SHA512T224 6 -#define SEC_ENG_SHA512T256 7 - void bflb_sha_init(struct bflb_device_s *dev, uint8_t mode) { uint32_t regval; @@ -45,18 +37,7 @@ void bflb_sha_init(struct bflb_device_s *dev, uint8_t mode) regval = getreg32(reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET); regval &= ~SEC_ENG_SE_SHA_0_MODE_EXT_MASK; regval &= ~SEC_ENG_SE_SHA_0_MODE_MASK; - - if (mode == SHA_MODE_SHA1) { - regval |= (SEC_ENG_SHA1 << SEC_ENG_SE_SHA_0_MODE_SHIFT); - } else if (mode == SHA_MODE_SHA224) { - regval |= (SEC_ENG_SHA224 << SEC_ENG_SE_SHA_0_MODE_SHIFT); - } else if (mode == SHA_MODE_SHA256) { - regval |= (SEC_ENG_SHA256 << SEC_ENG_SE_SHA_0_MODE_SHIFT); - } else if (mode == SHA_MODE_SHA384) { - regval |= (SEC_ENG_SHA384 << SEC_ENG_SE_SHA_0_MODE_SHIFT); - } else if (mode == SHA_MODE_SHA512) { - regval |= (SEC_ENG_SHA512 << SEC_ENG_SE_SHA_0_MODE_SHIFT); - } + regval |= (mode << SEC_ENG_SE_SHA_0_MODE_SHIFT); putreg32(regval, reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET); } @@ -78,18 +59,7 @@ void bflb_sha1_start(struct bflb_device_s *dev, struct bflb_sha1_ctx_s *ctx) void bflb_sha256_start(struct bflb_device_s *dev, struct bflb_sha256_ctx_s *ctx) { - uint32_t regval; - uint32_t reg_base; - - reg_base = dev->reg_base; - - memset(ctx, 0, sizeof(struct bflb_sha256_ctx_s)); - ctx->sha_padding[0] = 0x80; - - regval = getreg32(reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET); - regval |= SEC_ENG_SE_SHA_0_EN; - regval &= ~SEC_ENG_SE_SHA_0_HASH_SEL; - putreg32(regval, reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET); + return bflb_sha1_start(dev, (struct bflb_sha1_ctx_s *)ctx); } void bflb_sha512_start(struct bflb_device_s *dev, struct bflb_sha512_ctx_s *ctx) @@ -118,16 +88,10 @@ int bflb_sha1_update(struct bflb_device_s *dev, struct bflb_sha1_ctx_s *ctx, con if (len == 0) { return 0; } - if (((uint32_t)input) & 0x1f) { - return -1; - } reg_base = dev->reg_base; regval = getreg32(reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET); - if (regval & SEC_ENG_SE_SHA_0_BUSY) { - return -1; - } if (ctx->sha_feed) { regval |= SEC_ENG_SE_SHA_0_HASH_SEL; @@ -146,7 +110,7 @@ int bflb_sha1_update(struct bflb_device_s *dev, struct bflb_sha1_ctx_s *ctx, con } if (left && len >= fill) { - memcpy((void *)((uint8_t *)ctx->sha_buf + left), input, fill); + arch_memcpy_fast((void *)((uint8_t *)ctx->sha_buf + left), input, fill); putreg32((uint32_t)ctx->sha_buf, reg_base + SEC_ENG_SE_SHA_0_MSA_OFFSET); regval &= ~SEC_ENG_SE_SHA_0_MSG_LEN_MASK; @@ -195,7 +159,7 @@ int bflb_sha1_update(struct bflb_device_s *dev, struct bflb_sha1_ctx_s *ctx, con } /* Copy left data into temp buffer */ - memcpy((void *)((uint8_t *)ctx->sha_buf + left), input, len); + arch_memcpy_fast((void *)((uint8_t *)ctx->sha_buf + left), input, len); } while (getreg32(reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET) & SEC_ENG_SE_SHA_0_BUSY) { @@ -205,98 +169,7 @@ int bflb_sha1_update(struct bflb_device_s *dev, struct bflb_sha1_ctx_s *ctx, con int bflb_sha256_update(struct bflb_device_s *dev, struct bflb_sha256_ctx_s *ctx, const uint8_t *input, uint32_t len) { - uint32_t regval; - uint32_t reg_base; - uint32_t fill; - uint32_t left; - - if (len == 0) { - return 0; - } - - if (((uint32_t)input) & 0x1f) { - return -1; - } - - reg_base = dev->reg_base; - - regval = getreg32(reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET); - if (regval & SEC_ENG_SE_SHA_0_BUSY) { - return -1; - } - - if (ctx->sha_feed) { - regval |= SEC_ENG_SE_SHA_0_HASH_SEL; - } else { - regval &= ~SEC_ENG_SE_SHA_0_HASH_SEL; - } - - left = ctx->total[0] & 0x3F; - fill = 64 - left; - - ctx->total[0] += len; - ctx->total[0] &= 0xFFFFFFFF; - - if (ctx->total[0] < len) { - ctx->total[1]++; - } - - if (left && len >= fill) { - memcpy((void *)((uint8_t *)ctx->sha_buf + left), input, fill); - putreg32((uint32_t)ctx->sha_buf, reg_base + SEC_ENG_SE_SHA_0_MSA_OFFSET); - - regval &= ~SEC_ENG_SE_SHA_0_MSG_LEN_MASK; - regval |= (1 << SEC_ENG_SE_SHA_0_MSG_LEN_SHIFT); - putreg32(regval, reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET); - - regval |= SEC_ENG_SE_SHA_0_TRIG_1T; - putreg32(regval, reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET); - - ctx->sha_feed = 1; - input += fill; - len -= fill; - left = 0; - } - - fill = len / 64; - len = len % 64; - - if (fill > 0) { - while (getreg32(reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET) & SEC_ENG_SE_SHA_0_BUSY) { - } - - /* SHA need set se_sha_sel to 1 to keep the last sha state */ - regval = getreg32(reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET); - if (ctx->sha_feed) { - regval |= SEC_ENG_SE_SHA_0_HASH_SEL; - } else { - regval &= ~SEC_ENG_SE_SHA_0_HASH_SEL; - } - /* Fill data */ - putreg32((uintptr_t)input, reg_base + SEC_ENG_SE_SHA_0_MSA_OFFSET); - - regval &= ~SEC_ENG_SE_SHA_0_MSG_LEN_MASK; - regval |= (fill << SEC_ENG_SE_SHA_0_MSG_LEN_SHIFT); - putreg32(regval, reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET); - - regval |= SEC_ENG_SE_SHA_0_TRIG_1T; - putreg32(regval, reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET); - - input += (fill * 64); - ctx->sha_feed = 1; - } - - if (len > 0) { - while (getreg32(reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET) & SEC_ENG_SE_SHA_0_BUSY) { - } - - /* Copy left data into temp buffer */ - memcpy((void *)((uint8_t *)ctx->sha_buf + left), input, len); - } - - while (getreg32(reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET) & SEC_ENG_SE_SHA_0_BUSY) { - } - return 0; + return bflb_sha1_update(dev, (struct bflb_sha1_ctx_s *)ctx, input, len); } int bflb_sha512_update(struct bflb_device_s *dev, struct bflb_sha512_ctx_s *ctx, const uint8_t *input, uint32_t len) @@ -309,16 +182,10 @@ int bflb_sha512_update(struct bflb_device_s *dev, struct bflb_sha512_ctx_s *ctx, if (len == 0) { return 0; } - if (((uint32_t)input) & 0x1f) { - return -1; - } reg_base = dev->reg_base; regval = getreg32(reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET); - if (regval & SEC_ENG_SE_SHA_0_BUSY) { - return -1; - } if (ctx->sha_feed) { regval |= SEC_ENG_SE_SHA_0_HASH_SEL; @@ -336,7 +203,7 @@ int bflb_sha512_update(struct bflb_device_s *dev, struct bflb_sha512_ctx_s *ctx, } if (left && len >= fill) { - memcpy((void *)((uint8_t *)ctx->sha_buf + left), input, fill); + arch_memcpy_fast((void *)((uint8_t *)ctx->sha_buf + left), input, fill); putreg32((uint32_t)ctx->sha_buf, reg_base + SEC_ENG_SE_SHA_0_MSA_OFFSET); regval &= ~SEC_ENG_SE_SHA_0_MSG_LEN_MASK; @@ -385,7 +252,7 @@ int bflb_sha512_update(struct bflb_device_s *dev, struct bflb_sha512_ctx_s *ctx, } /* Copy left data into temp buffer */ - memcpy((void *)((uint8_t *)ctx->sha_buf + left), input, len); + arch_memcpy_fast((void *)((uint8_t *)ctx->sha_buf + left), input, len); } while (getreg32(reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET) & SEC_ENG_SE_SHA_0_BUSY) { @@ -414,7 +281,7 @@ void bflb_sha1_finish(struct bflb_device_s *dev, struct bflb_sha1_ctx_s *ctx, ui padn = (last < 56) ? (56 - last) : (120 - last); bflb_sha1_update(dev, ctx, (uint8_t *)ctx->sha_padding, padn); - memcpy(ctx->sha_padding, msgLen, 8); + arch_memcpy_fast(ctx->sha_padding, msgLen, 8); bflb_sha1_update(dev, ctx, (uint8_t *)ctx->sha_padding, 8); /* Copy SHA value */ @@ -453,81 +320,7 @@ void bflb_sha1_finish(struct bflb_device_s *dev, struct bflb_sha1_ctx_s *ctx, ui void bflb_sha256_finish(struct bflb_device_s *dev, struct bflb_sha256_ctx_s *ctx, uint8_t *output) { - uint32_t last, padn; - uint32_t high, low; - uint8_t msgLen[8]; - uint8_t mode; - uint32_t regval; - uint32_t reg_base; - uint8_t *p = (uint8_t *)output; - - reg_base = dev->reg_base; - - high = (ctx->total[0] >> 29) | (ctx->total[1] << 3); - low = (ctx->total[0] << 3); - - PUT_UINT32_BE(high, msgLen, 0); - PUT_UINT32_BE(low, msgLen, 4); - - last = ctx->total[0] & 0x3F; - padn = (last < 56) ? (56 - last) : (120 - last); - - bflb_sha256_update(dev, ctx, (uint8_t *)ctx->sha_padding, padn); - memcpy(ctx->sha_padding, msgLen, 8); - bflb_sha256_update(dev, ctx, (uint8_t *)ctx->sha_padding, 8); - - /* Copy SHA value */ - regval = getreg32(reg_base + SEC_ENG_SE_SHA_0_HASH_L_0_OFFSET); - *p++ = (regval & 0xff); - *p++ = ((regval >> 8) & 0xff); - *p++ = ((regval >> 16) & 0xff); - *p++ = ((regval >> 24) & 0xff); - regval = getreg32(reg_base + SEC_ENG_SE_SHA_0_HASH_L_1_OFFSET); - *p++ = (regval & 0xff); - *p++ = ((regval >> 8) & 0xff); - *p++ = ((regval >> 16) & 0xff); - *p++ = ((regval >> 24) & 0xff); - regval = getreg32(reg_base + SEC_ENG_SE_SHA_0_HASH_L_2_OFFSET); - *p++ = (regval & 0xff); - *p++ = ((regval >> 8) & 0xff); - *p++ = ((regval >> 16) & 0xff); - *p++ = ((regval >> 24) & 0xff); - regval = getreg32(reg_base + SEC_ENG_SE_SHA_0_HASH_L_3_OFFSET); - *p++ = (regval & 0xff); - *p++ = ((regval >> 8) & 0xff); - *p++ = ((regval >> 16) & 0xff); - *p++ = ((regval >> 24) & 0xff); - regval = getreg32(reg_base + SEC_ENG_SE_SHA_0_HASH_L_4_OFFSET); - *p++ = (regval & 0xff); - *p++ = ((regval >> 8) & 0xff); - *p++ = ((regval >> 16) & 0xff); - *p++ = ((regval >> 24) & 0xff); - regval = getreg32(reg_base + SEC_ENG_SE_SHA_0_HASH_L_5_OFFSET); - *p++ = (regval & 0xff); - *p++ = ((regval >> 8) & 0xff); - *p++ = ((regval >> 16) & 0xff); - *p++ = ((regval >> 24) & 0xff); - regval = getreg32(reg_base + SEC_ENG_SE_SHA_0_HASH_L_6_OFFSET); - *p++ = (regval & 0xff); - *p++ = ((regval >> 8) & 0xff); - *p++ = ((regval >> 16) & 0xff); - *p++ = ((regval >> 24) & 0xff); - - mode = (getreg32(reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET) & SEC_ENG_SE_SHA_0_MODE_MASK) >> SEC_ENG_SE_SHA_0_MODE_SHIFT; - - if (mode == SEC_ENG_SHA256) { - regval = getreg32(reg_base + SEC_ENG_SE_SHA_0_HASH_L_7_OFFSET); - *p++ = (regval & 0xff); - *p++ = ((regval >> 8) & 0xff); - *p++ = ((regval >> 16) & 0xff); - *p++ = ((regval >> 24) & 0xff); - } - - /* Disable SHA engine*/ - regval = getreg32(reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET); - regval &= ~SEC_ENG_SE_SHA_0_HASH_SEL; - regval &= ~SEC_ENG_SE_SHA_0_EN; - putreg32(regval, reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET); + return bflb_sha1_finish(dev, (struct bflb_sha1_ctx_s *)ctx, output); } void bflb_sha512_finish(struct bflb_device_s *dev, struct bflb_sha512_ctx_s *ctx, uint8_t *output) @@ -552,7 +345,7 @@ void bflb_sha512_finish(struct bflb_device_s *dev, struct bflb_sha512_ctx_s *ctx padn = (last < 112) ? (112 - last) : (240 - last); bflb_sha512_update(dev, ctx, (uint8_t *)ctx->sha_padding, padn); - memcpy(ctx->sha_padding, msgLen, 16); + arch_memcpy_fast(ctx->sha_padding, msgLen, 16); bflb_sha512_update(dev, ctx, (uint8_t *)ctx->sha_padding, 16); /* Copy SHA value */ @@ -594,14 +387,14 @@ void bflb_sha512_finish(struct bflb_device_s *dev, struct bflb_sha512_ctx_s *ctx mode = (getreg32(reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET) & SEC_ENG_SE_SHA_0_MODE_MASK) >> SEC_ENG_SE_SHA_0_MODE_SHIFT; - if ((mode == SEC_ENG_SHA512) || (mode == SEC_ENG_SHA384) || (mode == SEC_ENG_SHA512T256)) { + if ((mode == SHA_MODE_SHA512) || (mode == SHA_MODE_SHA384) || (mode == SHA_MODE_SHA512T256)) { regval = getreg32(reg_base + SEC_ENG_SE_SHA_0_HASH_L_3_OFFSET); *p++ = (regval & 0xff); *p++ = ((regval >> 8) & 0xff); *p++ = ((regval >> 16) & 0xff); *p++ = ((regval >> 24) & 0xff); - if ((mode == SEC_ENG_SHA512) || (mode == SEC_ENG_SHA384)) { + if ((mode == SHA_MODE_SHA512) || (mode == SHA_MODE_SHA384)) { regval = getreg32(reg_base + SEC_ENG_SE_SHA_0_HASH_H_4_OFFSET); *p++ = (regval & 0xff); *p++ = ((regval >> 8) & 0xff); @@ -623,7 +416,7 @@ void bflb_sha512_finish(struct bflb_device_s *dev, struct bflb_sha512_ctx_s *ctx *p++ = ((regval >> 16) & 0xff); *p++ = ((regval >> 24) & 0xff); - if (mode == SEC_ENG_SHA512) { + if (mode == SHA_MODE_SHA512) { regval = getreg32(reg_base + SEC_ENG_SE_SHA_0_HASH_H_6_OFFSET); *p++ = (regval & 0xff); *p++ = ((regval >> 8) & 0xff); @@ -653,4 +446,363 @@ void bflb_sha512_finish(struct bflb_device_s *dev, struct bflb_sha512_ctx_s *ctx regval &= ~SEC_ENG_SE_SHA_0_HASH_SEL; regval &= ~SEC_ENG_SE_SHA_0_EN; putreg32(regval, reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET); -} \ No newline at end of file +} + +void bflb_sha_link_init(struct bflb_device_s *dev) +{ + uint32_t regval; + uint32_t reg_base; + + reg_base = dev->reg_base; + + regval = getreg32(reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET); + regval |= SEC_ENG_SE_SHA_0_EN; + regval |= SEC_ENG_SE_SHA_0_LINK_MODE; + putreg32(regval, reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET); +} + +void bflb_sha_link_deinit(struct bflb_device_s *dev) +{ + uint32_t regval; + uint32_t reg_base; + + reg_base = dev->reg_base; + + regval = getreg32(reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET); + regval &= ~SEC_ENG_SE_SHA_0_EN; + regval &= ~SEC_ENG_SE_SHA_0_LINK_MODE; + putreg32(regval, reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET); +} + +void bflb_sha1_link_start(struct bflb_device_s *dev, struct bflb_sha1_ctx_s *ctx) +{ + memset(ctx, 0, sizeof(struct bflb_sha1_ctx_s)); + ctx->sha_padding[0] = 0x80; +} + +void bflb_sha256_link_start(struct bflb_device_s *dev, struct bflb_sha256_ctx_s *ctx) +{ + return bflb_sha1_link_start(dev, (struct bflb_sha1_ctx_s *)ctx); +} + +void bflb_sha512_link_start(struct bflb_device_s *dev, struct bflb_sha512_ctx_s *ctx) +{ + memset(ctx, 0, sizeof(struct bflb_sha512_ctx_s)); + ctx->sha_padding[0] = 0x80; +} + +int bflb_sha1_link_update(struct bflb_device_s *dev, + struct bflb_sha1_ctx_s *ctx, + uint32_t link_addr, + const uint8_t *input, + uint32_t len) +{ + uint32_t regval; + uint32_t reg_base; + uint32_t fill; + uint32_t left; + + if (len == 0) { + return 0; + } + + reg_base = dev->reg_base; + + /* Set link address */ + putreg32(link_addr, reg_base + SEC_ENG_SE_SHA_0_LINK_OFFSET); + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += len; + ctx->total[0] &= 0xFFFFFFFF; + + if (ctx->total[0] < len) { + ctx->total[1]++; + } + + if (left && len >= fill) { + arch_memcpy_fast((void *)((uint8_t *)ctx->sha_buf + left), input, fill); + /* Set data source address */ + *(uint32_t *)(uintptr_t)(link_addr + 4) = (uint32_t)(uintptr_t)ctx->sha_buf; + + /* Set data length */ + *((uint16_t *)(uintptr_t)link_addr + 1) = 1; + + regval = getreg32(reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET); + regval |= SEC_ENG_SE_SHA_0_TRIG_1T; + putreg32(regval, reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET); + + /* Choose accumulating last hash in the next time */ + *((uint32_t *)(uintptr_t)link_addr) |= 0x40; + input += fill; + len -= fill; + left = 0; + } + + fill = len / 64; + len = len % 64; + + if (fill > 0) { + while (getreg32(reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET) & SEC_ENG_SE_SHA_0_BUSY) { + } + + /* Fill data */ + *(uint32_t *)(uintptr_t)(link_addr + 4) = (uint32_t)(uintptr_t)input; + *((uint16_t *)(uintptr_t)link_addr + 1) = fill; + + regval = getreg32(reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET); + regval |= SEC_ENG_SE_SHA_0_TRIG_1T; + putreg32(regval, reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET); + + input += (fill * 64); + /* Choose accumulating last hash in the next time */ + *((uint32_t *)(uintptr_t)link_addr) |= 0x40; + } + + if (len > 0) { + while (getreg32(reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET) & SEC_ENG_SE_SHA_0_BUSY) { + } + + /* Copy left data into temp buffer */ + arch_memcpy_fast((void *)((uint8_t *)ctx->sha_buf + left), input, len); + } + + while (getreg32(reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET) & SEC_ENG_SE_SHA_0_BUSY) { + } + return 0; +} + +int bflb_sha256_link_update(struct bflb_device_s *dev, + struct bflb_sha256_ctx_s *ctx, + uint32_t link_addr, + const uint8_t *input, + uint32_t len) +{ + return bflb_sha1_link_update(dev, (struct bflb_sha1_ctx_s *)ctx, link_addr, input, len); +} + +int bflb_sha512_link_update(struct bflb_device_s *dev, + struct bflb_sha512_ctx_s *ctx, + uint32_t link_addr, + const uint8_t *input, + uint32_t len) +{ + uint32_t regval; + uint32_t reg_base; + uint32_t fill; + uint32_t left; + + if (len == 0) { + return 0; + } + + reg_base = dev->reg_base; + + /* Set link address */ + putreg32(link_addr, reg_base + SEC_ENG_SE_SHA_0_LINK_OFFSET); + + left = ctx->total[0] & 0x7F; + fill = 128 - left; + + ctx->total[0] += len; + + if (ctx->total[0] < len) { + ctx->total[1]++; + } + + if (left && len >= fill) { + arch_memcpy_fast((void *)((uint8_t *)ctx->sha_buf + left), input, fill); + /* Set data source address */ + *(uint32_t *)(uintptr_t)(link_addr + 4) = (uint32_t)(uintptr_t)ctx->sha_buf; + + /* Set data length */ + *((uint16_t *)(uintptr_t)link_addr + 1) = 1; + + regval = getreg32(reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET); + regval |= SEC_ENG_SE_SHA_0_TRIG_1T; + putreg32(regval, reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET); + + /* Choose accumulating last hash in the next time */ + *((uint32_t *)(uintptr_t)link_addr) |= 0x40; + input += fill; + len -= fill; + left = 0; + } + + fill = len / 128; + len = len % 128; + + if (fill > 0) { + while (getreg32(reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET) & SEC_ENG_SE_SHA_0_BUSY) { + } + + /* Fill data */ + *(uint32_t *)(uintptr_t)(link_addr + 4) = (uint32_t)(uintptr_t)input; + *((uint16_t *)(uintptr_t)link_addr + 1) = fill; + + regval = getreg32(reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET); + regval |= SEC_ENG_SE_SHA_0_TRIG_1T; + putreg32(regval, reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET); + + input += (fill * 128); + /* Choose accumulating last hash in the next time */ + *((uint32_t *)(uintptr_t)link_addr) |= 0x40; + } + + if (len > 0) { + while (getreg32(reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET) & SEC_ENG_SE_SHA_0_BUSY) { + } + + /* Copy left data into temp buffer */ + arch_memcpy_fast((void *)((uint8_t *)ctx->sha_buf + left), input, len); + } + + while (getreg32(reg_base + SEC_ENG_SE_SHA_0_CTRL_OFFSET) & SEC_ENG_SE_SHA_0_BUSY) { + } + return 0; +} + +void bflb_sha1_link_finish(struct bflb_device_s *dev, + struct bflb_sha1_ctx_s *ctx, + uint32_t link_addr, + uint8_t *output) +{ + uint32_t last, padn; + uint32_t high, low; + uint8_t msgLen[8]; + + uint32_t reg_base; + uint32_t sha_mode = (*(uint32_t *)(uintptr_t)link_addr) >> 2 & 0x7; + + reg_base = dev->reg_base; + + /* Set link address */ + putreg32(link_addr, reg_base + SEC_ENG_SE_SHA_0_LINK_OFFSET); + + high = (ctx->total[0] >> 29) | (ctx->total[1] << 3); + low = (ctx->total[0] << 3); + + PUT_UINT32_BE(high, msgLen, 0); + PUT_UINT32_BE(low, msgLen, 4); + + last = ctx->total[0] & 0x3F; + padn = (last < 56) ? (56 - last) : (120 - last); + + bflb_sha1_link_update(dev, ctx, link_addr, (uint8_t *)ctx->sha_padding, padn); + bflb_sha1_link_update(dev, ctx, link_addr, msgLen, 8); + + /* Get result according to SHA mode,result is placed in (link address + offset:8) */ + switch (sha_mode) { + case 0: + arch_memcpy_fast(output, (uint8_t *)(uintptr_t)(link_addr + 8), 32); + break; + + case 1: + arch_memcpy_fast(output, (uint8_t *)(uintptr_t)(link_addr + 8), 28); + break; + + case 2: + arch_memcpy_fast(output, (uint8_t *)(uintptr_t)(link_addr + 8), 20); + break; + + case 3: + arch_memcpy_fast(output, (uint8_t *)(uintptr_t)(link_addr + 8), 20); + break; + + default: + break; + } + + /* Choose new hash in the next time */ + *((uint32_t *)(uintptr_t)link_addr) &= ~0x40; +} + +void bflb_sha256_link_finish(struct bflb_device_s *dev, + struct bflb_sha256_ctx_s *ctx, + uint32_t link_addr, + uint8_t *output) +{ + return bflb_sha1_link_finish(dev, (struct bflb_sha1_ctx_s *)ctx, link_addr, output); +} + +void bflb_sha512_link_finish(struct bflb_device_s *dev, + struct bflb_sha512_ctx_s *ctx, + uint32_t link_addr, + uint8_t *output) +{ + uint32_t last, padn; + uint32_t high, low; + uint8_t msgLen[16]; + + uint32_t reg_base; + uint32_t sha_mode = (*(uint32_t *)(uintptr_t)link_addr) >> 2 & 0x7; + + reg_base = dev->reg_base; + + /* Set link address */ + putreg32(link_addr, reg_base + SEC_ENG_SE_SHA_0_LINK_OFFSET); + + high = (ctx->total[0] >> 61) | (ctx->total[1] << 3); + low = (ctx->total[0] << 3); + + PUT_UINT32_BE(high, msgLen, 0); + PUT_UINT32_BE(low, msgLen, 8); + + last = ctx->total[0] & 0x7F; + padn = (last < 112) ? (112 - last) : (240 - last); + + bflb_sha512_link_update(dev, ctx, link_addr, (uint8_t *)ctx->sha_padding, padn); + bflb_sha512_link_update(dev, ctx, link_addr, msgLen, 16); + + /* Get result according to SHA mode,result is placed in (link address + offset:8) */ + switch (sha_mode) { + case 4: + arch_memcpy_fast(output, (uint8_t *)(uintptr_t)(link_addr + 8), 64); + break; + + case 5: + arch_memcpy_fast(output, (uint8_t *)(uintptr_t)(link_addr + 8), 48); + break; + + case 6: + arch_memcpy_fast(output, (uint8_t *)(uintptr_t)(link_addr + 8), 28); + break; + + case 7: + arch_memcpy_fast(output, (uint8_t *)(uintptr_t)(link_addr + 8), 32); + break; + + default: + break; + } + + /* Choose new hash in the next time */ + *((uint32_t *)(uintptr_t)link_addr) &= ~0x40; +} + +void bflb_group0_request_sha_access(struct bflb_device_s *dev) +{ + uint32_t regval; + uint32_t reg_base; + + reg_base = dev->reg_base; + + regval = getreg32(reg_base + SEC_ENG_SE_CTRL_PROT_RD_OFFSET); + if ((regval & 0x03) == 0x03) { + putreg32(0x02, reg_base + SEC_ENG_SE_SHA_0_CTRL_PROT_OFFSET); + + regval = getreg32(reg_base + SEC_ENG_SE_CTRL_PROT_RD_OFFSET); + if ((regval & 0x03) == 0x01) { + } + } +} + +void bflb_group0_release_sha_access(struct bflb_device_s *dev) +{ + uint32_t reg_base; + + reg_base = dev->reg_base; + + putreg32(0x06, reg_base + SEC_ENG_SE_SHA_0_CTRL_PROT_OFFSET); +} diff --git a/drivers/lhal/src/bflb_sec_trng.c b/drivers/lhal/src/bflb_sec_trng.c index 111ca326..eec914aa 100644 --- a/drivers/lhal/src/bflb_sec_trng.c +++ b/drivers/lhal/src/bflb_sec_trng.c @@ -9,7 +9,7 @@ p[3] = (val >> 24) & 0xff; \ } -void bflb_trng_read(struct bflb_device_s *dev, uint8_t data[32]) +int bflb_trng_read(struct bflb_device_s *dev, uint8_t data[32]) { uint32_t regval; uint32_t reg_base; @@ -90,4 +90,74 @@ void bflb_trng_read(struct bflb_device_s *dev, uint8_t data[32]) regval = getreg32(reg_base + SEC_ENG_SE_TRNG_0_CTRL_0_OFFSET); regval |= SEC_ENG_SE_TRNG_0_INT_CLR_1T; putreg32(regval, reg_base + SEC_ENG_SE_TRNG_0_CTRL_0_OFFSET); + + return 0; +} + +int bflb_trng_readlen(uint8_t *data, uint32_t len) +{ + struct bflb_device_s *trng; + + uint8_t tmp_buf[32]; + uint32_t readlen = 0; + uint32_t i = 0, cnt = 0; + + trng = bflb_device_get_by_name("trng"); + + while (readlen < len) { + if (bflb_trng_read(trng, tmp_buf) != 0) { + return -ETIMEDOUT; + } + + cnt = len - readlen; + + if (cnt > sizeof(tmp_buf)) { + cnt = sizeof(tmp_buf); + } + + for (i = 0; i < cnt; i++) { + data[readlen + i] = tmp_buf[i]; + } + + readlen += cnt; + } + + return 0; +} + +long random(void) +{ + uint32_t data[8]; + struct bflb_device_s *trng; + + trng = bflb_device_get_by_name("trng"); + bflb_trng_read(trng, (uint8_t *)data); + + return data[0]; +} + +void bflb_group0_request_trng_access(struct bflb_device_s *dev) +{ + uint32_t regval; + uint32_t reg_base; + + reg_base = dev->reg_base; + + regval = getreg32(reg_base + SEC_ENG_SE_CTRL_PROT_RD_OFFSET); + if (((regval >> 4) & 0x03) == 0x03) { + putreg32(0x04, reg_base + SEC_ENG_SE_TRNG_0_CTRL_PROT_OFFSET); + + regval = getreg32(reg_base + SEC_ENG_SE_CTRL_PROT_RD_OFFSET); + if (((regval >> 4) & 0x03) == 0x01) { + } + } +} + +void bflb_group0_release_trng_access(struct bflb_device_s *dev) +{ + uint32_t reg_base; + + reg_base = dev->reg_base; + + putreg32(0x06, reg_base + SEC_ENG_SE_TRNG_0_CTRL_PROT_OFFSET); } \ No newline at end of file diff --git a/drivers/lhal/src/bflb_spi.c b/drivers/lhal/src/bflb_spi.c index d8a15014..45da67f5 100644 --- a/drivers/lhal/src/bflb_spi.c +++ b/drivers/lhal/src/bflb_spi.c @@ -472,7 +472,7 @@ void bflb_spi_int_clear(struct bflb_device_s *dev, uint32_t int_clear) putreg32(regval, reg_base + SPI_INT_STS_OFFSET); } -int bflb_spi_isbusy(struct bflb_device_s *dev) +bool bflb_spi_isbusy(struct bflb_device_s *dev) { uint32_t reg_base; uint32_t regval; @@ -483,21 +483,21 @@ int bflb_spi_isbusy(struct bflb_device_s *dev) regval = getreg32(reg_base + SPI_FIFO_CONFIG_1_OFFSET); #if (SPI_FIFO_WIDTH_VARIABLE_SUPPORT) if ((regval & SPI_TX_FIFO_CNT_MASK) >> SPI_TX_FIFO_CNT_SHIFT < SPI_FIFO_BYTE_NUM_MAX) { - return 1; + return true; } #else if ((regval & SPI_TX_FIFO_CNT_MASK) >> SPI_TX_FIFO_CNT_SHIFT < SPI_FIFO_WORD_NUM_MAX) { - return 1; + return true; } #endif /* check busy bit */ regval = getreg32(reg_base + SPI_BUS_BUSY_OFFSET); if (regval) { - return 1; + return true; } - return 0; + return false; } int bflb_spi_feature_control(struct bflb_device_s *dev, int cmd, size_t arg) @@ -556,7 +556,7 @@ int bflb_spi_feature_control(struct bflb_device_s *dev, int cmd, size_t arg) break; default: - ret = -1; + ret = -EPERM; break; } diff --git a/drivers/lhal/src/bflb_timer.c b/drivers/lhal/src/bflb_timer.c index 15c3f7ce..c72e0a3b 100644 --- a/drivers/lhal/src/bflb_timer.c +++ b/drivers/lhal/src/bflb_timer.c @@ -5,7 +5,6 @@ void bflb_timer_init(struct bflb_device_s *dev, const struct bflb_timer_config_s { uint32_t regval; uint32_t reg_base; - uint8_t clk_source = 3; reg_base = dev->reg_base; @@ -14,24 +13,19 @@ void bflb_timer_init(struct bflb_device_s *dev, const struct bflb_timer_config_s regval &= ~(1 << (dev->idx + 1)); putreg32(regval, reg_base + TIMER_TCER_OFFSET); - /* Configure clock source */ - if (config->clock_source == BFLB_SYSTEM_CPU_CLK) { - clk_source = 0; - } else if (config->clock_source == BFLB_SYSTEM_XCLK) { - clk_source = 3; - } else if (config->clock_source == BFLB_SYSTEM_32K_CLK) { - clk_source = 1; - } else if (config->clock_source == BFLB_SYSTEM_1K_CLK) { - clk_source = 2; - } + /* Timer interrupr clear */ + bflb_timer_compint_clear(dev, TIMER_COMP_ID_0); + bflb_timer_compint_clear(dev, TIMER_COMP_ID_1); + bflb_timer_compint_clear(dev, TIMER_COMP_ID_2); + /* Configure clock source */ regval = getreg32(reg_base + TIMER_TCCR_OFFSET); if (dev->idx == 0) { regval &= ~TIMER_CS_0_MASK; - regval |= (clk_source << TIMER_CS_0_SHIFT); + regval |= (config->clock_source << TIMER_CS_0_SHIFT); } else { regval &= ~TIMER_CS_1_MASK; - regval |= (clk_source << TIMER_CS_1_SHIFT); + regval |= (config->clock_source << TIMER_CS_1_SHIFT); } putreg32(regval, reg_base + TIMER_TCCR_OFFSET); @@ -76,16 +70,28 @@ void bflb_timer_init(struct bflb_device_s *dev, const struct bflb_timer_config_s bflb_timer_set_compvalue(dev, TIMER_COMP_ID_0, config->comp0_val - 2); bflb_timer_set_compvalue(dev, TIMER_COMP_ID_1, config->comp1_val - 2); bflb_timer_set_compvalue(dev, TIMER_COMP_ID_2, 0xffffffff); - } else { + } else if (config->trigger_comp_id < TIMER_COMP_NONE) { bflb_timer_compint_mask(dev, TIMER_COMP_ID_0, false); bflb_timer_compint_mask(dev, TIMER_COMP_ID_1, false); bflb_timer_compint_mask(dev, TIMER_COMP_ID_2, false); bflb_timer_set_compvalue(dev, TIMER_COMP_ID_0, config->comp0_val - 2); bflb_timer_set_compvalue(dev, TIMER_COMP_ID_1, config->comp1_val - 2); bflb_timer_set_compvalue(dev, TIMER_COMP_ID_2, config->comp2_val - 2); + } else { + bflb_timer_compint_mask(dev, TIMER_COMP_ID_0, true); + bflb_timer_compint_mask(dev, TIMER_COMP_ID_1, true); + bflb_timer_compint_mask(dev, TIMER_COMP_ID_2, true); + bflb_timer_set_compvalue(dev, TIMER_COMP_ID_0, 0xffffffff); + bflb_timer_set_compvalue(dev, TIMER_COMP_ID_1, 0xffffffff); + bflb_timer_set_compvalue(dev, TIMER_COMP_ID_2, 0xffffffff); } } +void bflb_timer_deinit(struct bflb_device_s *dev) +{ + +} + void bflb_timer_start(struct bflb_device_s *dev) { uint32_t regval; @@ -185,4 +191,22 @@ void bflb_timer_compint_clear(struct bflb_device_s *dev, uint8_t cmp_no) regval = getreg32(reg_base + TIMER_TICR0_OFFSET + 4 * dev->idx); regval |= (1 << cmp_no); putreg32(regval, reg_base + TIMER_TICR0_OFFSET + 4 * dev->idx); -} \ No newline at end of file +} + +#if !defined(BL702) || !defined(BL602) +void bflb_timer_capture_init(struct bflb_device_s *dev, const struct bflb_timer_capture_config_s *config) +{ + uint32_t regval; + uint32_t reg_base; + + reg_base = dev->reg_base; + regval = getreg32(reg_base + TIMER_GPIO_OFFSET); + /* polarity: 1->neg, 0->pos */ + if (config->polarity == TIMER_CAPTURE_POLARITY_FALLING) { + regval |= (1 << (5 + dev->idx)); + } else { + regval &= ~(1 << (5 + dev->idx)); + } + putreg32(regval, reg_base + TIMER_GPIO_OFFSET); +} +#endif diff --git a/drivers/lhal/src/bflb_uart.c b/drivers/lhal/src/bflb_uart.c index 23e2ec92..b27ef3e7 100644 --- a/drivers/lhal/src/bflb_uart.c +++ b/drivers/lhal/src/bflb_uart.c @@ -72,25 +72,14 @@ void bflb_uart_init(struct bflb_device_s *dev, const struct bflb_uart_config_s * putreg32(tx_cfg, reg_base + UART_UTX_CONFIG_OFFSET); putreg32(rx_cfg, reg_base + UART_URX_CONFIG_OFFSET); #if defined(BL602) - if (config->flow_ctrl & UART_FLOWCTRL_RTS) { - regval = getreg32(reg_base + UART_URX_CONFIG_OFFSET); - regval |= UART_CR_URX_RTS_SW_MODE; - putreg32(regval, reg_base + UART_URX_CONFIG_OFFSET); - } else { - regval = getreg32(reg_base + UART_URX_CONFIG_OFFSET); - regval &= ~UART_CR_URX_RTS_SW_MODE; - putreg32(regval, reg_base + UART_URX_CONFIG_OFFSET); - } + regval = getreg32(reg_base + UART_URX_CONFIG_OFFSET); + regval &= ~UART_CR_URX_RTS_SW_MODE; + putreg32(regval, reg_base + UART_URX_CONFIG_OFFSET); + #else - if (config->flow_ctrl & UART_FLOWCTRL_RTS) { - regval = getreg32(reg_base + UART_SW_MODE_OFFSET); - regval |= UART_CR_URX_RTS_SW_MODE; - putreg32(regval, reg_base + UART_SW_MODE_OFFSET); - } else { - regval = getreg32(reg_base + UART_SW_MODE_OFFSET); - regval &= ~UART_CR_URX_RTS_SW_MODE; - putreg32(regval, reg_base + UART_SW_MODE_OFFSET); - } + regval = getreg32(reg_base + UART_SW_MODE_OFFSET); + regval &= ~UART_CR_URX_RTS_SW_MODE; + putreg32(regval, reg_base + UART_SW_MODE_OFFSET); #endif regval = getreg32(reg_base + UART_DATA_CONFIG_OFFSET); regval &= ~UART_CR_UART_BIT_INV; @@ -113,8 +102,12 @@ void bflb_uart_init(struct bflb_device_s *dev, const struct bflb_uart_config_s * regval = getreg32(reg_base + UART_FIFO_CONFIG_0_OFFSET); regval |= UART_TX_FIFO_CLR; regval |= UART_RX_FIFO_CLR; + regval &= ~UART_DMA_TX_EN; + regval &= ~UART_DMA_RX_EN; putreg32(regval, reg_base + UART_FIFO_CONFIG_0_OFFSET); + putreg32(0xFFFFFFFF, reg_base + UART_INT_MASK_OFFSET); + /* Enable UART tx rx unit */ tx_cfg = getreg32(reg_base + UART_UTX_CONFIG_OFFSET); rx_cfg = getreg32(reg_base + UART_URX_CONFIG_OFFSET); @@ -139,6 +132,36 @@ void bflb_uart_deinit(struct bflb_device_s *dev) putreg32(rx_cfg, reg_base + UART_URX_CONFIG_OFFSET); } +void bflb_uart_enable(struct bflb_device_s *dev) +{ + uint32_t reg_base; + uint32_t tx_cfg; + uint32_t rx_cfg; + + reg_base = dev->reg_base; + tx_cfg = getreg32(reg_base + UART_UTX_CONFIG_OFFSET); + rx_cfg = getreg32(reg_base + UART_URX_CONFIG_OFFSET); + tx_cfg |= UART_CR_UTX_EN; + rx_cfg |= UART_CR_URX_EN; + putreg32(tx_cfg, reg_base + UART_UTX_CONFIG_OFFSET); + putreg32(rx_cfg, reg_base + UART_URX_CONFIG_OFFSET); +} + +void bflb_uart_disable(struct bflb_device_s *dev) +{ + uint32_t reg_base; + uint32_t tx_cfg; + uint32_t rx_cfg; + + reg_base = dev->reg_base; + tx_cfg = getreg32(reg_base + UART_UTX_CONFIG_OFFSET); + rx_cfg = getreg32(reg_base + UART_URX_CONFIG_OFFSET); + tx_cfg &= ~UART_CR_UTX_EN; + rx_cfg &= ~UART_CR_URX_EN; + putreg32(tx_cfg, reg_base + UART_UTX_CONFIG_OFFSET); + putreg32(rx_cfg, reg_base + UART_URX_CONFIG_OFFSET); +} + void bflb_uart_link_txdma(struct bflb_device_s *dev, bool enable) { uint32_t reg_base; @@ -192,6 +215,28 @@ int bflb_uart_getchar(struct bflb_device_s *dev) return ch; } +void bflb_uart_put(struct bflb_device_s *dev, uint8_t *data, uint32_t len) +{ + for (uint32_t i = 0; i < len; i++) { + bflb_uart_putchar(dev, data[i]); + } +} + +int bflb_uart_get(struct bflb_device_s *dev, uint8_t *data, uint32_t len) +{ + int ch = -1; + uint32_t count = 0; + + while (count < len) { + if ((ch = bflb_uart_getchar(dev)) < 0) { + break; + } + data[count] = ch; + count++; + } + return count; +} + bool bflb_uart_txready(struct bflb_device_s *dev) { uint32_t reg_base; @@ -301,8 +346,9 @@ void bflb_uart_int_clear(struct bflb_device_s *dev, uint32_t int_clear) putreg32(int_clear, reg_base + UART_INT_CLEAR_OFFSET); } -void bflb_uart_feature_control(struct bflb_device_s *dev, int cmd, size_t arg) +int bflb_uart_feature_control(struct bflb_device_s *dev, int cmd, size_t arg) { + int ret = 0; uint32_t reg_base; uint32_t tmp; uint32_t tx_tmp; @@ -401,13 +447,11 @@ void bflb_uart_feature_control(struct bflb_device_s *dev, int cmd, size_t arg) case UART_CMD_GET_TX_FIFO_CNT: /* Get tx fifo count */ - *(uint32_t *)arg = getreg32(reg_base + UART_FIFO_CONFIG_1_OFFSET) & UART_TX_FIFO_CNT_MASK; - break; + return (getreg32(reg_base + UART_FIFO_CONFIG_1_OFFSET) & UART_TX_FIFO_CNT_MASK) >> UART_TX_FIFO_CNT_SHIFT; case UART_CMD_GET_RX_FIFO_CNT: /* Get rx fifo count */ - *(uint32_t *)arg = (getreg32(reg_base + UART_FIFO_CONFIG_1_OFFSET) & UART_RX_FIFO_CNT_MASK) >> UART_RX_FIFO_CNT_SHIFT; - break; + return (getreg32(reg_base + UART_FIFO_CONFIG_1_OFFSET) & UART_RX_FIFO_CNT_MASK) >> UART_RX_FIFO_CNT_SHIFT; case UART_CMD_SET_AUTO_BAUD: /* Set auto baudrate detection */ @@ -432,12 +476,11 @@ void bflb_uart_feature_control(struct bflb_device_s *dev, int cmd, size_t arg) case UART_CMD_GET_AUTO_BAUD: /* Get auto baudrate detection count value */ tmp = getreg32(reg_base + UART_STS_URX_ABR_PRD_OFFSET); - if (*(uint32_t *)arg == UART_AUTO_BAUD_START) { - *((uint32_t *)arg + 1) = tmp & UART_STS_URX_ABR_PRD_START_MASK; + if (arg == UART_AUTO_BAUD_START) { + return (tmp & UART_STS_URX_ABR_PRD_START_MASK); } else { - *((uint32_t *)arg + 1) = (tmp & UART_STS_URX_ABR_PRD_0X55_MASK) >> UART_STS_URX_ABR_PRD_0X55_SHIFT; + return ((tmp & UART_STS_URX_ABR_PRD_0X55_MASK) >> UART_STS_URX_ABR_PRD_0X55_SHIFT); } - break; #if !defined(BL602) case UART_CMD_SET_BREAK_VALUE: /* Set lin mode break value */ @@ -498,7 +541,7 @@ void bflb_uart_feature_control(struct bflb_device_s *dev, int cmd, size_t arg) putreg32(tx_tmp, reg_base + UART_UTX_RS485_CFG_OFFSET); break; - case UART_CMD_SET_TX_RS485_POL: + case UART_CMD_SET_TX_RS485_POLARITY: /* Set tx rs485 de pin polarity */ tx_tmp = getreg32(reg_base + UART_UTX_RS485_CFG_OFFSET); tx_tmp &= ~UART_CR_UTX_RS485_POL; @@ -510,7 +553,7 @@ void bflb_uart_feature_control(struct bflb_device_s *dev, int cmd, size_t arg) putreg32(tx_tmp, reg_base + UART_UTX_RS485_CFG_OFFSET); break; - case UART_CMD_SET_ABR_PW_VALUE: + case UART_CMD_SET_ABR_ALLOWABLE_ERROR: /* Set auto baudrate detection mode pulse-width tolerance value for codeword 0x55 */ rx_tmp = getreg32(reg_base + UART_URX_ABR_PW_TOL_OFFSET); rx_tmp &= ~UART_CR_URX_ABR_PW_TOL_MASK; @@ -519,7 +562,33 @@ void bflb_uart_feature_control(struct bflb_device_s *dev, int cmd, size_t arg) putreg32(rx_tmp, reg_base + UART_URX_ABR_PW_TOL_OFFSET); break; #endif + case UART_CMD_SET_SW_RTS_CONTROL: +#if defined(BL602) + if (arg) { + rx_tmp = getreg32(reg_base + UART_URX_CONFIG_OFFSET); + rx_tmp |= UART_CR_URX_RTS_SW_MODE; + putreg32(rx_tmp, reg_base + UART_URX_CONFIG_OFFSET); + } else { + rx_tmp = getreg32(reg_base + UART_URX_CONFIG_OFFSET); + rx_tmp &= ~UART_CR_URX_RTS_SW_MODE; + putreg32(rx_tmp, reg_base + UART_URX_CONFIG_OFFSET); + } +#else + if (arg) { + rx_tmp = getreg32(reg_base + UART_SW_MODE_OFFSET); + rx_tmp |= UART_CR_URX_RTS_SW_MODE; + putreg32(rx_tmp, reg_base + UART_SW_MODE_OFFSET); + + } else { + rx_tmp = getreg32(reg_base + UART_SW_MODE_OFFSET); + rx_tmp &= ~UART_CR_URX_RTS_SW_MODE; + putreg32(rx_tmp, reg_base + UART_SW_MODE_OFFSET); + } +#endif + break; default: + ret = -EPERM; break; } + return ret; } diff --git a/drivers/lhal/src/bflb_usb_v2.c b/drivers/lhal/src/bflb_usb_v2.c index c12d83c2..7b2e4824 100644 --- a/drivers/lhal/src/bflb_usb_v2.c +++ b/drivers/lhal/src/bflb_usb_v2.c @@ -1,10 +1,11 @@ #include "bflb_core.h" -#include "bflb_mtimer.h" #include "bflb_irq.h" #include "usbd_core.h" #include "usbh_core.h" #include "hardware/usb_v2_reg.h" +// #define CONFIG_USB_PINGPONG_ENABLE + #define BLFB_USB_BASE ((uint32_t)0x20072000) #define BFLB_PDS_BASE ((uint32_t)0x2000e000) @@ -673,6 +674,22 @@ int usbd_ep_open(const struct usbd_endpoint_cfg *ep_cfg) #else if (ep_cfg->ep_mps > 512) { bflb_usb_set_ep_fifomap(1, USB_FIFO_F0); + + bflb_usb_set_fifo_epmap(USB_FIFO_F0, 1, USB_FIFO_DIR_BID); + bflb_usb_set_fifo_epmap(USB_FIFO_F1, 1, USB_FIFO_DIR_BID); + bflb_usb_set_fifo_epmap(USB_FIFO_F2, 1, USB_FIFO_DIR_BID); + bflb_usb_set_fifo_epmap(USB_FIFO_F3, 1, USB_FIFO_DIR_BID); + + if (ep_idx == 1) { + bflb_usb_fifo_config(USB_FIFO_F0, ep_cfg->ep_type, 1024, 2, true); + bflb_usb_fifo_config(USB_FIFO_F1, ep_cfg->ep_type, 1024, 2, false); + bflb_usb_fifo_config(USB_FIFO_F2, ep_cfg->ep_type, 1024, 2, false); + bflb_usb_fifo_config(USB_FIFO_F3, ep_cfg->ep_type, 1024, 2, false); + } else { + return -1; + } + } else { + bflb_usb_set_ep_fifomap(1, USB_FIFO_F0); bflb_usb_set_ep_fifomap(2, USB_FIFO_F2); bflb_usb_set_fifo_epmap(USB_FIFO_F0, 1, USB_FIFO_DIR_BID); @@ -689,22 +706,6 @@ int usbd_ep_open(const struct usbd_endpoint_cfg *ep_cfg) } else { return -1; } - } else { - bflb_usb_set_ep_fifomap(1, USB_FIFO_F0); - - bflb_usb_set_fifo_epmap(USB_FIFO_F0, 1, USB_FIFO_DIR_BID); - bflb_usb_set_fifo_epmap(USB_FIFO_F1, 1, USB_FIFO_DIR_BID); - bflb_usb_set_fifo_epmap(USB_FIFO_F2, 1, USB_FIFO_DIR_BID); - bflb_usb_set_fifo_epmap(USB_FIFO_F3, 1, USB_FIFO_DIR_BID); - - if (ep_idx == 1) { - bflb_usb_fifo_config(USB_FIFO_F0, ep_cfg->ep_type, 1024, 2, true); - bflb_usb_fifo_config(USB_FIFO_F1, ep_cfg->ep_type, 1024, 2, false); - bflb_usb_fifo_config(USB_FIFO_F2, ep_cfg->ep_type, 1024, 2, false); - bflb_usb_fifo_config(USB_FIFO_F3, ep_cfg->ep_type, 1024, 2, false); - } else { - return -1; - } } #endif regval = getreg32(BLFB_USB_BASE + USB_DEV_ADR_OFFSET); diff --git a/drivers/lhal/src/bflb_wdg.c b/drivers/lhal/src/bflb_wdg.c index 9c887ec8..da1bbd93 100644 --- a/drivers/lhal/src/bflb_wdg.c +++ b/drivers/lhal/src/bflb_wdg.c @@ -6,7 +6,6 @@ void bflb_wdg_init(struct bflb_device_s *dev, const struct bflb_wdg_config_s *co { uint32_t regval; uint32_t reg_base; - uint8_t clk_source; reg_base = dev->reg_base; @@ -23,19 +22,9 @@ void bflb_wdg_init(struct bflb_device_s *dev, const struct bflb_wdg_config_s *co putreg32(regval, reg_base + TIMER_WMER_OFFSET); /* Configure clock source */ - if (config->clock_source == BFLB_SYSTEM_CPU_CLK) { - clk_source = 0; - } else if (config->clock_source == BFLB_SYSTEM_XCLK) { - clk_source = 3; - } else if (config->clock_source == BFLB_SYSTEM_32K_CLK) { - clk_source = 1; - } else { - clk_source = 2; - } - regval = getreg32(reg_base + TIMER_TCCR_OFFSET); regval &= ~TIMER_CS_WDT_MASK; - regval |= (clk_source << TIMER_CS_WDT_SHIFT); + regval |= (config->clock_source << TIMER_CS_WDT_SHIFT); putreg32(regval, reg_base + TIMER_TCCR_OFFSET); /* Configure clock div */ diff --git a/drivers/lhal/src/pka/libpka.a b/drivers/lhal/src/pka/libpka.a new file mode 100644 index 0000000000000000000000000000000000000000..82fee0e8fe9db614da802d5a50dd34482f2cfa78 GIT binary patch literal 586636 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

S0OAgkBNb{t>rKEWBjVPbE^&<0?W%CkL{Y*1Y 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

dr1k8g-;%`CjD@?p4-@^Ls*E&miO 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 b274E{zJt727vU}DI_bAEAGypw-e>p=YK^qY literal 0 HcmV?d00001 diff --git a/examples/peripherals/timer/CMakeLists.txt b/examples/peripherals/cks/cks_dma/CMakeLists.txt similarity index 89% rename from examples/peripherals/timer/CMakeLists.txt rename to examples/peripherals/cks/cks_dma/CMakeLists.txt index 86cfea3b..d69e7970 100644 --- a/examples/peripherals/timer/CMakeLists.txt +++ b/examples/peripherals/cks/cks_dma/CMakeLists.txt @@ -6,4 +6,4 @@ find_package(bouffalo_sdk REQUIRED HINTS $ENV{BL_SDK_BASE}) sdk_set_main_file(main.c) -project(timer) +project(cks_dma) diff --git a/examples/peripherals/cks/cks_dma/Makefile b/examples/peripherals/cks/cks_dma/Makefile new file mode 100644 index 00000000..93f8cb7b --- /dev/null +++ b/examples/peripherals/cks/cks_dma/Makefile @@ -0,0 +1,13 @@ +SDK_DEMO_PATH ?= . +BL_SDK_BASE ?= $(SDK_DEMO_PATH)/../../../.. + +export BL_SDK_BASE + +CHIP ?= bl628 +BOARD ?= bl628dk +CROSS_COMPILE ?= riscv64-unknown-elf- + +# add custom cmake definition +#cmake_definition+=-Dxxx=sss + +include $(BL_SDK_BASE)/project.build diff --git a/examples/peripherals/cks/cks_dma/main.c b/examples/peripherals/cks/cks_dma/main.c new file mode 100644 index 00000000..bfdcc211 --- /dev/null +++ b/examples/peripherals/cks/cks_dma/main.c @@ -0,0 +1,152 @@ +#include "board.h" +#include "bflb_cks.h" +#include "bflb_dma.h" +#include "bflb_mtimer.h" +#include "bl628_memorymap.h" +#include "bflb_core.h" + +#define DATA_LEN 1024 + +static volatile uint8_t dma_tc_flag0 = 0; +struct bflb_device_s *cks; +struct bflb_device_s *dma0_ch0; + +void dma0_ch0_isr(void *arg) +{ + dma_tc_flag0++; + printf("tc done\r\n"); +} + +uint16_t sw_chksum(uint8_t *data, uint32_t len) { + uint32_t sum = 0; + uint16_t chksum = 0; + uint32_t size = len; + + if (len % 2 == 1) { + size=len-1; + sum += data[size]; + } + + for (uint32_t i = 0; i < size; i = i + 2) { + sum += ((uint32_t)data[i]); + sum += ((uint32_t)data[i + 1] << 8); + } + + while (sum >> 16) { + sum = (sum >> 16) + (sum & 0x0000FFFF); + } + + chksum = (uint16_t)sum; + return ~chksum; +} + +uint16_t get_cks_with_dma(uint8_t* data,uint32_t length) +{ + uint16_t checksum = 0; + + struct bflb_dma_channel_lli_pool_s lli[20]; /* max trasnfer size 4064 * 20 */ + struct bflb_dma_channel_lli_transfer_s transfers[1]; + + transfers[0].src_addr = (uint32_t)data; + transfers[0].dst_addr = (uint32_t)(CKS_BASE+0x4); + transfers[0].nbytes = length; + + bflb_dma_channel_lli_reload(dma0_ch0, lli, 20, transfers, 1); + bflb_dma_channel_start(dma0_ch0); + + while(dma_tc_flag0 == 0) { + } + dma_tc_flag0 = 0; + + checksum = bflb_cks_compute(cks, data, 0); + + return checksum; +} + +static void test_case1(void){ + uint16_t dma_cks = 0; + uint16_t hw_cks = 0; + uint16_t sw_cks = 0; + uint32_t time = 0, i; + struct bflb_dma_channel_config_s config; + + static uint32_t data_src1[DATA_LEN/4]; + + for(i = 0;i < DATA_LEN; i++){ + ((uint8_t *)data_src1)[i] = i&0xff; + } + + time = (unsigned int)bflb_mtimer_get_time_us(); + + sw_cks = sw_chksum((uint8_t *)data_src1, sizeof(data_src1)); + + printf("software checksum time=%ldus\r\n", (unsigned int)bflb_mtimer_get_time_us() - time); + + printf("sw_cks is %04x\r\n", sw_cks); + + bflb_cks_reset(cks); + bflb_cks_set_endian(cks, CKS_BIG_ENDIAN); + + time = (unsigned int)bflb_mtimer_get_time_us(); + + hw_cks = bflb_cks_compute(cks, (uint8_t *)data_src1, sizeof(data_src1)); + + printf("hardware checksum time=%ldus\r\n", (unsigned int)bflb_mtimer_get_time_us() - time); + + printf("hw_cks is %04x\r\n", hw_cks); + + bflb_cks_reset(cks); + bflb_cks_set_endian(cks, CKS_BIG_ENDIAN); + + printf("\r\ndma case 1:\n"); + + config.direction = DMA_MEMORY_TO_MEMORY; + config.src_req = 0; + config.dst_req = 0; + config.src_addr_inc = DMA_ADDR_INCREMENT_ENABLE; + config.dst_addr_inc = DMA_ADDR_INCREMENT_DISABLE; + config.src_burst_count = DMA_BURST_INCR1; + config.dst_burst_count = DMA_BURST_INCR1; + config.src_width = DMA_DATA_WIDTH_8BIT; + config.dst_width = DMA_DATA_WIDTH_8BIT; + bflb_dma_channel_init(dma0_ch0, &config); + bflb_dma_channel_irq_attach(dma0_ch0, dma0_ch0_isr, NULL); + + time = (unsigned int)bflb_mtimer_get_time_us(); + + dma_cks = get_cks_with_dma((uint8_t *)data_src1, sizeof(data_src1)); + printf("dma checksum time=%ldus\r\n", (unsigned int)bflb_mtimer_get_time_us() - time); + printf("dma_cks is %04x\r\n", dma_cks); + + bflb_cks_reset(cks); + bflb_cks_set_endian(cks, CKS_BIG_ENDIAN); + + printf("\r\ndma case 2:\n"); + config.src_width = DMA_DATA_WIDTH_32BIT; + config.src_burst_count = DMA_BURST_INCR4; + config.dst_width = DMA_DATA_WIDTH_8BIT; + config.dst_burst_count = DMA_BURST_INCR16; + time = (unsigned int)bflb_mtimer_get_time_us(); + + dma_cks = get_cks_with_dma((uint8_t *)data_src1, sizeof(data_src1)); + printf("dma checksum time=%ldus\r\n", (unsigned int)bflb_mtimer_get_time_us() - time); + printf("dma_cks is %04x\r\n", dma_cks); +} + +/* main */ +int main(void) +{ + board_init(); + + printf("CKS dma case:\r\n"); + + cks = bflb_device_get_by_name("cks"); + dma0_ch0 = bflb_device_get_by_name("dma0_ch0"); + + test_case1(); + + printf("\r\nend\r\n"); + + while (1) { + } +} diff --git a/examples/peripherals/timer/proj.conf b/examples/peripherals/cks/cks_dma/proj.conf similarity index 100% rename from examples/peripherals/timer/proj.conf rename to examples/peripherals/cks/cks_dma/proj.conf diff --git a/examples/peripherals/cks/cks_normal/CMakeLists.txt b/examples/peripherals/cks/cks_normal/CMakeLists.txt new file mode 100644 index 00000000..0007ba88 --- /dev/null +++ b/examples/peripherals/cks/cks_normal/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.15) + +include(proj.conf) + +find_package(bouffalo_sdk REQUIRED HINTS $ENV{BL_SDK_BASE}) + +sdk_set_main_file(main.c) + +project(cks_normal) diff --git a/examples/peripherals/cks/cks_normal/Makefile b/examples/peripherals/cks/cks_normal/Makefile new file mode 100644 index 00000000..93f8cb7b --- /dev/null +++ b/examples/peripherals/cks/cks_normal/Makefile @@ -0,0 +1,13 @@ +SDK_DEMO_PATH ?= . +BL_SDK_BASE ?= $(SDK_DEMO_PATH)/../../../.. + +export BL_SDK_BASE + +CHIP ?= bl628 +BOARD ?= bl628dk +CROSS_COMPILE ?= riscv64-unknown-elf- + +# add custom cmake definition +#cmake_definition+=-Dxxx=sss + +include $(BL_SDK_BASE)/project.build diff --git a/examples/peripherals/cks/cks_normal/main.c b/examples/peripherals/cks/cks_normal/main.c new file mode 100644 index 00000000..709fd4d3 --- /dev/null +++ b/examples/peripherals/cks/cks_normal/main.c @@ -0,0 +1,260 @@ +#include "board.h" +#include "bflb_cks.h" +#include "bflb_mtimer.h" +#include "bflb_core.h" + +#define USER_UNUSED(a) ((void)(a)) + +struct bflb_device_s *cks; + +static void test_case1(struct bflb_device_s *dev) { + /*case from wiki: https://en.wikipedia.org/wiki/IPv4_header_checksum*/ + static const uint8_t data_src1[] = {0x45, 0x00, 0x00, 0x73, 0x00, 0x00, 0x40, + 0x00, 0x40, 0x11, 0x00, 0x00, 0xc0, 0xa8, + 0x00, 0x01, 0xc0, 0xa8, 0x00, 0xc7}; + static const uint8_t data_src1_cks[] = {0xB8, 0x61}; + uint16_t cks; + USER_UNUSED(cks); + USER_UNUSED(data_src1_cks); + + bflb_cks_reset(dev); + bflb_cks_set_endian(dev, CKS_LITTLE_ENDIAN); + cks = bflb_cks_compute(dev, (uint8_t *)data_src1, sizeof(data_src1)); + + if (cks != (data_src1_cks[0] << 8 | data_src1_cks[1])) { + printf("Error! CKS result with LE is %04x, should be %02x%02x\r\n", cks, data_src1_cks[1], data_src1_cks[0]); + } else { + printf("Pass\r\n"); + } + + bflb_cks_reset(dev); + bflb_cks_set_endian(dev, CKS_BIG_ENDIAN); + cks = bflb_cks_compute(dev, (uint8_t *)data_src1, sizeof(data_src1)); + + if (cks != (data_src1_cks[1] << 8 | data_src1_cks[0])) { + printf("Error! CKS result with BE is %04x, should be %02x%02x\r\n", cks, data_src1_cks[1], data_src1_cks[0]); + } else { + printf("Pass\r\n"); + } +} + +static void test_case2(struct bflb_device_s *dev) { + uint16_t data_segment_one = 0x3F1F; + int i; + uint32_t checksum; + uint16_t cks; + uint8_t data; + + bflb_cks_reset(dev); + bflb_cks_set_endian(dev, CKS_LITTLE_ENDIAN); + checksum = 0; + for (i = 0; i < 1; i++) { + checksum += data_segment_one; + data = data_segment_one & 0xff; + cks = bflb_cks_compute(dev, &data, 1); + data = data_segment_one >> 8 & 0xff; + cks = bflb_cks_compute(dev, &data, 1); + } + while (checksum >> 16) { + checksum = (checksum >> 16) + (checksum & 0xFFFF); + } + + printf("CKS LE result is %04x, %04x\r\n", cks, (uint16_t)~checksum); + + bflb_cks_reset(dev); + bflb_cks_set_endian(dev, CKS_BIG_ENDIAN); + checksum = 0; + for (i = 0; i < 1; i++) { + checksum += data_segment_one; + data = data_segment_one & 0xff; + cks = bflb_cks_compute(dev, &data, 1); + data = data_segment_one >> 8 & 0xff; + cks = bflb_cks_compute(dev, &data, 1); + } + while (checksum >> 16) { + checksum = (checksum >> 16) + (checksum & 0xFFFF); + } + + printf("CKS BE result is %04x, %04x\r\n", cks, (uint16_t)~checksum); + if (cks == ((uint16_t)~checksum)) { + printf("====== Success %04X Checksum=====\r\n", cks); + } else { + printf("====== Failed %04X Checksum======\r\n", cks); + } +} + +static void test_case3(struct bflb_device_s *dev) { + uint16_t data_segment_one = 0x3F1F; + int i; + uint32_t checksum; + uint16_t cks; + uint8_t data; + + bflb_cks_reset(dev); + bflb_cks_set_endian(dev, CKS_LITTLE_ENDIAN); + checksum = 0; + for (i = 0; i < 1000; i++) { + checksum += data_segment_one; + data = data_segment_one & 0xff; + cks = bflb_cks_compute(dev, &data, 1); + data = data_segment_one >> 8 & 0xff; + cks = bflb_cks_compute(dev, &data, 1); + } + while (checksum >> 16) { + checksum = (checksum >> 16) + (checksum & 0xFFFF); + } + + printf("CKS LE result is %04x, %04x\r\n", cks, (uint16_t)~checksum); + + bflb_cks_reset(dev); + bflb_cks_set_endian(dev, CKS_BIG_ENDIAN); + checksum = 0; + for (i = 0; i < 1000; i++) { + checksum += data_segment_one; + data = data_segment_one & 0xff; + cks = bflb_cks_compute(dev, &data, 1); + data = data_segment_one >> 8 & 0xff; + cks = bflb_cks_compute(dev, &data, 1); + } + while (checksum >> 16) { + checksum = (checksum >> 16) + (checksum & 0xFFFF); + } + + printf("CKS BE result is %04x, %04x\r\n", cks, (uint16_t)~checksum); + if (cks == ((uint16_t)~checksum)) { + printf("====== Success %04X Checksum=====\r\n", cks); + } else { + printf("====== Failed %04X Checksum======\r\n", cks); + } +} + +static void test_case4(struct bflb_device_s *dev) { + uint16_t data_segment_one = 0x3F1F; + uint8_t data_segment_two = 0xa1; + int i; + uint32_t checksum; + uint16_t cks; + uint8_t data; + + bflb_cks_reset(dev); + bflb_cks_set_endian(dev, CKS_LITTLE_ENDIAN); + checksum = 0; + for (i = 0; i < 1; i++) { + checksum += data_segment_one; + data = data_segment_one & 0xff; + cks = bflb_cks_compute(dev, &data, 1); + data = data_segment_one >> 8 & 0xff; + cks = bflb_cks_compute(dev, &data, 1); + } + checksum += data_segment_two; + while (checksum >> 16) { + checksum = (checksum >> 16) + (checksum & 0xFFFF); + } + cks = bflb_cks_compute(dev, &data_segment_two, 1); + + printf("CKS LE result is %04x, %04x\r\n", cks, (uint16_t)~checksum); + + bflb_cks_reset(dev); + bflb_cks_set_endian(dev, CKS_BIG_ENDIAN); + checksum = 0; + for (i = 0; i < 1; i++) { + checksum += data_segment_one; + data = data_segment_one & 0xff; + cks = bflb_cks_compute(dev, &data, 1); + data = data_segment_one >> 8 & 0xff; + cks = bflb_cks_compute(dev, &data, 1); + } + checksum += data_segment_two; + while (checksum >> 16) { + checksum = (checksum >> 16) + (checksum & 0xFFFF); + } + cks = bflb_cks_compute(dev, &data_segment_two, 1); + + printf("CKS BE result is %04x, %04x\r\n", cks, (uint16_t)~checksum); + if (cks == ((uint16_t)~checksum)) { + printf("====== Success %04X Checksum=====\r\n", cks); + } else { + printf("====== Failed %04X Checksum======\r\n", cks); + } +} + +uint16_t sw_chksum(uint8_t *data, uint32_t len) { + uint32_t sum = 0; + uint16_t chksum = 0; + uint32_t size = len; + + if (len % 2 == 1) { + size=len-1; + sum += data[size]; + } + + for (uint32_t i = 0; i < size; i = i + 2) { + sum += ((uint32_t)data[i]); + sum += ((uint32_t)data[i + 1] << 8); + } + + while (sum >> 16) { + sum = (sum >> 16) + (sum & 0x0000FFFF); + } + + chksum = (uint16_t)sum; + return ~chksum; +} + +static void test_case5(struct bflb_device_s *dev) { + uint16_t sw_cks = 0; + uint16_t hw_cks = 0; + uint32_t time = 0; + + static const uint8_t data_src1[] = {0x45, 0x00, 0x00, 0x73, 0x00, 0x00, 0x40, + 0x00, 0x40, 0x11, 0x00, 0x00, 0xc0, 0xa8, + 0x00, 0x01, 0xc0, 0xa8, 0x00, 0xc7}; + time = (unsigned int)bflb_mtimer_get_time_us(); + + sw_cks = sw_chksum((uint8_t *)data_src1, sizeof(data_src1)); + + printf("software checksum time=%ldus\r\n", (unsigned int)bflb_mtimer_get_time_us() - time); + + printf("sw_cks is %04x\r\n", sw_cks); + + bflb_cks_reset(dev); + bflb_cks_set_endian(dev, CKS_BIG_ENDIAN); + + time = (unsigned int)bflb_mtimer_get_time_us(); + + hw_cks = bflb_cks_compute(dev, (uint8_t *)data_src1, sizeof(data_src1)); + + printf("hardware checksum time=%ldus\r\n", (unsigned int)bflb_mtimer_get_time_us() - time); + + printf("hw_cks is %04x\r\n", hw_cks); + + if (sw_cks != hw_cks) { + printf("Error!\r\n"); + } +} + +/* main */ +int main(void) +{ + board_init(); + + printf("CKS normal case:\r\n"); + + cks = bflb_device_get_by_name("cks"); + + printf("\r\n--->>> case1 test\r\n"); + test_case1(cks); + printf("\r\n--->>> case2 test\r\n"); + test_case2(cks); + printf("\r\n--->>> case3 test\r\n"); + test_case3(cks); + printf("\r\n--->>> case4 test\r\n"); + test_case4(cks); + printf("\r\n--->>> case5 test\r\n"); + test_case5(cks); + + printf("\r\nend\r\n"); + + while (1) { + } +} diff --git a/examples/peripherals/cks/cks_normal/proj.conf b/examples/peripherals/cks/cks_normal/proj.conf new file mode 100644 index 00000000..13320d67 --- /dev/null +++ b/examples/peripherals/cks/cks_normal/proj.conf @@ -0,0 +1 @@ +#set(CONFIG_XXX 1) \ No newline at end of file diff --git a/examples/peripherals/i2c/i2c_10_bit/CMakeLists.txt b/examples/peripherals/i2c/i2c_10_bit/CMakeLists.txt new file mode 100644 index 00000000..4c90c624 --- /dev/null +++ b/examples/peripherals/i2c/i2c_10_bit/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.15) + +include(proj.conf) + +find_package(bouffalo_sdk REQUIRED HINTS $ENV{BL_SDK_BASE}) + +sdk_set_main_file(main.c) + +project(i2c_10_bit) diff --git a/examples/peripherals/timer/Makefile b/examples/peripherals/i2c/i2c_10_bit/Makefile similarity index 82% rename from examples/peripherals/timer/Makefile rename to examples/peripherals/i2c/i2c_10_bit/Makefile index 9b01b7fe..44367c02 100644 --- a/examples/peripherals/timer/Makefile +++ b/examples/peripherals/i2c/i2c_10_bit/Makefile @@ -1,5 +1,5 @@ SDK_DEMO_PATH ?= . -BL_SDK_BASE ?= $(SDK_DEMO_PATH)/../../.. +BL_SDK_BASE ?= $(SDK_DEMO_PATH)/../../../.. export BL_SDK_BASE diff --git a/examples/peripherals/i2c/i2c_10_bit/main.c b/examples/peripherals/i2c/i2c_10_bit/main.c new file mode 100644 index 00000000..1872c352 --- /dev/null +++ b/examples/peripherals/i2c/i2c_10_bit/main.c @@ -0,0 +1,49 @@ +#include "bflb_mtimer.h" +#include "bflb_i2c.h" +#include "board.h" + +#define I2C_10BIT_SLAVE_ADDR 0x355 +#define I2C_10BIT_TRANSFER_LENGTH 32 + +static struct bflb_device_s *i2c0; + +int main(void) +{ + struct bflb_i2c_msg_s msgs[2]; + uint8_t subaddr[2] = { 0x00, 0x04}; + uint8_t write_data[I2C_10BIT_TRANSFER_LENGTH]; + + board_init(); + board_i2c0_gpio_init(); + + i2c0 = bflb_device_get_by_name("i2c0"); + + bflb_i2c_init(i2c0, 400000); + + /* Write buffer init */ + write_data[0] = 0x55; + write_data[1] = 0x11; + write_data[2] = 0x22; + for (size_t i = 3; i < I2C_10BIT_TRANSFER_LENGTH; i++) { + write_data[i] = i; + } + + /* Write data */ + msgs[0].addr = I2C_10BIT_SLAVE_ADDR; + msgs[0].flags = I2C_M_NOSTOP | I2C_M_TEN; + msgs[0].buffer = subaddr; + msgs[0].length = 2; + + msgs[1].addr = I2C_10BIT_SLAVE_ADDR; + msgs[1].flags = 0; + msgs[1].buffer = write_data; + msgs[1].length = I2C_10BIT_TRANSFER_LENGTH; + + bflb_i2c_transfer(i2c0, msgs, 2); + printf("write over, check slave and wave\r\n"); + + printf("end\r\n"); + + while(1){ + } +} diff --git a/examples/peripherals/i2c/i2c_10_bit/proj.conf b/examples/peripherals/i2c/i2c_10_bit/proj.conf new file mode 100644 index 00000000..13320d67 --- /dev/null +++ b/examples/peripherals/i2c/i2c_10_bit/proj.conf @@ -0,0 +1 @@ +#set(CONFIG_XXX 1) \ No newline at end of file diff --git a/examples/peripherals/i2c/i2c_eeprom/main.c b/examples/peripherals/i2c/i2c_eeprom/main.c index f822376b..25c3a06b 100644 --- a/examples/peripherals/i2c/i2c_eeprom/main.c +++ b/examples/peripherals/i2c/i2c_eeprom/main.c @@ -2,25 +2,32 @@ #include "bflb_i2c.h" #include "board.h" +#define EEPROM_TRANSFER_LENGTH 32 +#define EEPROM_SELECT_PAGE0 (0 << 5) + +static struct bflb_device_s *i2c0; + int main(void) { + struct bflb_i2c_msg_s msgs[2]; + uint8_t subaddr[2] = { 0x00, EEPROM_SELECT_PAGE0}; + uint8_t write_data[256]; + uint8_t read_data[256]; + board_init(); board_i2c0_gpio_init(); - struct bflb_device_s *i2c0; i2c0 = bflb_device_get_by_name("i2c0"); bflb_i2c_init(i2c0, 400000); - struct bflb_i2c_msg_s msgs[2]; - uint8_t subaddr[2] = { 0x00, 0x00 }; - uint8_t write_data[8]; - uint8_t read_data[8]; - - for (size_t i = 0; i < 8; i++) { + /* Write and read buffer init */ + for (size_t i = 0; i < 256; i++) { write_data[i] = i; + read_data[i] = 0; } + /* Write page 0 */ msgs[0].addr = 0x50; msgs[0].flags = I2C_M_NOSTOP; msgs[0].buffer = subaddr; @@ -29,27 +36,30 @@ int main(void) msgs[1].addr = 0x50; msgs[1].flags = 0; msgs[1].buffer = write_data; - msgs[1].length = 8; + msgs[1].length = EEPROM_TRANSFER_LENGTH; bflb_i2c_transfer(i2c0, msgs, 2); printf("write over\r\n"); - bflb_mtimer_delay_ms(200); + bflb_mtimer_delay_ms(100); + /* Read page 0 */ msgs[1].addr = 0x50; msgs[1].flags = I2C_M_READ; msgs[1].buffer = read_data; - msgs[1].length = 8; + msgs[1].length = EEPROM_TRANSFER_LENGTH; bflb_i2c_transfer(i2c0, msgs, 2); printf("read over\r\n"); - for (uint8_t i = 0; i < 8; i++) { + bflb_mtimer_delay_ms(100); + + /* Check read data */ + for (uint8_t i = 0; i < EEPROM_TRANSFER_LENGTH; i++) { if (write_data[i] != read_data[i]) { - printf("check fail\r\n"); - while (1) { - } + printf("check fail, %d write: %02x, read: %02x\r\n", i, write_data[i], read_data[i]); } } - while (1) { - printf("helloworld\r\n"); - bflb_mtimer_delay_ms(2000); + printf("check over\r\n"); + printf("end\r\n"); + + while(1){ } } diff --git a/examples/peripherals/i2c/i2c_eeprom_dma/CMakeLists.txt b/examples/peripherals/i2c/i2c_eeprom_dma/CMakeLists.txt new file mode 100644 index 00000000..7226f71f --- /dev/null +++ b/examples/peripherals/i2c/i2c_eeprom_dma/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.15) + +include(proj.conf) + +find_package(bouffalo_sdk REQUIRED HINTS $ENV{BL_SDK_BASE}) + +sdk_set_main_file(main.c) + +project(i2c_eeprom_dma) diff --git a/examples/peripherals/i2c/i2c_eeprom_dma/Makefile b/examples/peripherals/i2c/i2c_eeprom_dma/Makefile new file mode 100644 index 00000000..44367c02 --- /dev/null +++ b/examples/peripherals/i2c/i2c_eeprom_dma/Makefile @@ -0,0 +1,13 @@ +SDK_DEMO_PATH ?= . +BL_SDK_BASE ?= $(SDK_DEMO_PATH)/../../../.. + +export BL_SDK_BASE + +CHIP ?= bl616 +BOARD ?= bl616dk +CROSS_COMPILE ?= riscv64-unknown-elf- + +# add custom cmake definition +#cmake_definition+=-Dxxx=sss + +include $(BL_SDK_BASE)/project.build diff --git a/examples/peripherals/i2c/i2c_eeprom_dma/main.c b/examples/peripherals/i2c/i2c_eeprom_dma/main.c new file mode 100644 index 00000000..0a1ee6f0 --- /dev/null +++ b/examples/peripherals/i2c/i2c_eeprom_dma/main.c @@ -0,0 +1,150 @@ +#include "bflb_mtimer.h" +#include "bflb_i2c.h" +#include "bflb_dma.h" +#include "board.h" + +#define EEPROM_TRANSFER_LENGTH 32 +#define EEPROM_SELECT_PAGE0 (0 << 5) + +struct bflb_device_s *i2c0; +struct bflb_device_s *dma0_ch0; +struct bflb_device_s *dma0_ch1; + +static ATTR_NOCACHE_RAM_SECTION uint32_t send_buffer[8]; +static ATTR_NOCACHE_RAM_SECTION uint32_t receive_buffer[8]; +static volatile uint32_t dma_tc_flag0 = 0; +static volatile uint32_t dma_tc_flag1 = 0; + +void dma0_ch0_isr(void *arg) +{ + dma_tc_flag0++; + printf("Send done\r\n"); +} + +void dma0_ch1_isr(void *arg) +{ + dma_tc_flag1++; + printf("Receive done\r\n"); +} + +int main(void) +{ + struct bflb_i2c_msg_s msgs[2]; + uint8_t subaddr[2] = { 0x00, EEPROM_SELECT_PAGE0}; + + board_init(); + board_i2c0_gpio_init(); + + /* Send and receive buffer init */ + for (size_t i = 0; i < 32; i++) { + ((uint8_t *)send_buffer)[i] = i; + ((uint8_t *)receive_buffer)[i] = 0; + } + + i2c0 = bflb_device_get_by_name("i2c0"); + + bflb_i2c_init(i2c0, 400000); + bflb_i2c_link_txdma(i2c0, true); + bflb_i2c_link_rxdma(i2c0, true); + + /* Write page 0 */ + dma0_ch0 = bflb_device_get_by_name("dma0_ch0"); + + struct bflb_dma_channel_config_s tx_config; + + tx_config.direction = DMA_MEMORY_TO_PERIPH; + tx_config.src_req = DMA_REQUEST_NONE; + tx_config.dst_req = DMA_REQUEST_I2C0_TX; + tx_config.src_addr_inc = DMA_ADDR_INCREMENT_ENABLE; + tx_config.dst_addr_inc = DMA_ADDR_INCREMENT_DISABLE; + tx_config.src_burst_count = DMA_BURST_INCR1; + tx_config.dst_burst_count = DMA_BURST_INCR1; + tx_config.src_width = DMA_DATA_WIDTH_32BIT; + tx_config.dst_width = DMA_DATA_WIDTH_32BIT; + bflb_dma_channel_init(dma0_ch0, &tx_config); + + bflb_dma_channel_irq_attach(dma0_ch0, dma0_ch0_isr, NULL); + + struct bflb_dma_channel_lli_pool_s tx_llipool[20]; /* max trasnfer size 4064 * 20 */ + struct bflb_dma_channel_lli_transfer_s tx_transfers[1]; + tx_transfers[0].src_addr = (uint32_t)send_buffer; + tx_transfers[0].dst_addr = (uint32_t)DMA_ADDR_I2C0_TDR; + tx_transfers[0].nbytes = 32; + bflb_dma_channel_lli_reload(dma0_ch0, tx_llipool, 20, tx_transfers, 1); + + msgs[0].addr = 0x50; + msgs[0].flags = I2C_M_NOSTOP; + msgs[0].buffer = subaddr; + msgs[0].length = 2; + + msgs[1].addr = 0x50; + msgs[1].flags = I2C_M_DMA; + msgs[1].buffer = NULL; + msgs[1].length = 32; + bflb_i2c_transfer(i2c0, msgs, 2); + + bflb_dma_channel_start(dma0_ch0); + + while (dma_tc_flag0 == 0) { + } + while ((bflb_i2c_get_intstatus(i2c0) & I2C_INT_END) == 0) { + } + bflb_i2c_deinit(i2c0); + + printf("write over\r\n"); + bflb_mtimer_delay_ms(100); + + /* Read page 0 */ + dma0_ch1 = bflb_device_get_by_name("dma0_ch1"); + + struct bflb_dma_channel_config_s rx_config; + + rx_config.direction = DMA_PERIPH_TO_MEMORY; + rx_config.src_req = DMA_REQUEST_I2C0_RX; + rx_config.dst_req = DMA_REQUEST_NONE; + rx_config.src_addr_inc = DMA_ADDR_INCREMENT_DISABLE; + rx_config.dst_addr_inc = DMA_ADDR_INCREMENT_ENABLE; + rx_config.src_burst_count = DMA_BURST_INCR1; + rx_config.dst_burst_count = DMA_BURST_INCR1; + rx_config.src_width = DMA_DATA_WIDTH_32BIT; + rx_config.dst_width = DMA_DATA_WIDTH_32BIT; + bflb_dma_channel_init(dma0_ch1, &rx_config); + + bflb_dma_channel_irq_attach(dma0_ch1, dma0_ch1_isr, NULL); + + struct bflb_dma_channel_lli_pool_s rx_llipool[20]; + struct bflb_dma_channel_lli_transfer_s rx_transfers[1]; + rx_transfers[0].src_addr = (uint32_t)DMA_ADDR_I2C0_RDR; + rx_transfers[0].dst_addr = (uint32_t)receive_buffer; + rx_transfers[0].nbytes = 32; + + bflb_dma_channel_lli_reload(dma0_ch1, rx_llipool, 20, rx_transfers, 1); + + msgs[1].addr = 0x50; + msgs[1].flags = I2C_M_DMA | I2C_M_READ; + msgs[1].buffer = NULL; + msgs[1].length = 32; + bflb_i2c_transfer(i2c0, msgs, 2); + + bflb_dma_channel_start(dma0_ch1); + + while (dma_tc_flag1 == 0) { + } + while ((bflb_i2c_get_intstatus(i2c0) & I2C_INT_END) == 0) { + } + bflb_i2c_deinit(i2c0); + + printf("read over\r\n"); + + /* Check read data */ + for (uint8_t i = 0; i < 32; i++) { + if (((uint8_t *)send_buffer)[i] != ((uint8_t *)receive_buffer)[i]) { + printf("check fail, %d write: %02x, read: %02x\r\n", i, ((uint8_t *)send_buffer)[i], ((uint8_t *)receive_buffer)[i]); + } + } + printf("check over\r\n"); + printf("end\r\n"); + + while(1){ + } +} diff --git a/examples/peripherals/i2c/i2c_eeprom_dma/proj.conf b/examples/peripherals/i2c/i2c_eeprom_dma/proj.conf new file mode 100644 index 00000000..13320d67 --- /dev/null +++ b/examples/peripherals/i2c/i2c_eeprom_dma/proj.conf @@ -0,0 +1 @@ +#set(CONFIG_XXX 1) \ No newline at end of file diff --git a/examples/peripherals/i2c/i2c_eeprom_interrupt/CMakeLists.txt b/examples/peripherals/i2c/i2c_eeprom_interrupt/CMakeLists.txt new file mode 100644 index 00000000..34520e1f --- /dev/null +++ b/examples/peripherals/i2c/i2c_eeprom_interrupt/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.15) + +include(proj.conf) + +find_package(bouffalo_sdk REQUIRED HINTS $ENV{BL_SDK_BASE}) + +sdk_set_main_file(main.c) + +project(i2c_eeprom_interrupt) diff --git a/examples/peripherals/i2c/i2c_eeprom_interrupt/Makefile b/examples/peripherals/i2c/i2c_eeprom_interrupt/Makefile new file mode 100644 index 00000000..44367c02 --- /dev/null +++ b/examples/peripherals/i2c/i2c_eeprom_interrupt/Makefile @@ -0,0 +1,13 @@ +SDK_DEMO_PATH ?= . +BL_SDK_BASE ?= $(SDK_DEMO_PATH)/../../../.. + +export BL_SDK_BASE + +CHIP ?= bl616 +BOARD ?= bl616dk +CROSS_COMPILE ?= riscv64-unknown-elf- + +# add custom cmake definition +#cmake_definition+=-Dxxx=sss + +include $(BL_SDK_BASE)/project.build diff --git a/examples/peripherals/i2c/i2c_eeprom_interrupt/main.c b/examples/peripherals/i2c/i2c_eeprom_interrupt/main.c new file mode 100644 index 00000000..aefad4bb --- /dev/null +++ b/examples/peripherals/i2c/i2c_eeprom_interrupt/main.c @@ -0,0 +1,132 @@ +#include "bflb_mtimer.h" +#include "bflb_i2c.h" +#include "board.h" + +#define EEPROM_TRANSFER_LENGTH 32 +#define EEPROM_SELECT_PAGE0 (0 << 5) +#define EEPROM_SELECT_PAGE1 (1 << 5) + +static struct bflb_device_s *i2c0; + +void i2c_isr(int irq, void *arg) +{ + uint32_t status; + + status = bflb_i2c_get_intstatus(i2c0); + + if (status & I2C_INTSTS_END) { + bflb_i2c_int_mask(i2c0, I2C_INT_END, true); + printf("Transfer end interrupt\r\n"); + } + if (status & I2C_INTSTS_NACK) { + bflb_i2c_int_mask(i2c0, I2C_INT_NACK, true); + printf("Error! NACK interrupt\r\n"); + } + if (status & I2C_INTSTS_ARB) { + bflb_i2c_int_mask(i2c0, I2C_INT_ARB, true); + printf("Error! Arbitration lost interrupt\r\n"); + } + if (status & I2C_INTSTS_FER) { + bflb_i2c_int_mask(i2c0, I2C_INT_FER, true); + printf("Error! TX/RX FIFO error interrupt\r\n"); + } +} + +int main(void) +{ + board_init(); + board_i2c0_gpio_init(); + + i2c0 = bflb_device_get_by_name("i2c0"); + + bflb_i2c_init(i2c0, 400000); + + /* Set i2c interrupt */ + bflb_i2c_int_mask(i2c0, I2C_INT_END | I2C_INT_NACK | I2C_INT_ARB | I2C_INT_FER, false); + bflb_irq_attach(i2c0->irq_num, i2c_isr, i2c0); + bflb_irq_enable(i2c0->irq_num); + + struct bflb_i2c_msg_s msgs[2]; + uint8_t subaddr[2] = { 0x00, 0x00 }; + + uint8_t write_data[256]; + uint8_t read_data[256]; + + /* Write and read buffer init */ + for (size_t i = 0; i < 256; i++) { + write_data[i] = i; + read_data[i] = 0; + } + + /* Write page 0 */ + subaddr[1] = EEPROM_SELECT_PAGE0; + + msgs[0].addr = 0x50; + msgs[0].flags = I2C_M_NOSTOP; + msgs[0].buffer = subaddr; + msgs[0].length = 2; + + msgs[1].addr = 0x50; + msgs[1].flags = 0; + msgs[1].buffer = write_data; + msgs[1].length = EEPROM_TRANSFER_LENGTH; + + bflb_i2c_transfer(i2c0, msgs, 2); + printf("write over\r\n\r\n"); + bflb_mtimer_delay_ms(100); + + /* Unmask interrupt */ + bflb_i2c_int_mask(i2c0, I2C_INT_END | I2C_INT_NACK | I2C_INT_ARB | I2C_INT_FER, false); + + /* Write page 1 */ + subaddr[1] = EEPROM_SELECT_PAGE1; + + msgs[1].addr = 0x50; + msgs[1].flags = 0; + msgs[1].buffer = write_data + EEPROM_TRANSFER_LENGTH; + msgs[1].length = EEPROM_TRANSFER_LENGTH; + + bflb_i2c_transfer(i2c0, msgs, 2); + printf("write over\r\n\r\n"); + bflb_mtimer_delay_ms(100); + + /* Unmask interrupt */ + bflb_i2c_int_mask(i2c0, I2C_INT_END | I2C_INT_NACK | I2C_INT_ARB | I2C_INT_FER, false); + + /* Read page 0 */ + subaddr[1] = EEPROM_SELECT_PAGE0; + + msgs[1].addr = 0x50; + msgs[1].flags = I2C_M_READ; + msgs[1].buffer = read_data; + msgs[1].length = EEPROM_TRANSFER_LENGTH; + bflb_i2c_transfer(i2c0, msgs, 2); + printf("read over\r\n\r\n"); + bflb_mtimer_delay_ms(100); + + /* Unmask interrupt */ + bflb_i2c_int_mask(i2c0, I2C_INT_END | I2C_INT_NACK | I2C_INT_ARB | I2C_INT_FER, false); + + /* Read page 1 */ + subaddr[1] = EEPROM_SELECT_PAGE1; + + msgs[1].addr = 0x50; + msgs[1].flags = I2C_M_READ; + msgs[1].buffer = read_data + EEPROM_TRANSFER_LENGTH; + msgs[1].length = EEPROM_TRANSFER_LENGTH; + bflb_i2c_transfer(i2c0, msgs, 2); + printf("read over\r\n\r\n"); + bflb_mtimer_delay_ms(100); + + /* Check read data */ + for (uint8_t i = 0; i < 2 * EEPROM_TRANSFER_LENGTH; i++) { + if (write_data[i] != read_data[i]) { + printf("check fail, %d write: %02x, read: %02x\r\n", i, write_data[i], read_data[i]); + } + } + printf("check over\r\n"); + printf("end\r\n"); + + while (1) { + } +} diff --git a/examples/peripherals/i2c/i2c_eeprom_interrupt/proj.conf b/examples/peripherals/i2c/i2c_eeprom_interrupt/proj.conf new file mode 100644 index 00000000..13320d67 --- /dev/null +++ b/examples/peripherals/i2c/i2c_eeprom_interrupt/proj.conf @@ -0,0 +1 @@ +#set(CONFIG_XXX 1) \ No newline at end of file diff --git a/examples/peripherals/sec_eng/sec_eng_aes_link_sw_key/CMakeLists.txt b/examples/peripherals/sec_eng/sec_eng_aes_link_sw_key/CMakeLists.txt new file mode 100644 index 00000000..339b24ca --- /dev/null +++ b/examples/peripherals/sec_eng/sec_eng_aes_link_sw_key/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.15) + +include(proj.conf) + +find_package(bouffalo_sdk REQUIRED HINTS $ENV{BL_SDK_BASE}) + +sdk_set_main_file(main.c) + +project(sec_eng_aes_link_sw_key) diff --git a/examples/peripherals/sec_eng/sec_eng_aes_link_sw_key/Makefile b/examples/peripherals/sec_eng/sec_eng_aes_link_sw_key/Makefile new file mode 100644 index 00000000..44367c02 --- /dev/null +++ b/examples/peripherals/sec_eng/sec_eng_aes_link_sw_key/Makefile @@ -0,0 +1,13 @@ +SDK_DEMO_PATH ?= . +BL_SDK_BASE ?= $(SDK_DEMO_PATH)/../../../.. + +export BL_SDK_BASE + +CHIP ?= bl616 +BOARD ?= bl616dk +CROSS_COMPILE ?= riscv64-unknown-elf- + +# add custom cmake definition +#cmake_definition+=-Dxxx=sss + +include $(BL_SDK_BASE)/project.build diff --git a/examples/peripherals/sec_eng/sec_eng_aes_link_sw_key/main.c b/examples/peripherals/sec_eng/sec_eng_aes_link_sw_key/main.c new file mode 100644 index 00000000..dfcc44c3 --- /dev/null +++ b/examples/peripherals/sec_eng/sec_eng_aes_link_sw_key/main.c @@ -0,0 +1,365 @@ +#include "bflb_mtimer.h" +#include "bflb_sec_aes.h" +#include "board.h" + +const uint8_t aes_ecb_128bit_pt[16] = { + 0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, + 0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34 +}; + +const uint8_t aes_ecb_128bit_ct[16] = { + 0x39, 0x25, 0x84, 0x1d, 0x02, 0xDc, 0x09, 0xfb, + 0xdc, 0x11, 0x85, 0x97, 0x19, 0x6a, 0x0b, 0x32 +}; + +const uint8_t aes_cbc_128bit_pt[48] = { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff +}; + +const uint8_t aes_cbc_128bit_ct[48] = { + 0x76, 0x49, 0xab, 0xac, 0x81, 0x19, 0xb2, 0x46, + 0xce, 0xe9, 0x8e, 0x9b, 0x12, 0xe9, 0x19, 0x7d, + 0x50, 0x86, 0xcb, 0x9b, 0x50, 0x72, 0x19, 0xee, + 0x95, 0xdb, 0x11, 0x3a, 0x91, 0x76, 0x78, 0xb2, + 0x7f, 0xee, 0xdb, 0x79, 0xc5, 0x87, 0x1f, 0x16, + 0x59, 0xd4, 0x60, 0xa6, 0x76, 0xd1, 0xc0, 0x18 +}; + +const uint8_t aes_ctr_128bit_pt[16] = { + 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, + 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A +}; + +const uint8_t aes_ctr_128bit_ct[16] = { + 0x87, 0x4D, 0x61, 0x91, 0xB6, 0x20, 0xE3, 0x26, + 0x1B, 0xEF, 0x68, 0x64, 0x99, 0x0D, 0xB6, 0xCE +}; + +const uint8_t aes_xts_128bit_pt[64] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +const uint8_t aes_xts_128bit_ct[64] = { + 0x91, 0x7c, 0xf6, 0x9e, 0xbd, 0x68, 0xb2, 0xec, 0x9b, 0x9f, 0xe9, 0xa3, 0xea, 0xdd, 0xa6, 0x92, + 0xcd, 0x43, 0xd2, 0xf5, 0x95, 0x98, 0xed, 0x85, 0x8c, 0x02, 0xc2, 0x65, 0x2f, 0xbf, 0x92, 0x2e, + 0xc4, 0xcf, 0xc5, 0xa3, 0x8b, 0x75, 0x84, 0x30, 0xd5, 0x16, 0x51, 0x18, 0x7f, 0x65, 0xbb, 0xe6, + 0x16, 0x6b, 0xc3, 0x60, 0xd7, 0xbb, 0x56, 0xe9, 0xbb, 0xe4, 0x54, 0x10, 0x72, 0x2e, 0x46, 0x75 +}; + +const uint8_t aes_xts_192bit_pt[64] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +const uint8_t aes_xts_192bit_ct[64] = { + 0x82, 0xba, 0x63, 0x7a, 0xd6, 0xfb, 0x48, 0xe1, 0x5c, 0xc2, 0x3e, 0x8e, 0x36, 0xf9, 0x63, 0x53, + 0x0c, 0xd8, 0xda, 0x20, 0x87, 0x90, 0xdf, 0x03, 0x82, 0x97, 0xe5, 0x65, 0xee, 0xe2, 0x54, 0xa5, + 0xe8, 0x3d, 0x20, 0xa1, 0x23, 0xd2, 0xcc, 0x22, 0xe1, 0x6e, 0xc2, 0x14, 0x49, 0x19, 0xdc, 0x09, + 0x4c, 0x1c, 0xdb, 0xe1, 0xbd, 0xc1, 0x5b, 0xa6, 0xdf, 0x7a, 0x71, 0xc7, 0x9e, 0x11, 0x62, 0xdb + +}; + +const uint8_t aes_xts_256bit_pt[64] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/* key1=000102030405060708090a0b0c0d0e0ffffefdfcfbfaf9f8f7f6f5f4f3f2f1f0 + key2=fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0000102030405060708090a0b0c0d0e0f*/ +const uint8_t aes_xts_256bit_ct[64] = { + 0x06, 0x87, 0xea, 0x7b, 0xf9, 0x87, 0x4b, 0x5a, 0xa6, 0xa5, 0xf1, 0x23, 0x6e, 0xda, 0x73, 0x0a, + 0x73, 0x8d, 0x30, 0x6c, 0x9d, 0x4f, 0xc1, 0x6b, 0xfb, 0x47, 0x2c, 0x58, 0x68, 0x16, 0xfd, 0x07, + 0xe9, 0x59, 0x84, 0xd9, 0x36, 0x84, 0xcd, 0xfc, 0x77, 0xce, 0x30, 0xdf, 0x6d, 0x49, 0xef, 0x54, + 0x66, 0xb2, 0x7f, 0x06, 0x46, 0xbb, 0xb2, 0x46, 0x00, 0xf8, 0x6b, 0x0c, 0xc0, 0x5f, 0xb5, 0x20 +}; + +static struct bflb_aes_link_s aes_ecb_link = { + .aes_key = AES_LINK_KEY_128BITS, /* 128-bit key mode select */ + .aes_dec_en = 0, /* Encode */ + .aes_newkey_dis = 0, /* Use new key */ + .aes_hwkey_en = 0, /* Use sw key */ + .aes_intclr = 0, /* Not clear intrrupt */ + .aes_intset = 0, /* Not set interrupt */ + .aes_mode = AES_MODE_ECB, /* ECB mode select */ + .aes_newiv_dis = 0, /* Use new iv */ + .aes_xts = 0, /* XTS mode select */ + .aes_msglen = 1, /* Number of 128-bit block */ + .aes_srcaddr = 0, /* Message source address */ + .aes_dstaddr = 0, /* Message destination address */ + .aes_iv0 = 0, /* Big endian initial vector(MSB) */ + .aes_iv1 = 0, /* Big endian initial vector */ + .aes_iv2 = 0, /* Big endian initial vector */ + .aes_iv3 = 0, /* Big endian initial vector(LSB)(CTR mode:counter initial value) */ + .aes_key0 = 0x16157e2b, /* Big endian aes key(aes-128/256 key MSB) */ + .aes_key1 = 0xa6d2ae28, /* Big endian aes key */ + .aes_key2 = 0x8815f7ab, /* Big endian aes key */ + .aes_key3 = 0x3c4fcf09, /* Big endian aes key(aes-128 key LSB) */ + .aes_key4 = 0, /* Big endian aes key */ + .aes_key5 = 0, /* Big endian aes key */ + .aes_key6 = 0, /* Big endian aes key */ + .aes_key7 = 0 /* Big endian aes key(aes-256 key LSB) */ +}; + +static struct bflb_aes_link_s aes_cbc_link = { + .aes_key = AES_LINK_KEY_128BITS, /* 128-bit key mode select */ + .aes_dec_en = 0, /* Encode */ + .aes_newkey_dis = 0, /* Use new key */ + .aes_hwkey_en = 0, /* Use sw key */ + .aes_intclr = 0, /* Not clear intrrupt */ + .aes_intset = 0, /* Not set interrupt */ + .aes_mode = AES_MODE_CBC, /* ECB mode select */ + .aes_newiv_dis = 0, /* Use new iv */ + .aes_xts = 0, /* XTS mode select */ + .aes_msglen = 1, /* Number of 128-bit block */ + .aes_srcaddr = 0, /* Message source address */ + .aes_dstaddr = 0, /* Message destination address */ + .aes_iv0 = 0x03020100, /* Big endian initial vector(MSB) */ + .aes_iv1 = 0x07060504, /* Big endian initial vector */ + .aes_iv2 = 0x0b0a0908, /* Big endian initial vector */ + .aes_iv3 = 0x0f0e0d0c, /* Big endian initial vector(LSB)(CTR mode:counter initial value) */ + .aes_key0 = 0x16157e2b, /* Big endian aes key(aes-128/256 key MSB) */ + .aes_key1 = 0xa6d2ae28, /* Big endian aes key */ + .aes_key2 = 0x8815f7ab, /* Big endian aes key */ + .aes_key3 = 0x3c4fcf09, /* Big endian aes key(aes-128 key LSB) */ + .aes_key4 = 0, /* Big endian aes key */ + .aes_key5 = 0, /* Big endian aes key */ + .aes_key6 = 0, /* Big endian aes key */ + .aes_key7 = 0 /* Big endian aes key(aes-256 key LSB) */ +}; + +static struct bflb_aes_link_s aes_cbc_link2 = { + .aes_key = AES_LINK_KEY_128BITS, /* 128-bit key mode select */ + .aes_dec_en = 0, /* Encode */ + .aes_newkey_dis = 0, /* Use new key */ + .aes_hwkey_en = 0, /* Use sw key */ + .aes_intclr = 0, /* Not clear intrrupt */ + .aes_intset = 0, /* Not set interrupt */ + .aes_mode = AES_MODE_CBC, /* ECB mode select */ + .aes_newiv_dis = 0, /* Use new iv */ + .aes_xts = 0, /* XTS mode select */ + .aes_msglen = 1, /* Number of 128-bit block */ + .aes_srcaddr = 0, /* Message source address */ + .aes_dstaddr = 0, /* Message destination address */ + .aes_iv0 = 0x03020100, /* Big endian initial vector(MSB) */ + .aes_iv1 = 0x07060504, /* Big endian initial vector */ + .aes_iv2 = 0x0b0a0908, /* Big endian initial vector */ + .aes_iv3 = 0x0f0e0d0c, /* Big endian initial vector(LSB)(CTR mode:counter initial value) */ + .aes_key0 = 0x16157e2b, /* Big endian aes key(aes-128/256 key MSB) */ + .aes_key1 = 0xa6d2ae28, /* Big endian aes key */ + .aes_key2 = 0x8815f7ab, /* Big endian aes key */ + .aes_key3 = 0x3c4fcf09, /* Big endian aes key(aes-128 key LSB) */ + .aes_key4 = 0, /* Big endian aes key */ + .aes_key5 = 0, /* Big endian aes key */ + .aes_key6 = 0, /* Big endian aes key */ + .aes_key7 = 0 /* Big endian aes key(aes-256 key LSB) */ +}; + +static struct bflb_aes_link_s aes_ctr_link = { + .aes_key = AES_LINK_KEY_128BITS, /* 128-bit key mode select */ + .aes_dec_en = 0, /* Encode */ + .aes_newkey_dis = 0, /* Use new key */ + .aes_hwkey_en = 0, /* Use sw key */ + .aes_intclr = 0, /* Not clear intrrupt */ + .aes_intset = 0, /* Not set interrupt */ + .aes_mode = AES_MODE_CTR, /* ECB mode select */ + .aes_newiv_dis = 0, /* Use new iv */ + .aes_xts = 0, /* XTS mode select */ + .aes_msglen = 1, /* Number of 128-bit block */ + .aes_srcaddr = 0, /* Message source address */ + .aes_dstaddr = 0, /* Message destination address */ + .aes_iv0 = 0xf3f2f1f0, /* Big endian initial vector(MSB) */ + .aes_iv1 = 0xf7f6f5f4, /* Big endian initial vector */ + .aes_iv2 = 0xfbfaf9f8, /* Big endian initial vector */ + .aes_iv3 = 0xfffefdfc, /* Big endian initial vector(LSB)(CTR mode:counter initial value) */ + .aes_key0 = 0x16157e2b, /* Big endian aes key(aes-128/256 key MSB) */ + .aes_key1 = 0xa6d2ae28, /* Big endian aes key */ + .aes_key2 = 0x8815f7ab, /* Big endian aes key */ + .aes_key3 = 0x3c4fcf09, /* Big endian aes key(aes-128 key LSB) */ + .aes_key4 = 0, /* Big endian aes key */ + .aes_key5 = 0, /* Big endian aes key */ + .aes_key6 = 0, /* Big endian aes key */ + .aes_key7 = 0 /* Big endian aes key(aes-256 key LSB) */ +}; + +static struct bflb_aes_xts_link_s aes_xts_link1 = { + .aes_key = AES_LINK_KEY_128BITS, /* 128-bit key mode select */ + .aes_dec_en = 0, /* Encode */ + .aes_newkey_dis = 0, /* Use new key */ + .aes_hwkey_en = 0, /* Use sw key */ + .aes_intclr = 0, /* Not clear intrrupt */ + .aes_intset = 0, /* Not set interrupt */ + .aes_mode = AES_MODE_XTS, /* ECB mode select */ + .aes_newiv_dis = 0, /* Use new iv */ + .aes_xts = 0, /* XTS mode select */ + .aes_msglen = 1, /* Number of 128-bit block */ + .aes_srcaddr = 0, /* Message source address */ + .aes_dstaddr = 0, /* Message destination address */ + .aes_iv0 = 0x00000000, /* Big endian initial vector(MSB) */ + .aes_iv1 = 0x00000000, /* Big endian initial vector */ + .aes_iv2 = 0x00000000, /* Big endian initial vector */ + .aes_iv3 = 0x00000000, /* Big endian initial vector(LSB)(CTR mode:counter initial value) */ + .aes_key10 = 0x00000000, /* Big endian aes key(aes-128/256 key MSB) */ + .aes_key11 = 0x00000000, /* Big endian aes key */ + .aes_key12 = 0x00000000, /* Big endian aes key */ + .aes_key13 = 0x00000000, /* Big endian aes key(aes-128 key LSB) */ + .aes_key14 = 0x00000000, /* Big endian aes key */ + .aes_key15 = 0x00000000, /* Big endian aes key */ + .aes_key16 = 0x00000000, /* Big endian aes key */ + .aes_key17 = 0x00000000, /* Big endian aes key(aes-256 key LSB) */ + .aes_unitlen = 2, /* Big endian aes unit len*/ + .aes_key20 = 0x00000000, /* Big endian aes key2(aes-128/256 key MSB) */ + .aes_key21 = 0x00000000, /* Big endian aes key2 */ + .aes_key22 = 0x00000000, /* Big endian aes key2 */ + .aes_key23 = 0x00000000, /* Big endian aes key2(aes-128 key LSB) */ + .aes_key24 = 0x00000000, /* Big endian aes key2 */ + .aes_key25 = 0x00000000, /* Big endian aes key2 */ + .aes_key26 = 0x00000000, /* Big endian aes key2 */ + .aes_key27 = 0x00000000 /* Big endian aes key2(aes-256 key LSB) */ +}; + +static struct bflb_aes_xts_link_s aes_xts_link2 = { + .aes_key = AES_LINK_KEY_192BITS, /* 128-bit key mode select */ + .aes_dec_en = 0, /* Encode */ + .aes_newkey_dis = 0, /* Use new key */ + .aes_hwkey_en = 0, /* Use sw key */ + .aes_intclr = 0, /* Not clear intrrupt */ + .aes_intset = 0, /* Not set interrupt */ + .aes_mode = AES_MODE_XTS, /* ECB mode select */ + .aes_newiv_dis = 0, /* Use new iv */ + .aes_xts = 0, /* XTS mode select */ + .aes_msglen = 1, /* Number of 128-bit block */ + .aes_srcaddr = 0, /* Message source address */ + .aes_dstaddr = 0, /* Message destination address */ + .aes_iv0 = 0x00000000, /* Big endian initial vector(MSB) */ + .aes_iv1 = 0x00000000, /* Big endian initial vector */ + .aes_iv2 = 0x00000000, /* Big endian initial vector */ + .aes_iv3 = 0x00000000, /* Big endian initial vector(LSB)(CTR mode:counter initial value) */ + .aes_key10 = 0x03020100, /* Big endian aes key(aes-128/256 key MSB) */ + .aes_key11 = 0x07060504, /* Big endian aes key */ + .aes_key12 = 0x0b0a0908, /* Big endian aes key */ + .aes_key13 = 0x0f0e0d0c, /* Big endian aes key(aes-128 key LSB) */ + .aes_key14 = 0xfcfdfeff, /* Big endian aes key */ + .aes_key15 = 0xf8f9fafb, /* Big endian aes key */ + .aes_key16 = 0x00000000, /* Big endian aes key */ + .aes_key17 = 0x00000000, /* Big endian aes key(aes-256 key LSB) */ + .aes_unitlen = 2, /* Big endian aes unit len*/ + .aes_key20 = 0x03020100, /* Big endian aes key2(aes-128/256 key MSB) */ + .aes_key21 = 0x07060504, /* Big endian aes key2 */ + .aes_key22 = 0x0b0a0908, /* Big endian aes key2 */ + .aes_key23 = 0x0f0e0d0c, /* Big endian aes key2(aes-128 key LSB) */ + .aes_key24 = 0xfcfdfeff, /* Big endian aes key2 */ + .aes_key25 = 0xf8f9fafb, /* Big endian aes key2 */ + .aes_key26 = 0x00000000, /* Big endian aes key2 */ + .aes_key27 = 0x00000000 /* Big endian aes key2(aes-256 key LSB) */ +}; + +static struct bflb_aes_xts_link_s aes_xts_link3 = { + .aes_key = AES_LINK_KEY_256BITS, /* 128-bit key mode select */ + .aes_dec_en = 0, /* Encode */ + .aes_newkey_dis = 0, /* Use new key */ + .aes_hwkey_en = 0, /* Use sw key */ + .aes_intclr = 0, /* Not clear intrrupt */ + .aes_intset = 0, /* Not set interrupt */ + .aes_mode = AES_MODE_XTS, /* ECB mode select */ + .aes_newiv_dis = 0, /* Use new iv */ + .aes_xts = 0, /* XTS mode select */ + .aes_msglen = 1, /* Number of 128-bit block */ + .aes_srcaddr = 0, /* Message source address */ + .aes_dstaddr = 0, /* Message destination address */ + .aes_iv0 = 0x00000000, /* Big endian initial vector(MSB) */ + .aes_iv1 = 0x00000000, /* Big endian initial vector */ + .aes_iv2 = 0x00000000, /* Big endian initial vector */ + .aes_iv3 = 0x00000000, /* Big endian initial vector(LSB)(CTR mode:counter initial value) */ + .aes_key10 = 0x03020100, /* Big endian aes key(aes-128/256 key MSB) */ + .aes_key11 = 0x07060504, /* Big endian aes key */ + .aes_key12 = 0x0b0a0908, /* Big endian aes key */ + .aes_key13 = 0x0f0e0d0c, /* Big endian aes key(aes-128 key LSB) */ + .aes_key14 = 0xfcfdfeff, /* Big endian aes key */ + .aes_key15 = 0xf8f9fafb, /* Big endian aes key */ + .aes_key16 = 0xf4f5f6f7, /* Big endian aes key */ + .aes_key17 = 0xf0f1f2f3, /* Big endian aes key(aes-256 key LSB) */ + .aes_unitlen = 2, /* Big endian aes unit len*/ + .aes_key20 = 0xfcfdfeff, /* Big endian aes key2(aes-128/256 key MSB) */ + .aes_key21 = 0xf8f9fafb, /* Big endian aes key2 */ + .aes_key22 = 0xf4f5f6f7, /* Big endian aes key2 */ + .aes_key23 = 0xf0f1f2f3, /* Big endian aes key2(aes-128 key LSB) */ + .aes_key24 = 0x03020100, /* Big endian aes key2 */ + .aes_key25 = 0x07060504, /* Big endian aes key2 */ + .aes_key26 = 0x0b0a0908, /* Big endian aes key2 */ + .aes_key27 = 0x0f0e0d0c /* Big endian aes key2(aes-256 key LSB) */ +}; + +static uint32_t bflb_data_compare(const uint8_t *expected, uint8_t *input, uint32_t len) +{ + int i = 0; + for (i = 0; i < len; i++) { + if (input[i] != expected[i]) { + printf("Compare fail at %d,input %02x, but expect %02x\r\n", i, input[i], expected[i]); + while (1) { + } + } + } + + return 0; +} + +ATTR_NOCACHE_RAM_SECTION uint8_t aes_enc_buf[512]; +ATTR_NOCACHE_RAM_SECTION uint8_t aes_dec_buf[512]; + +int main(void) +{ + board_init(); + + struct bflb_device_s *aes; + + aes = bflb_device_get_by_name("aes"); + + bflb_group0_request_aes_access(aes); + + bflb_aes_link_init(aes); + + bflb_aes_link_update(aes, (uint32_t)&aes_ecb_link, aes_ecb_128bit_pt, aes_enc_buf, 16); + bflb_data_compare(aes_ecb_128bit_ct, aes_enc_buf, 16); + printf("aes link ecb 128 success\r\n"); + + bflb_aes_link_update(aes, (uint32_t)&aes_cbc_link, aes_cbc_128bit_pt, aes_enc_buf, 16); + bflb_data_compare(aes_cbc_128bit_ct, aes_enc_buf, 16); + printf("aes link cbc 128 success\r\n"); + + bflb_aes_link_update(aes, (uint32_t)&aes_cbc_link2, aes_cbc_128bit_pt, aes_enc_buf, 48); + bflb_data_compare(aes_cbc_128bit_ct, aes_enc_buf, 48); + printf("aes link cbc 128 success\r\n"); + + bflb_aes_link_update(aes, (uint32_t)&aes_ctr_link, aes_ctr_128bit_pt, aes_enc_buf, 16); + bflb_data_compare(aes_ctr_128bit_ct, aes_enc_buf, 16); + printf("aes link ctr 128 success\r\n"); + + bflb_aes_link_update(aes, (uint32_t)&aes_xts_link1, aes_xts_128bit_pt, aes_enc_buf, 16); + bflb_data_compare(aes_xts_128bit_ct, aes_enc_buf, 16); + printf("aes link xts 128 success\r\n"); + + bflb_aes_link_update(aes, (uint32_t)&aes_xts_link2, aes_xts_192bit_pt, aes_enc_buf, 16); + bflb_data_compare(aes_xts_192bit_ct, aes_enc_buf, 16); + printf("aes link xts 192 success\r\n"); + + bflb_aes_link_update(aes, (uint32_t)&aes_xts_link3, aes_xts_256bit_pt, aes_enc_buf, 16); + bflb_data_compare(aes_xts_256bit_ct, aes_enc_buf, 16); + printf("aes link xts 256 success\r\n"); + + printf("aes link success\r\n"); + bflb_group0_release_aes_access(aes); + while (1) { + bflb_mtimer_delay_ms(2000); + } +} \ No newline at end of file diff --git a/examples/peripherals/sec_eng/sec_eng_aes_link_sw_key/proj.conf b/examples/peripherals/sec_eng/sec_eng_aes_link_sw_key/proj.conf new file mode 100644 index 00000000..13320d67 --- /dev/null +++ b/examples/peripherals/sec_eng/sec_eng_aes_link_sw_key/proj.conf @@ -0,0 +1 @@ +#set(CONFIG_XXX 1) \ No newline at end of file diff --git a/examples/peripherals/sec_eng/sec_eng_aes_sw_key/main.c b/examples/peripherals/sec_eng/sec_eng_aes_sw_key/main.c index c771c8bf..5e1c4c1e 100644 --- a/examples/peripherals/sec_eng/sec_eng_aes_sw_key/main.c +++ b/examples/peripherals/sec_eng/sec_eng_aes_sw_key/main.c @@ -490,6 +490,8 @@ int main(void) aes = bflb_device_get_by_name("aes"); + bflb_group0_request_aes_access(aes); + bflb_aes_init(aes); bflb_aes_set_mode(aes, AES_MODE_ECB); @@ -589,6 +591,7 @@ int main(void) printf("aes xts 256 success\r\n"); printf("aes success\r\n"); + bflb_group0_release_aes_access(aes); while (1) { bflb_mtimer_delay_ms(2000); } diff --git a/examples/peripherals/sec_eng/sec_eng_ecdh/CMakeLists.txt b/examples/peripherals/sec_eng/sec_eng_ecdh/CMakeLists.txt new file mode 100644 index 00000000..a1b1f691 --- /dev/null +++ b/examples/peripherals/sec_eng/sec_eng_ecdh/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.15) + +include(proj.conf) + +find_package(bouffalo_sdk REQUIRED HINTS $ENV{BL_SDK_BASE}) + +sdk_set_main_file(main.c) + +project(sec_eng_ecdh) diff --git a/examples/peripherals/sec_eng/sec_eng_ecdh/Makefile b/examples/peripherals/sec_eng/sec_eng_ecdh/Makefile new file mode 100644 index 00000000..44367c02 --- /dev/null +++ b/examples/peripherals/sec_eng/sec_eng_ecdh/Makefile @@ -0,0 +1,13 @@ +SDK_DEMO_PATH ?= . +BL_SDK_BASE ?= $(SDK_DEMO_PATH)/../../../.. + +export BL_SDK_BASE + +CHIP ?= bl616 +BOARD ?= bl616dk +CROSS_COMPILE ?= riscv64-unknown-elf- + +# add custom cmake definition +#cmake_definition+=-Dxxx=sss + +include $(BL_SDK_BASE)/project.build diff --git a/examples/peripherals/sec_eng/sec_eng_ecdh/main.c b/examples/peripherals/sec_eng/sec_eng_ecdh/main.c new file mode 100644 index 00000000..88a753f2 --- /dev/null +++ b/examples/peripherals/sec_eng/sec_eng_ecdh/main.c @@ -0,0 +1,228 @@ +#include "bflb_mtimer.h" +#include "bflb_sec_ecdsa.h" +#include "board.h" + +#define ALGORITHM_TYPE 0 + +/* We use following two case to show how ECDH works*/ +//========================== +//Alice's secret key: 1672493697407246559549867004310108600574958080780180188771300643695147736525 +//Alice's public key: (8186931993451804108690395451499266320135437983074928011404785122795116228120L, 42583342814291813019381020879433259376088942101048764740128506039642196631017L) +//Bob's secret key: 80820894835688796582966945354468122770925276582929501754975915934762303146292 +//Bob's public key: (110419239604359817300303235482162221248952850592986847629047641306847745620659L, 19394459839852358891515335116028197103691369259799083720249515230794728385441L) +//========================== +//Alice's shared key: (89478371667134321617252675049711550685663874249668539239111908843552332917927L, 817906898059826893312335918167859928021104862259509866199871605894193053448L) +//Bob's shared key: (89478371667134321617252675049711550685663874249668539239111908843552332917927L, 817906898059826893312335918167859928021104862259509866199871605894193053448L) +//========================== +//The shared value is the x-value: 89478371667134321617252675049711550685663874249668539239111908843552332917927 +uint8_t secp256r1_ecdh_private_key1[32] = { 0x03, 0xb2, 0x99, 0xf, 0x18, 0x16, 0x38, 0x78, 0x88, 0xb1, 0x9, 0xfd, 0xd4, 0x33, 0x94, 0x1a, + 0x1f, 0x7e, 0x7c, 0x8b, 0xf7, 0xf2, 0x34, 0x15, 0xb0, 0xc1, 0x21, 0x61, 0xc0, 0xe9, 0xdd, 0xcd }; +uint8_t secp256r1_ecdh_public_keyx1[32] = { 0x12, 0x19, 0xa3, 0xa9, 0xd, 0xbf, 0xfa, 0xf3, 0xd5, 0x1b, 0x8c, 0xa0, 0xa6, 0xec, 0xd9, 0xa8, + 0xca, 0xf0, 0x6, 0xaf, 0x3b, 0x52, 0x4b, 0x9f, 0x93, 0x96, 0xcb, 0xa, 0xe6, 0xa6, 0xee, 0x18 }; +uint8_t secp256r1_ecdh_public_keyy1[32] = { 0x5e, 0x25, 0x51, 0x62, 0xd6, 0x5, 0x89, 0xe3, 0x65, 0x3d, 0xde, 0xf1, 0x59, 0xcb, 0xee, 0x70, + 0x56, 0x40, 0x71, 0x55, 0x9e, 0xec, 0xe0, 0x4, 0x81, 0xa4, 0xfc, 0x7a, 0xf, 0xe5, 0x5d, 0xe9 }; +uint8_t secp256r1_ecdh_shared_keyx1[32] = { 0xc5, 0xd2, 0xf6, 0xb1, 0x69, 0x8c, 0x4f, 0xff, 0x1b, 0x4a, 0x9d, 0x4, 0x4d, 0x7a, 0x3d, 0xbf, + 0xa5, 0xed, 0xfc, 0xd6, 0xc9, 0x12, 0xe7, 0x67, 0x32, 0x1e, 0x3f, 0x31, 0x4b, 0xf1, 0x2c, 0xa7 }; + +uint8_t secp256r1_ecdh_private_key2[32] = { 0xb2, 0xaf, 0x1, 0x62, 0x49, 0x36, 0x12, 0xee, 0x36, 0xfb, 0x72, 0x20, 0xc9, 0xcc, 0xba, 0xe7, + 0x86, 0x5, 0x11, 0x84, 0x72, 0xed, 0x1c, 0xa4, 0xf8, 0x2c, 0x3a, 0xb, 0xf6, 0x9e, 0xc9, 0x34 }; +uint8_t secp256r1_ecdh_public_keyx2[32] = { 0xf4, 0x1f, 0x13, 0x2a, 0xf2, 0x7b, 0x67, 0x22, 0xcb, 0x6a, 0x73, 0xb5, 0x21, 0x17, 0x32, 0x32, + 0x7d, 0x8c, 0x42, 0x71, 0x3, 0x9d, 0x54, 0xc, 0x68, 0xdc, 0xac, 0x8b, 0x1d, 0x63, 0x3a, 0xb3 }; +uint8_t secp256r1_ecdh_public_keyy2[32] = { 0x2a, 0xe0, 0xe0, 0x11, 0x45, 0xbc, 0x5e, 0x1b, 0x30, 0x4, 0x1b, 0xc3, 0x45, 0x3b, 0xb9, 0xb6, + 0x77, 0x64, 0x6b, 0x7e, 0x96, 0x1a, 0xad, 0x22, 0xd2, 0xe4, 0x9f, 0x29, 0x8e, 0x64, 0xab, 0xa1 }; +uint8_t secp256r1_ecdh_shared_keyx2[32] = { 0xc5, 0xd2, 0xf6, 0xb1, 0x69, 0x8c, 0x4f, 0xff, 0x1b, 0x4a, 0x9d, 0x4, 0x4d, 0x7a, 0x3d, 0xbf, + 0xa5, 0xed, 0xfc, 0xd6, 0xc9, 0x12, 0xe7, 0x67, 0x32, 0x1e, 0x3f, 0x31, 0x4b, 0xf1, 0x2c, 0xa7 }; + +uint8_t secp256r1_ecdh_private_key[32] = { 0xba, 0x25, 0xf6, 0xc1, 0xa7, 0x82, 0x9a, 0x18, 0x51, 0x08, 0x0c, 0xa8, 0x79, 0x50, 0xb9, 0xd5, + 0x17, 0x7a, 0x8a, 0x65, 0x72, 0xd3, 0x12, 0x87, 0x07, 0x04, 0x9c, 0x74, 0x95, 0x3e, 0xf6, 0x11 }; +uint8_t secp256r1_ecdh_public_keyx[32] = { 0xbe, 0xbb, 0x36, 0x3c, 0xfd, 0x53, 0x8d, 0x94, 0x86, 0x7c, 0xf5, 0xbb, 0x35, 0xd8, 0xb6, 0x7b, + 0x74, 0x8c, 0x7a, 0xcf, 0x05, 0xa4, 0x5c, 0x70, 0x79, 0xb4, 0x78, 0x50, 0x8e, 0x87, 0xea, 0x4c }; +uint8_t secp256r1_ecdh_public_keyy[32] = { 0x84, 0x3c, 0x5b, 0x9c, 0x9c, 0x6b, 0x6c, 0xca, 0xe0, 0xfe, 0x1b, 0x2b, 0xdc, 0xce, 0xb0, 0x24, + 0x3b, 0x4c, 0xc3, 0x58, 0x4c, 0x59, 0x28, 0x4c, 0xda, 0x26, 0x8d, 0x67, 0x9e, 0x8c, 0x29, 0xd4 }; +uint8_t secp256r1_ecdh_shared_keyx[32] = { 0x58, 0xa7, 0x3b, 0x0f, 0x15, 0x58, 0x4e, 0x3a, 0xed, 0x9e, 0x01, 0x3c, 0xbc, 0xdd, 0x9f, 0x56, + 0x16, 0xac, 0x5f, 0xe4, 0x8f, 0x2f, 0xad, 0x38, 0x98, 0x50, 0x43, 0x5e, 0x4e, 0xed, 0x74, 0x53 }; + +uint8_t secp256k1_ecdh_private_key1[32] = { 0x85, 0xE6, 0xDC, 0xDB, 0x9D, 0x9C, 0x00, 0x72, + 0xC0, 0xB7, 0x7C, 0x85, 0xF3, 0x34, 0x83, 0xFC, + 0x8A, 0x3A, 0xDF, 0xC5, 0xAC, 0x64, 0xB5, 0xA0, + 0xC2, 0xFA, 0xD6, 0xDA, 0xAA, 0x51, 0x04, 0xEE }; +uint8_t secp256k1_ecdh_public_keyx1[32] = { 0x10, 0xC8, 0x99, 0xD4, 0x8B, 0xA1, 0x23, 0x90, + 0xBC, 0x54, 0xE3, 0x1F, 0x32, 0x09, 0x7B, 0x3F, + 0xFF, 0xF2, 0x50, 0xB2, 0xBA, 0xBA, 0x82, 0xFB, + 0x64, 0x58, 0x12, 0xDD, 0x14, 0x17, 0x89, 0x53 }; +uint8_t secp256k1_ecdh_public_keyy1[32] = { 0xC3, 0x71, 0x10, 0x3B, 0xF3, 0x00, 0x4B, 0x6E, + 0x4E, 0x6A, 0x95, 0xF1, 0xAB, 0xCE, 0xDE, 0x10, + 0x91, 0x38, 0x7A, 0x9C, 0xCF, 0x0D, 0x9B, 0x67, + 0x55, 0x79, 0xFD, 0x16, 0x30, 0xFB, 0x0B, 0xC4 }; +uint8_t secp256k1_ecdh_shared_keyx1[32] = { 0x4B, 0xA5, 0xE0, 0xFD, 0x2C, 0x36, 0xC4, 0xA4, + 0xB5, 0xAA, 0x6D, 0x05, 0xF6, 0x3D, 0xAF, 0x99, + 0x58, 0x38, 0x84, 0x6A, 0xE1, 0xD3, 0x0E, 0x2E, + 0xE6, 0x2D, 0xCF, 0x3C, 0x96, 0x70, 0xC0, 0x86 }; + +uint8_t secp256k1_ecdh_private_key2[32] = { 0x07, 0xDF, 0xAB, 0x47, 0x68, 0xA1, 0x2B, 0x99, + 0xDF, 0x8F, 0xE0, 0x1A, 0x5D, 0x04, 0x83, 0xB2, + 0xB1, 0x64, 0x45, 0xB5, 0xB5, 0xC7, 0x7B, 0x09, + 0x17, 0xC9, 0x07, 0x04, 0x2C, 0xFB, 0xBF, 0x40 }; +uint8_t secp256k1_ecdh_public_keyx2[32] = { 0xBD, 0x50, 0xB9, 0x7C, 0x60, 0xB5, 0x23, 0x6B, + 0xDA, 0xCD, 0xA8, 0xB6, 0xCF, 0x9F, 0x01, 0xDF, + 0xAC, 0x00, 0x5D, 0x23, 0xA3, 0x21, 0xEC, 0xDB, + 0xC2, 0x0C, 0x03, 0x70, 0x9B, 0x2B, 0x15, 0x7B }; +uint8_t secp256k1_ecdh_public_keyy2[32] = { 0x95, 0xE3, 0x6C, 0x9C, 0xE2, 0xB3, 0x08, 0x8B, + 0x80, 0x95, 0x54, 0xFD, 0x73, 0x6D, 0xF5, 0xB4, + 0x3B, 0xDE, 0x5B, 0xD7, 0x90, 0x5C, 0x89, 0x73, + 0xF0, 0x08, 0xF5, 0x23, 0x7B, 0x2D, 0x31, 0xD3 }; +uint8_t secp256k1_ecdh_shared_keyx2[32] = { 0x4B, 0xA5, 0xE0, 0xFD, 0x2C, 0x36, 0xC4, 0xA4, + 0xB5, 0xAA, 0x6D, 0x05, 0xF6, 0x3D, 0xAF, 0x99, + 0x58, 0x38, 0x84, 0x6A, 0xE1, 0xD3, 0x0E, 0x2E, + 0xE6, 0x2D, 0xCF, 0x3C, 0x96, 0x70, 0xC0, 0x86 }; + +uint8_t secp256k1_ecdh_private_key[32] = { 0x07, 0xDF, 0xAB, 0x47, 0x68, 0xA1, 0x2B, 0x99, + 0xDF, 0x8F, 0xE0, 0x1A, 0x5D, 0x04, 0x83, 0xB2, + 0xB1, 0x64, 0x45, 0xB5, 0xB5, 0xC7, 0x7B, 0x09, + 0x17, 0xC9, 0x07, 0x04, 0x2C, 0xFB, 0xBF, 0x40 }; +uint8_t secp256k1_ecdh_public_keyx[32] = { 0xBD, 0x50, 0xB9, 0x7C, 0x60, 0xB5, 0x23, 0x6B, + 0xDA, 0xCD, 0xA8, 0xB6, 0xCF, 0x9F, 0x01, 0xDF, + 0xAC, 0x00, 0x5D, 0x23, 0xA3, 0x21, 0xEC, 0xDB, + 0xC2, 0x0C, 0x03, 0x70, 0x9B, 0x2B, 0x15, 0x7B }; +uint8_t secp256k1_ecdh_public_keyy[32] = { 0x95, 0xE3, 0x6C, 0x9C, 0xE2, 0xB3, 0x08, 0x8B, + 0x80, 0x95, 0x54, 0xFD, 0x73, 0x6D, 0xF5, 0xB4, + 0x3B, 0xDE, 0x5B, 0xD7, 0x90, 0x5C, 0x89, 0x73, + 0xF0, 0x08, 0xF5, 0x23, 0x7B, 0x2D, 0x31, 0xD3 }; +uint8_t secp256k1_ecdh_shared_keyx[32] = { 0x15, 0x5C, 0x1B, 0x6F, 0xE7, 0xF9, 0x99, 0xCC, + 0xBD, 0x9E, 0x1E, 0x3B, 0x71, 0xA0, 0x10, 0x5F, + 0xA7, 0x74, 0x9C, 0xAF, 0xE9, 0x92, 0xFB, 0xE8, + 0x9E, 0x9C, 0x54, 0x6B, 0x23, 0x39, 0x22, 0xEE }; + +#define BUFF_COPY(G) \ + { \ + memcpy(ecdh_private_key1, G##_ecdh_private_key1, 32); \ + memcpy(ecdh_public_keyx1, G##_ecdh_public_keyx1, 32); \ + memcpy(ecdh_public_keyy1, G##_ecdh_public_keyy1, 32); \ + memcpy(ecdh_shared_keyx1, G##_ecdh_shared_keyx1, 32); \ + memcpy(ecdh_private_key2, G##_ecdh_private_key2, 32); \ + memcpy(ecdh_public_keyx2, G##_ecdh_public_keyx2, 32); \ + memcpy(ecdh_public_keyy2, G##_ecdh_public_keyy2, 32); \ + memcpy(ecdh_shared_keyx2, G##_ecdh_shared_keyx2, 32); \ + memcpy(ecdh_private_key, G##_ecdh_private_key, 32); \ + memcpy(ecdh_public_keyx, G##_ecdh_public_keyx, 32); \ + memcpy(ecdh_public_keyy, G##_ecdh_public_keyy, 32); \ + memcpy(ecdh_shared_keyx, G##_ecdh_shared_keyx, 32); \ + } + +int main(void) +{ + uint8_t ecdh_private_key1[32]; + uint8_t ecdh_public_keyx1[32]; + uint8_t ecdh_public_keyy1[32]; + uint8_t ecdh_shared_keyx1[32]; + + uint8_t ecdh_private_key2[32]; + uint8_t ecdh_public_keyx2[32]; + uint8_t ecdh_public_keyy2[32]; + uint8_t ecdh_shared_keyx2[32]; + + uint8_t ecdh_private_key[32]; + uint8_t ecdh_public_keyx[32]; + uint8_t ecdh_public_keyy[32]; + uint8_t ecdh_shared_keyx[32]; + + uint32_t ecdh_keyx[8]; + uint32_t ecdh_keyy[8]; + + int32_t i; + uint8_t *p; + + struct bflb_ecdh_s ecdh_handle; + uint32_t time1, time2; + + board_init(); + + printf("ECDH Case\r\n"); + + for (int type_id = 0; type_id < 2; type_id++) { + if (type_id == 0) { + bflb_sec_ecdh_init(&ecdh_handle, ECP_SECP256R1); + printf("ECP_SECP256R1\r\n"); + BUFF_COPY(secp256r1); + } else if (type_id == 1) { + bflb_sec_ecdh_init(&ecdh_handle, ECP_SECP256K1); + printf("ECP_SECP256K1\r\n"); + BUFF_COPY(secp256k1); + } + + printf("Bob calculate encrypt key\r\n"); + time1 = (unsigned int)bflb_mtimer_get_time_us(); + bflb_sec_ecdh_get_encrypt_key(&ecdh_handle, (uint32_t *)ecdh_public_keyx1, (uint32_t *)ecdh_public_keyy1, (uint32_t *)ecdh_private_key2, ecdh_keyx, ecdh_keyy); + time2 = (unsigned int)bflb_mtimer_get_time_us(); + printf("Get encrypt key time=%dus\r\n", (time2 - time1)); + + p = (uint8_t *)ecdh_keyx; + + for (i = 0; i < 32; i++) { + if (ecdh_shared_keyx2[i] != p[i]) { + printf("ECDH Compare fail\r\n"); + printf("p[%d]=0x%x\r\n", i, p[i]); + } + } + + printf("Alice calculate encrypt key\r\n"); + time1 = (unsigned int)bflb_mtimer_get_time_us(); + bflb_sec_ecdh_get_encrypt_key(&ecdh_handle, (uint32_t *)ecdh_public_keyx2, (uint32_t *)ecdh_public_keyy2, (uint32_t *)ecdh_private_key1, ecdh_keyx, ecdh_keyy); + time2 = (unsigned int)bflb_mtimer_get_time_us(); + printf("Get encrypt key time=%dus\r\n", (time2 - time1)); + + p = (uint8_t *)ecdh_keyx; + + for (i = 0; i < 32; i++) { + if (ecdh_shared_keyx1[i] != p[i]) { + printf("ECDH Compare fail\r\n"); + printf("p[%d]=0x%x\r\n", i, p[i]); + } + } + + printf("Another case\r\n"); + printf("Get Public key\r\n"); + time1 = (unsigned int)bflb_mtimer_get_time_us(); + bflb_sec_ecdh_get_public_key(&ecdh_handle, (uint32_t *)ecdh_private_key, ecdh_keyx, ecdh_keyy); + time2 = (unsigned int)bflb_mtimer_get_time_us(); + printf("Get public key time=%dus\r\n", (time2 - time1)); + + p = (uint8_t *)ecdh_keyx; + + for (i = 0; i < 32; i++) { + if (ecdh_public_keyx[i] != p[i]) { + printf("ECDH Compare fail\r\n"); + printf("p[%d]=0x%x\r\n", i, p[i]); + } + } + + p = (uint8_t *)ecdh_keyy; + + for (i = 0; i < 32; i++) { + if (ecdh_public_keyy[i] != p[i]) { + printf("ECDH Compare fail\r\n"); + printf("p[%d]=0x%x\r\n", i, p[i]); + } + } + + printf("Get shared key\r\n"); + + time1 = (unsigned int)bflb_mtimer_get_time_us(); + bflb_sec_ecdh_get_encrypt_key(&ecdh_handle, ecdh_keyx, ecdh_keyy, (uint32_t *)ecdh_private_key, ecdh_keyx, ecdh_keyy); + time2 = (unsigned int)bflb_mtimer_get_time_us(); + printf("Get share key time=%dus\r\n", (time2 - time1)); + + p = (uint8_t *)ecdh_keyx; + + for (i = 0; i < 32; i++) { + if (ecdh_shared_keyx[i] != p[i]) { + printf("ECDH Compare fail\r\n"); + printf("p[%d]=0x%x\r\n", i, p[i]); + } + } + } + + while (1) { + bflb_mtimer_delay_ms(2000); + } +} \ No newline at end of file diff --git a/examples/peripherals/sec_eng/sec_eng_ecdh/proj.conf b/examples/peripherals/sec_eng/sec_eng_ecdh/proj.conf new file mode 100644 index 00000000..13320d67 --- /dev/null +++ b/examples/peripherals/sec_eng/sec_eng_ecdh/proj.conf @@ -0,0 +1 @@ +#set(CONFIG_XXX 1) \ No newline at end of file diff --git a/examples/peripherals/sec_eng/sec_eng_ecdsa/CMakeLists.txt b/examples/peripherals/sec_eng/sec_eng_ecdsa/CMakeLists.txt new file mode 100644 index 00000000..a3f3ee67 --- /dev/null +++ b/examples/peripherals/sec_eng/sec_eng_ecdsa/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.15) + +include(proj.conf) + +find_package(bouffalo_sdk REQUIRED HINTS $ENV{BL_SDK_BASE}) + +sdk_set_main_file(main.c) + +project(sec_eng_ecdsa) diff --git a/examples/peripherals/sec_eng/sec_eng_ecdsa/Makefile b/examples/peripherals/sec_eng/sec_eng_ecdsa/Makefile new file mode 100644 index 00000000..44367c02 --- /dev/null +++ b/examples/peripherals/sec_eng/sec_eng_ecdsa/Makefile @@ -0,0 +1,13 @@ +SDK_DEMO_PATH ?= . +BL_SDK_BASE ?= $(SDK_DEMO_PATH)/../../../.. + +export BL_SDK_BASE + +CHIP ?= bl616 +BOARD ?= bl616dk +CROSS_COMPILE ?= riscv64-unknown-elf- + +# add custom cmake definition +#cmake_definition+=-Dxxx=sss + +include $(BL_SDK_BASE)/project.build diff --git a/examples/peripherals/sec_eng/sec_eng_ecdsa/main.c b/examples/peripherals/sec_eng/sec_eng_ecdsa/main.c new file mode 100644 index 00000000..ddb80101 --- /dev/null +++ b/examples/peripherals/sec_eng/sec_eng_ecdsa/main.c @@ -0,0 +1,156 @@ +#include "bflb_mtimer.h" +#include "bflb_sec_ecdsa.h" +#include "board.h" + +int main(void) +{ + board_init(); + + /* We use following test vector to show how BFLB_ECDSA works�� + * this can be found in https://tools.ietf.org/html/rfc6979#page-33 */ +#if 0 + A.2.5. ECDSA, 256 Bits (Prime Field) + + Key pair: + + curve: NIST P-256 + + q = FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551 + (qlen = 256 bits) + + private key: + + x = C9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721 + + public key: U = xG + + Ux = 60FED4BA255A9D31C961EB74C6356D68C049B8923B61FA6CE669622E60F29FB6 + + Uy = 7903FE1008B8BC99A41AE9E95628BC64F2F1B20C2D7E9F5177A3C294D4462299 + + Signatures: + + With SHA-1, message = "sample": + k = 882905F1227FD620FBF2ABF21244F0BA83D0DC3A9103DBBEE43A1FB858109DB4 + r = 61340C88C3AAEBEB4F6D667F672CA9759A6CCAA9FA8811313039EE4A35471D32 + s = 6D7F147DAC089441BB2E2FE8F7A3FA264B9C475098FDCF6E00D7C996E1B8B7EB + + With SHA-224, message = "sample": + k = 103F90EE9DC52E5E7FB5132B7033C63066D194321491862059967C715985D473 + r = 53B2FFF5D1752B2C689DF257C04C40A587FABABB3F6FC2702F1343AF7CA9AA3F + s = B9AFB64FDC03DC1A131C7D2386D11E349F070AA432A4ACC918BEA988BF75C74C + + With SHA-256, message = "sample": + k = A6E3C57DD01ABE90086538398355DD4C3B17AA873382B0F24D6129493D8AAD60 + r = EFD48B2AACB6A8FD1140DD9CD45E81D69D2C877B56AAF991C34D0EA84EAF3716 + s = F7CB1C942D657C41D436C7A1B6E29F65F3E900DBB9AFF4064DC4AB2F843ACDA8 + + With SHA-384, message = "sample": + k = 09F634B188CEFD98E7EC88B1AA9852D734D0BC272F7D2A47DECC6EBEB375AAD4 + r = 0EAFEA039B20E9B42309FB1D89E213057CBF973DC0CFC8F129EDDDC800EF7719 + s = 4861F0491E6998B9455193E34E7B0D284DDD7149A74B95B9261F13ABDE940954 + + With SHA-512, message = "sample": + k = 5FA81C63109BADB88C1F367B47DA606DA28CAD69AA22C4FE6AD7DF73A7173AA5 + r = 8496A60B5E9B47C825488827E0495B0E3FA109EC4568FD3F8D1097678EB97F00 + s = 2362AB1ADBE2B8ADF9CB9EDAB740EA6049C028114F2460F96554F61FAE3302FE +#endif + uint32_t i = 0; + uint8_t *p; + uint32_t time = 0; + + uint8_t ecdsa_hash[32] = { 0xAF, 0x2B, 0xDB, 0xE1, 0xAA, 0x9B, 0x6E, 0xC1, 0xE2, 0xAD, 0xE1, 0xD6, 0x94, 0xF4, 0x1F, 0xC7, + 0x1A, 0x83, 0x1D, 0x02, 0x68, 0xE9, 0x89, 0x15, 0x62, 0x11, 0x3D, 0x8A, 0x62, 0xAD, 0xD1, 0xBF }; + uint8_t ecdsa_private_key[32] = { 0xC9, 0xAF, 0xA9, 0xD8, 0x45, 0xBA, 0x75, 0x16, 0x6B, 0x5C, 0x21, 0x57, 0x67, 0xB1, 0xD6, 0x93, + 0x4E, 0x50, 0xC3, 0xDB, 0x36, 0xE8, 0x9B, 0x12, 0x7B, 0x8A, 0x62, 0x2B, 0x12, 0x0F, 0x67, 0x21 }; + uint8_t ecdsa_public_keyx[32] = { 0x60, 0xFE, 0xD4, 0xBA, 0x25, 0x5A, 0x9D, 0x31, 0xC9, 0x61, 0xEB, 0x74, 0xC6, 0x35, 0x6D, 0x68, + 0xC0, 0x49, 0xB8, 0x92, 0x3B, 0x61, 0xFA, 0x6C, 0xE6, 0x69, 0x62, 0x2E, 0x60, 0xF2, 0x9F, 0xB6 }; + uint8_t ecdsa_public_keyy[32] = { 0x79, 0x03, 0xFE, 0x10, 0x08, 0xB8, 0xBC, 0x99, 0xA4, 0x1A, 0xE9, 0xE9, 0x56, 0x28, 0xBC, 0x64, + 0xF2, 0xF1, 0xB2, 0x0C, 0x2D, 0x7E, 0x9F, 0x51, 0x77, 0xA3, 0xC2, 0x94, 0xD4, 0x46, 0x22, 0x99 }; + uint8_t ecdsa_k[32] = { 0xA6, 0xE3, 0xC5, 0x7D, 0xD0, 0x1A, 0xBE, 0x90, 0x08, 0x65, 0x38, 0x39, 0x83, 0x55, 0xDD, 0x4C, + 0x3B, 0x17, 0xAA, 0x87, 0x33, 0x82, 0xB0, 0xF2, 0x4D, 0x61, 0x29, 0x49, 0x3D, 0x8A, 0xAD, 0x60 }; + uint8_t ecdsa_r[32] = { 0xEF, 0xD4, 0x8B, 0x2A, 0xAC, 0xB6, 0xA8, 0xFD, 0x11, 0x40, 0xDD, 0x9C, 0xD4, 0x5E, 0x81, 0xD6, + 0x9D, 0x2C, 0x87, 0x7B, 0x56, 0xAA, 0xF9, 0x91, 0xC3, 0x4D, 0x0E, 0xA8, 0x4E, 0xAF, 0x37, 0x16 }; + uint8_t ecdsa_s[32] = { 0xF7, 0xCB, 0x1C, 0x94, 0x2D, 0x65, 0x7C, 0x41, 0xD4, 0x36, 0xC7, 0xA1, 0xB6, 0xE2, 0x9F, 0x65, + 0xF3, 0xE9, 0x00, 0xDB, 0xB9, 0xAF, 0xF4, 0x06, 0x4D, 0xC4, 0xAB, 0x2F, 0x84, 0x3A, 0xCD, 0xA8 }; + + uint32_t tmp_keyx[8]; + uint32_t tmp_keyy[8]; + struct bflb_ecdsa_s ecdsa_handle; + + printf("ECDSA Case\r\n"); + + bflb_sec_ecdsa_init(&ecdsa_handle, ECP_SECP256R1); + ecdsa_handle.privateKey = (uint32_t *)ecdsa_private_key; + ecdsa_handle.publicKeyx = (uint32_t *)ecdsa_public_keyx; + ecdsa_handle.publicKeyy = (uint32_t *)ecdsa_public_keyy; + +#if 0 + time = (unsigned int)bflb_mtimer_get_time_ms(); + bflb_sec_ecdsa_get_public_key(&ecdsa_handle, (uint32_t *)ecdsa_private_key, tmp_keyx, tmp_keyy); + printf("Get public key time=%dms\r\n", (unsigned int)bflb_mtimer_get_time_ms() - time); + + p = (uint8_t *)tmp_keyx; + + for(i = 0; i < 32; i++) + { + if(ecdsa_public_keyx[i] != p[i]) + { + printf("ECDSA Compare fail\r\n"); + bflb_mtimer_delay_ms(1000); + } + } + + p = (uint8_t *)tmp_keyy; + + for(i = 0; i < 32; i++) + { + if(ecdsa_public_keyy[i] != p[i]) + { + printf("ECDSA Compare fail\r\n"); + bflb_mtimer_delay_ms(1000); + } + } + +#endif + + time = (unsigned int)bflb_mtimer_get_time_ms(); + + if (0 != bflb_sec_ecdsa_sign(&ecdsa_handle, (uint32_t *)ecdsa_k, (uint32_t *)ecdsa_hash, sizeof(ecdsa_hash) / 4, tmp_keyx, tmp_keyy)) { + printf("Sign Fail\r\n"); + } + + printf("ECDSA sign time=%dms\r\n", (unsigned int)bflb_mtimer_get_time_ms() - time); + + printf("Check sign\r\n"); + p = (uint8_t *)tmp_keyx; + + for (i = 0; i < 32; i++) { + if (ecdsa_r[i] != p[i]) { + printf("ECDSA Compare fail\r\n"); + bflb_mtimer_delay_ms(1000); + } + } + + p = (uint8_t *)tmp_keyy; + + for (i = 0; i < 32; i++) { + if (ecdsa_s[i] != p[i]) { + printf("ECDSA Compare fail\r\n"); + bflb_mtimer_delay_ms(1000); + } + } + + time = (unsigned int)bflb_mtimer_get_time_ms(); + + if (0 != bflb_sec_ecdsa_verify(&ecdsa_handle, (uint32_t *)ecdsa_hash, sizeof(ecdsa_hash) / 4, tmp_keyx, tmp_keyy)) { + printf("Verify Fail\r\n"); + } else { + printf("ECDSA verify time=%dms\r\n", (unsigned int)bflb_mtimer_get_time_ms() - time); + printf("Verify Success\r\n"); + } + + while (1) { + bflb_mtimer_delay_ms(2000); + } +} \ No newline at end of file diff --git a/examples/peripherals/sec_eng/sec_eng_ecdsa/proj.conf b/examples/peripherals/sec_eng/sec_eng_ecdsa/proj.conf new file mode 100644 index 00000000..13320d67 --- /dev/null +++ b/examples/peripherals/sec_eng/sec_eng_ecdsa/proj.conf @@ -0,0 +1 @@ +#set(CONFIG_XXX 1) \ No newline at end of file diff --git a/examples/peripherals/sec_eng/sec_eng_sha/main.c b/examples/peripherals/sec_eng/sec_eng_sha/main.c index 5c16940e..c1d29682 100644 --- a/examples/peripherals/sec_eng/sec_eng_sha/main.c +++ b/examples/peripherals/sec_eng/sec_eng_sha/main.c @@ -156,6 +156,8 @@ int main(void) sha = bflb_device_get_by_name("sha"); + bflb_group0_request_sha_access(sha); + bflb_sha_init(sha, SHA_MODE_SHA1); for (uint8_t i = 0; i < 3; i++) { @@ -247,6 +249,7 @@ int main(void) bflb_data_compare(sha512_test_sum[i + 3], sha_output_buf, 20); } printf("sha512 success\r\n"); + bflb_group0_release_sha_access(sha); while (1) { bflb_mtimer_delay_ms(2000); } diff --git a/examples/peripherals/sec_eng/sec_eng_sha_link/CMakeLists.txt b/examples/peripherals/sec_eng/sec_eng_sha_link/CMakeLists.txt new file mode 100644 index 00000000..04d7ac85 --- /dev/null +++ b/examples/peripherals/sec_eng/sec_eng_sha_link/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.15) + +include(proj.conf) + +find_package(bouffalo_sdk REQUIRED HINTS $ENV{BL_SDK_BASE}) + +sdk_set_main_file(main.c) + +project(sec_eng_sha_link) diff --git a/examples/peripherals/sec_eng/sec_eng_sha_link/Makefile b/examples/peripherals/sec_eng/sec_eng_sha_link/Makefile new file mode 100644 index 00000000..44367c02 --- /dev/null +++ b/examples/peripherals/sec_eng/sec_eng_sha_link/Makefile @@ -0,0 +1,13 @@ +SDK_DEMO_PATH ?= . +BL_SDK_BASE ?= $(SDK_DEMO_PATH)/../../../.. + +export BL_SDK_BASE + +CHIP ?= bl616 +BOARD ?= bl616dk +CROSS_COMPILE ?= riscv64-unknown-elf- + +# add custom cmake definition +#cmake_definition+=-Dxxx=sss + +include $(BL_SDK_BASE)/project.build diff --git a/examples/peripherals/sec_eng/sec_eng_sha_link/main.c b/examples/peripherals/sec_eng/sec_eng_sha_link/main.c new file mode 100644 index 00000000..bf84e318 --- /dev/null +++ b/examples/peripherals/sec_eng/sec_eng_sha_link/main.c @@ -0,0 +1,123 @@ +#include "bflb_mtimer.h" +#include "bflb_sec_sha.h" +#include "board.h" + +const uint8_t sha256_testbuf[2][104 + 1] = { + { "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" }, + { "zyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcba" } +}; + +const uint8_t sha256_testsum[2][32] = { + { 0x94, 0x1a, 0xc3, 0x78, 0x68, 0x2e, 0x3d, 0xc6, + 0x62, 0x75, 0xdd, 0x49, 0xd5, 0xfb, 0x09, 0x97, + 0x87, 0x54, 0xec, 0xf4, 0x23, 0x1d, 0x18, 0xd3, + 0x03, 0x26, 0xfa, 0x51, 0x96, 0x26, 0x48, 0xec }, + { 0x0a, 0x9e, 0xfa, 0x03, 0x71, 0xcb, 0xf6, 0x78, + 0xe2, 0xd9, 0x59, 0x90, 0xa0, 0x22, 0x29, 0xe7, + 0x00, 0x78, 0x8d, 0x4a, 0x55, 0xc7, 0x8c, 0x46, + 0xab, 0xac, 0xe1, 0x40, 0x27, 0x6b, 0x7e, 0x5f } +}; + +const uint8_t sha512_testbuf[2][208 + 1] = { + { "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" + "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" }, + { "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" + "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" } +}; + +const uint8_t sha512_testsum[2][128] = { + { 0xa8, 0xf0, 0x5c, 0x44, 0x2c, 0x9f, 0xe7, 0xad, + 0xdb, 0x7b, 0xec, 0xc4, 0x13, 0xe3, 0x5b, 0xf4, + 0x81, 0x86, 0x5c, 0x8a, 0xd7, 0x85, 0xb0, 0xd0, + 0x17, 0x60, 0x40, 0x22, 0xca, 0xfd, 0xd1, 0x4e, + 0xb5, 0x82, 0xb8, 0xa0, 0xa6, 0x78, 0x59, 0x72, + 0xc9, 0xf9, 0x9c, 0x31, 0x9c, 0x7b, 0xf0, 0x27, + 0xb6, 0x28, 0x16, 0x7a, 0x0b, 0xad, 0xf6, 0xd5, + 0x84, 0x21, 0xc5, 0x75, 0x9c, 0x85, 0xc3, 0x37 }, + + { 0xa8, 0xf0, 0x5c, 0x44, 0x2c, 0x9f, 0xe7, 0xad, + 0xdb, 0x7b, 0xec, 0xc4, 0x13, 0xe3, 0x5b, 0xf4, + 0x81, 0x86, 0x5c, 0x8a, 0xd7, 0x85, 0xb0, 0xd0, + 0x17, 0x60, 0x40, 0x22, 0xca, 0xfd, 0xd1, 0x4e, + 0xb5, 0x82, 0xb8, 0xa0, 0xa6, 0x78, 0x59, 0x72, + 0xc9, 0xf9, 0x9c, 0x31, 0x9c, 0x7b, 0xf0, 0x27, + 0xb6, 0x28, 0x16, 0x7a, 0x0b, 0xad, 0xf6, 0xd5, + 0x84, 0x21, 0xc5, 0x75, 0x9c, 0x85, 0xc3, 0x37 } +}; + +static struct bflb_sha_link_s sha256_link = { + .sha_mode = SHA_MODE_SHA256, /* Sha-256 */ + .sha_newhash_dis = 0, /* New hash */ + .sha_intclr = 0, /* Not clear interrupt */ + .sha_intset = 0, /* Not set interrupt */ + .sha_mode_ext = 0, + .sha_msglen = 1, /* Number of 512-bit block */ + .sha_srcaddr = 0, /* Message source address */ + { 0 } /* Result of SHA */ +}; + +static struct bflb_sha_link_s sha512_link = { + .sha_mode = SHA_MODE_SHA512, /* Sha-512 */ + .sha_newhash_dis = 0, /* New hash */ + .sha_intclr = 0, /* Not clear interrupt */ + .sha_intset = 0, /* Not set interrupt */ + .sha_mode_ext = 0, + .sha_msglen = 1, /* Number of 512-bit block */ + .sha_srcaddr = 0, /* Message source address */ + { 0 } /* Result of SHA */ +}; + +ATTR_NOCACHE_RAM_SECTION __attribute__((aligned(32))) uint8_t sha_input_buf[1000]; + +uint8_t sha_output_buf[128]; + +ATTR_NOCACHE_RAM_SECTION struct bflb_sha256_ctx_s ctx_sha256; +ATTR_NOCACHE_RAM_SECTION struct bflb_sha512_ctx_s ctx_sha512; + +static uint32_t bflb_data_compare(const uint8_t *expected, uint8_t *input, uint32_t len) +{ + int i = 0; + for (i = 0; i < len; i++) { + if (input[i] != expected[i]) { + printf("Compare fail at %d,input %02x, but expect %02x\r\n", i, input[i], expected[i]); + while (1) { + } + } + } + + return 0; +} + +int main(void) +{ + board_init(); + + struct bflb_device_s *sha; + + sha = bflb_device_get_by_name("sha"); + + bflb_group0_request_sha_access(sha); + + bflb_sha_link_init(sha); + + bflb_sha256_link_start(sha, &ctx_sha256); + memcpy(sha_input_buf, sha256_testbuf[0], 104); + bflb_sha256_link_update(sha, &ctx_sha256, (uint32_t)&sha256_link, sha_input_buf, 80); + bflb_sha256_link_update(sha, &ctx_sha256, (uint32_t)&sha256_link, &sha_input_buf[80], 104 - 80); + bflb_sha256_link_finish(sha, &ctx_sha256, (uint32_t)&sha256_link, sha_output_buf); + bflb_data_compare(sha256_testsum[0], sha_output_buf, 32); + printf("sha256 link success\r\n"); + + bflb_sha512_link_start(sha, &ctx_sha512); + memcpy(sha_input_buf, sha512_testbuf[0], 208); + bflb_sha512_link_update(sha, &ctx_sha512, (uint32_t)&sha512_link, sha_input_buf, 160); + bflb_sha512_link_update(sha, &ctx_sha512, (uint32_t)&sha512_link, &sha_input_buf[160], 208 - 80); + bflb_sha512_link_finish(sha, &ctx_sha512, (uint32_t)&sha512_link, sha_output_buf); + bflb_data_compare(sha512_testsum[0], sha_output_buf, 64); + printf("sha512 link success\r\n"); + + bflb_group0_release_sha_access(sha); + while (1) { + bflb_mtimer_delay_ms(2000); + } +} \ No newline at end of file diff --git a/examples/peripherals/sec_eng/sec_eng_sha_link/proj.conf b/examples/peripherals/sec_eng/sec_eng_sha_link/proj.conf new file mode 100644 index 00000000..13320d67 --- /dev/null +++ b/examples/peripherals/sec_eng/sec_eng_sha_link/proj.conf @@ -0,0 +1 @@ +#set(CONFIG_XXX 1) \ No newline at end of file diff --git a/examples/peripherals/timer/main.c b/examples/peripherals/timer/main.c deleted file mode 100644 index ff83f80a..00000000 --- a/examples/peripherals/timer/main.c +++ /dev/null @@ -1,53 +0,0 @@ -#include "bflb_mtimer.h" -#include "bflb_timer.h" -#include "board.h" - -#define TEST_TIMER_COMP_ID TIMER_COMP_ID_0 - -struct bflb_device_s *timer0; - -void timer0_isr(int irq, void *arg) -{ - bool status = bflb_timer_get_compint_status(timer0, TIMER_COMP_ID_0); - if (status) { - printf("timer0 comp0 trigger\r\n"); - bflb_timer_compint_clear(timer0, TIMER_COMP_ID_0); - } - status = bflb_timer_get_compint_status(timer0, TIMER_COMP_ID_1); - if (status) { - printf("timer0 comp1 trigger\r\n"); - bflb_timer_compint_clear(timer0, TIMER_COMP_ID_1); - } - status = bflb_timer_get_compint_status(timer0, TIMER_COMP_ID_2); - if (status) { - printf("timer0 comp2 trigger\r\n"); - bflb_timer_compint_clear(timer0, TIMER_COMP_ID_2); - } -} - -int main(void) -{ - board_init(); - - /* timer clk = XCLK/(div + 1 )*/ - struct bflb_timer_config_s cfg; - cfg.counter_mode = TIMER_COUNTER_MODE_PROLOAD; - cfg.clock_source = BFLB_SYSTEM_XCLK; - cfg.clock_div = 39; /* for bl616/bl808/bl606p is 39, for bl702 is 31 */ - cfg.trigger_comp_id = TEST_TIMER_COMP_ID; - cfg.comp0_val = 1000000; - cfg.comp1_val = 2000000; - cfg.comp2_val = 3000000; - cfg.preload_val = 0; - - timer0 = bflb_device_get_by_name("timer0"); - - bflb_timer_init(timer0, &cfg); - bflb_irq_attach(timer0->irq_num, timer0_isr, timer0); - bflb_irq_enable(timer0->irq_num); - bflb_timer_start(timer0); - while (1) { - printf("helloworld\r\n"); - bflb_mtimer_delay_ms(1500); - } -} diff --git a/examples/peripherals/timer/timer_int/CMakeLists.txt b/examples/peripherals/timer/timer_int/CMakeLists.txt new file mode 100644 index 00000000..a6bae051 --- /dev/null +++ b/examples/peripherals/timer/timer_int/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.15) + +include(proj.conf) + +find_package(bouffalo_sdk REQUIRED HINTS $ENV{BL_SDK_BASE}) + +sdk_set_main_file(main.c) + +project(timer_int) diff --git a/examples/peripherals/timer/timer_int/Makefile b/examples/peripherals/timer/timer_int/Makefile new file mode 100644 index 00000000..44367c02 --- /dev/null +++ b/examples/peripherals/timer/timer_int/Makefile @@ -0,0 +1,13 @@ +SDK_DEMO_PATH ?= . +BL_SDK_BASE ?= $(SDK_DEMO_PATH)/../../../.. + +export BL_SDK_BASE + +CHIP ?= bl616 +BOARD ?= bl616dk +CROSS_COMPILE ?= riscv64-unknown-elf- + +# add custom cmake definition +#cmake_definition+=-Dxxx=sss + +include $(BL_SDK_BASE)/project.build diff --git a/examples/peripherals/timer/timer_int/main.c b/examples/peripherals/timer/timer_int/main.c new file mode 100644 index 00000000..3bc57ef6 --- /dev/null +++ b/examples/peripherals/timer/timer_int/main.c @@ -0,0 +1,93 @@ +#include "bflb_mtimer.h" +#include "bflb_timer.h" +#include "board.h" +#define TEST_TIMER_COMP_ID TIMER_COMP_ID_2 + +struct bflb_device_s *timer0; +struct bflb_device_s *timer1; + +void timer0_isr(int irq, void *arg) +{ + bool status = bflb_timer_get_compint_status(timer0, TIMER_COMP_ID_0); + if (status) { + printf("timer0 comp0 trigger\r\n"); + bflb_timer_compint_clear(timer0, TIMER_COMP_ID_0); + } + status = bflb_timer_get_compint_status(timer0, TIMER_COMP_ID_1); + if (status) { + printf("timer0 comp1 trigger\r\n"); + bflb_timer_compint_clear(timer0, TIMER_COMP_ID_1); + } + status = bflb_timer_get_compint_status(timer0, TIMER_COMP_ID_2); + if (status) { + printf("timer0 comp2 trigger\r\n"); + bflb_timer_compint_clear(timer0, TIMER_COMP_ID_2); + } +} + +void timer1_isr(int irq, void *arg) +{ + bool status = bflb_timer_get_compint_status(timer1, TIMER_COMP_ID_0); + if (status) { + printf("timer1 comp0 trigger\r\n"); + bflb_timer_compint_clear(timer1, TIMER_COMP_ID_0); + } + status = bflb_timer_get_compint_status(timer1, TIMER_COMP_ID_1); + if (status) { + printf("timer1 comp1 trigger\r\n"); + bflb_timer_compint_clear(timer1, TIMER_COMP_ID_1); + } + status = bflb_timer_get_compint_status(timer1, TIMER_COMP_ID_2); + if (status) { + printf("timer1 comp2 trigger\r\n"); + bflb_timer_compint_clear(timer1, TIMER_COMP_ID_2); + } +} + +int main(void) +{ + board_init(); + printf("Timer basic test\n"); + + /* timer clk = XCLK/(div + 1 )*/ + struct bflb_timer_config_s cfg0; + cfg0.counter_mode = TIMER_COUNTER_MODE_PROLOAD; /* preload when match occur */ + cfg0.clock_source = TIMER_CLKSRC_XTAL; + cfg0.clock_div = 0; /* for bl616/bl808/bl606p is 39, for bl702 is 31 */ + cfg0.trigger_comp_id = TEST_TIMER_COMP_ID; + cfg0.comp0_val = 230000; /* match value 0 */ + cfg0.comp1_val = 260000; /* match value 1 */ + cfg0.comp2_val = 290000; /* match value 2 */ + cfg0.preload_val = 0; /* preload value */ + + struct bflb_timer_config_s cfg1; + cfg1.counter_mode = TIMER_COUNTER_MODE_PROLOAD; + cfg1.clock_source = TIMER_CLKSRC_XTAL; + cfg1.clock_div = 0; /* for bl616/bl808/bl606p is 39, for bl702 is 31 */ + cfg1.trigger_comp_id = TEST_TIMER_COMP_ID; + cfg1.comp0_val = 330000; /* match value 0 */ + cfg1.comp1_val = 360000; /* match value 1 */ + cfg1.comp2_val = 390000; /* match value 2 */ + cfg1.preload_val = 0; /* preload value */ + + timer0 = bflb_device_get_by_name("timer0"); + timer1 = bflb_device_get_by_name("timer1"); + + /* Timer init with default configuration */ + bflb_timer_init(timer0, &cfg0); + bflb_timer_init(timer1, &cfg1); + + bflb_irq_attach(timer0->irq_num, timer0_isr, timer0); + bflb_irq_attach(timer1->irq_num, timer1_isr, timer1); + bflb_irq_enable(timer0->irq_num); + bflb_irq_enable(timer1->irq_num); + + /* Enable timer */ + bflb_timer_start(timer0); + bflb_timer_start(timer1); + + printf("case success.\r\n"); + while (1) { + bflb_mtimer_delay_ms(1500); + } +} diff --git a/examples/peripherals/timer/timer_int/proj.conf b/examples/peripherals/timer/timer_int/proj.conf new file mode 100644 index 00000000..13320d67 --- /dev/null +++ b/examples/peripherals/timer/timer_int/proj.conf @@ -0,0 +1 @@ +#set(CONFIG_XXX 1) \ No newline at end of file diff --git a/examples/peripherals/uart/uart_auto_baudrate/main.c b/examples/peripherals/uart/uart_auto_baudrate/main.c index c794e9d6..30a273e9 100644 --- a/examples/peripherals/uart/uart_auto_baudrate/main.c +++ b/examples/peripherals/uart/uart_auto_baudrate/main.c @@ -5,28 +5,25 @@ struct bflb_device_s *uart1; -static uint32_t uart_txbuf[3]; - void uart_isr(int irq, void *arg) { uint32_t intstatus = bflb_uart_get_intstatus(uart1); + int ret; + uint32_t baudrate; if (intstatus & UART_INTSTS_RX_AD5) { - uart_txbuf[0] = UART_AUTO_BAUD_0X55; - bflb_uart_feature_control(uart1, UART_CMD_GET_AUTO_BAUD, (uint32_t)uart_txbuf); - uint32_t baudrate = 40000000 / (uart_txbuf[1] + 1); + ret = bflb_uart_feature_control(uart1, UART_CMD_GET_AUTO_BAUD, UART_AUTO_BAUD_0X55); + baudrate = 40000000 / (ret + 1); printf("Detected baudrate by 0x55 is %d\r\n", baudrate); } bflb_uart_int_clear(uart1, UART_INTCLR_RX_AD5); if (intstatus & UART_INTSTS_RX_ADS) { - uart_txbuf[0] = UART_AUTO_BAUD_START; - bflb_uart_feature_control(uart1, UART_CMD_GET_AUTO_BAUD, (uint32_t)uart_txbuf); - uint32_t baudrate = 40000000 / (uart_txbuf[1] + 1); + ret = bflb_uart_feature_control(uart1, UART_CMD_GET_AUTO_BAUD, UART_AUTO_BAUD_START); + baudrate = 40000000 / (ret + 1); printf("Detected baudrate by startbit is %d\r\n", baudrate); } bflb_uart_int_clear(uart1, UART_INTCLR_RX_ADS); - } int main(void) @@ -48,9 +45,11 @@ int main(void) bflb_uart_init(uart1, &cfg); bflb_uart_feature_control(uart1, UART_CMD_SET_AUTO_BAUD, 1); - bflb_uart_feature_control(uart1, UART_CMD_SET_ABR_PW_VALUE, 3); + bflb_uart_feature_control(uart1, UART_CMD_SET_ABR_ALLOWABLE_ERROR, 3); bflb_irq_attach(uart1->irq_num, uart_isr, uart1); bflb_irq_enable(uart1->irq_num); + while (1) { + } } diff --git a/examples/peripherals/uart/uart_cts_rts/main.c b/examples/peripherals/uart/uart_cts_rts/main.c index 8dbc65b1..b3b5bf39 100644 --- a/examples/peripherals/uart/uart_cts_rts/main.c +++ b/examples/peripherals/uart/uart_cts_rts/main.c @@ -37,7 +37,7 @@ int main(void) cfg.data_bits = UART_DATA_BITS_8; cfg.stop_bits = UART_STOP_BITS_1; cfg.parity = UART_PARITY_NONE; - cfg.flow_ctrl = UART_FLOWCTRL_RTS; + cfg.flow_ctrl = 0; cfg.tx_fifo_threshold = 7; cfg.rx_fifo_threshold = 7; bflb_uart_init(uart1, &cfg); @@ -46,8 +46,9 @@ int main(void) bflb_irq_attach(uart1->irq_num, uart_isr, uart1); bflb_irq_enable(uart1->irq_num); + bflb_uart_feature_control(uart1, UART_CMD_SET_SW_RTS_CONTROL, true); + bflb_uart_feature_control(uart1, UART_CMD_SET_RTS_VALUE, 0); while (1) { - printf("helloworld\r\n"); bflb_mtimer_delay_ms(2000); } } diff --git a/examples/peripherals/uart/uart_dma/main.c b/examples/peripherals/uart/uart_dma/main.c index 2c1a0b3b..0f5c2fda 100644 --- a/examples/peripherals/uart/uart_dma/main.c +++ b/examples/peripherals/uart/uart_dma/main.c @@ -130,7 +130,6 @@ int main(void) printf("receive data:%02x\r\n", receive_buffer[i]); } while (1) { - printf("helloworld\r\n"); bflb_mtimer_delay_ms(2000); } } diff --git a/examples/peripherals/uart/uart_fifo_interrupt/main.c b/examples/peripherals/uart/uart_fifo_interrupt/main.c index c88889fa..39e4fe55 100644 --- a/examples/peripherals/uart/uart_fifo_interrupt/main.c +++ b/examples/peripherals/uart/uart_fifo_interrupt/main.c @@ -62,7 +62,6 @@ int main(void) bflb_irq_enable(uart1->irq_num); while (1) { - printf("helloworld\r\n"); bflb_mtimer_delay_ms(2000); } } diff --git a/examples/peripherals/uart/uart_rs485/main.c b/examples/peripherals/uart/uart_rs485/main.c index fe77bc42..96b1ec86 100644 --- a/examples/peripherals/uart/uart_rs485/main.c +++ b/examples/peripherals/uart/uart_rs485/main.c @@ -47,7 +47,7 @@ int main(void) bflb_uart_init(uart1, &cfg); bflb_uart_feature_control(uart1, UART_CMD_SET_TX_RS485_EN, 1); - bflb_uart_feature_control(uart1, UART_CMD_SET_TX_RS485_POL, 1); + bflb_uart_feature_control(uart1, UART_CMD_SET_TX_RS485_POLARITY, 1); for (uint8_t i = 0; i < 128; i++) { bflb_uart_putchar(uart1, uart_txbuf[i]); @@ -58,7 +58,6 @@ int main(void) bflb_irq_enable(uart1->irq_num); while (1) { - printf("helloworld\r\n"); bflb_mtimer_delay_ms(2000); } } diff --git a/examples/peripherals/wdg/wdg_int/main.c b/examples/peripherals/wdg/wdg_int/main.c index 16f57926..f685ad83 100644 --- a/examples/peripherals/wdg/wdg_int/main.c +++ b/examples/peripherals/wdg/wdg_int/main.c @@ -17,7 +17,7 @@ int main(void) printf("Watchdog interrupt test\r\n"); struct bflb_wdg_config_s wdg_cfg; - wdg_cfg.clock_source = BFLB_SYSTEM_32K_CLK; + wdg_cfg.clock_source = WDG_CLKSRC_32K; wdg_cfg.clock_div = 0; wdg_cfg.comp_val = 64000; wdg_cfg.mode = WDG_MODE_INTERRUPT; diff --git a/examples/peripherals/wdg/wdg_reset/main.c b/examples/peripherals/wdg/wdg_reset/main.c index d43d3732..0c270bee 100644 --- a/examples/peripherals/wdg/wdg_reset/main.c +++ b/examples/peripherals/wdg/wdg_reset/main.c @@ -11,7 +11,7 @@ int main(void) printf("Watchdog interrupt test\r\n"); struct bflb_wdg_config_s wdg_cfg; - wdg_cfg.clock_source = BFLB_SYSTEM_32K_CLK; + wdg_cfg.clock_source = WDG_CLKSRC_32K; wdg_cfg.clock_div = 0; wdg_cfg.comp_val = 64000; wdg_cfg.mode = WDG_MODE_RESET;