commit 685084c40aefdbcd812ba83e4fbb334c76a6dd03 Author: latyas Date: Thu Sep 13 22:06:11 2018 +0800 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8e16bd0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +autom4te.cache +build +build_i +config.log +config.status +Makefile +.DS_Store +!/regression/Makefile +.vs +.vscode +CMakeSettings.json +.idea +*.tar +*.tar.* +cmake-build-* \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..3f4c011 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,7 @@ +Changelog for Kendryte K210 +====== + +## 0.1.0 + +Kendryte K210 first SDK with FreeRTOS, have fun. + diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..26cd1f9 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,26 @@ +### This file is used for build example projects. + +# set this will supress some warnings +set(BUILDING_SDK "yes" CACHE INTERNAL "") + +# basic config +if (NOT PROJ) + message(FATAL_ERROR "PROJ must be set. e.g. -DPROJ=hello_world") +endif () +cmake_minimum_required(VERSION 3.0) +include(./cmake/common.cmake) +project(${PROJ}) + +# config self use headers +include(./cmake/macros.internal.cmake) +header_directories(${SDK_ROOT}/lib) +# build library first +add_subdirectory(lib) + +# TODO +#add_subdirectory(third_party) + +# compile project +add_source_files(src/${PROJ}/*.c src/${PROJ}/*.s src/${PROJ}/*.S src/${PROJ}/*.cpp) +include(./cmake/executable.cmake) + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e2c4705 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018 Canaan Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..e7cff90 --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ +Kendryte K210 standalone SDK +====== + +This SDK is for Kendryte K210 without OS support. +If you have any questions, please be free to contact us. + +# Usage + +If you want to start a new project, for instance, `hello_world`, you only need to: + +`mkdir` your project in `src/`, `cd src && mkdir hello_world`, then put your codes in it, and build it. + +```shell +mkdir build && cd build +cmake .. -DPROJ= -DTOOLCHAIN=/opt/riscv-toolchain/bin && make +``` + +You will get 2 key files, `hello_world` and `hello_world.bin`. + +1. If you are using JLink to run or debug your program, use `hello_world` +2. If you want to flash it in UOG, using `hello_world.bin`, then using flash-tool(s) burn .bin to your flash. + +This is very important, don't make a mistake in files. diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt new file mode 100644 index 0000000..64f2708 --- /dev/null +++ b/cmake/CMakeLists.txt @@ -0,0 +1,44 @@ +### This file is used for build library standalone. + +# set this will supress some warnings +set(BUILDING_SDK "yes" CACHE INTERNAL "") + +# basic config +cmake_minimum_required(VERSION 3.0) +include(./common.cmake) +project(kendryte) + +# config self use headers +include(./macros.internal.cmake) +header_directories(${SDK_ROOT}/lib) + +# include lib make file +include(../lib/CMakeLists.txt) + +# find headers files to INSTALL +file(GLOB_RECURSE LIB_HEADERS + "../lib/*.h" + "../lib/*.hpp" + ) +set_target_properties(kendryte PROPERTIES PUBLIC_HEADER "${LIB_HEADERS}") + +# copy .a file and headers +install(TARGETS kendryte + EXPORT kendryte + ARCHIVE + DESTINATION ${CMAKE_BINARY_DIR}/archive + PUBLIC_HEADER DESTINATION ${CMAKE_BINARY_DIR}/archive/include + ) + +# copy utils files +install(DIRECTORY + ../lds + ../utils + ../cmake + DESTINATION ${CMAKE_BINARY_DIR}/archive + PATTERN "*internal*" EXCLUDE + PATTERN "CMakeLists.txt" EXCLUDE + ) + +# show information +include(./dump-config.cmake) diff --git a/cmake/README.md b/cmake/README.md new file mode 100644 index 0000000..5e5bc8b --- /dev/null +++ b/cmake/README.md @@ -0,0 +1,3 @@ +prepend `common.cmake` before + +append `executable.cmake` after diff --git a/cmake/common.cmake b/cmake/common.cmake new file mode 100644 index 0000000..e9ba31a --- /dev/null +++ b/cmake/common.cmake @@ -0,0 +1,34 @@ +cmake_minimum_required(VERSION 3.0) + +include(${CMAKE_CURRENT_LIST_DIR}/macros.cmake) + +global_set(CMAKE_C_COMPILER_WORKS 1) +global_set(CMAKE_CXX_COMPILER_WORKS 1) + +global_set(CMAKE_SYSTEM_NAME "Generic") +if (NOT CMAKE_BUILD_TYPE) + global_set(CMAKE_BUILD_TYPE Debug) +else () + if ((NOT CMAKE_BUILD_TYPE STREQUAL "Debug") AND (NOT CMAKE_BUILD_TYPE STREQUAL "Release")) + message(FATAL_ERROR "CMAKE_BUILD_TYPE must either be Debug or Release instead of ${CMAKE_BUILD_TYPE}") + endif () +endif () + +# - Debug & Release +IF (CMAKE_BUILD_TYPE STREQUAL Debug) + add_definitions(-DDEBUG=1) +ENDIF () + +# definitions in macros +add_definitions(-DCONFIG_LOG_LEVEL=LOG_VERBOSE -DCONFIG_LOG_ENABLE -DCONFIG_LOG_COLORS -DLOG_KERNEL -D__riscv64 -DFPGA_PLL) + +if (NOT SDK_ROOT) + get_filename_component(_SDK_ROOT ${CMAKE_CURRENT_LIST_DIR} DIRECTORY) + global_set(SDK_ROOT ${_SDK_ROOT}) +endif () + +include(${CMAKE_CURRENT_LIST_DIR}/toolchain.cmake) + +include(${CMAKE_CURRENT_LIST_DIR}/compile-flags.cmake) + +include(${CMAKE_CURRENT_LIST_DIR}/fix-9985.cmake) diff --git a/cmake/compile-flags.cmake b/cmake/compile-flags.cmake new file mode 100644 index 0000000..b2f75e9 --- /dev/null +++ b/cmake/compile-flags.cmake @@ -0,0 +1,53 @@ +add_compile_flags(LD + -nostartfiles + -static + -Wl,--gc-sections + -Wl,-static + -Wl,--start-group + -Wl,--whole-archive + -Wl,--no-whole-archive + -Wl,--end-group + -Wl,-EL + -T ${SDK_ROOT}/lds/kendryte.ld + ) + +# C Flags Settings +add_compile_flags(BOTH + -mcmodel=medany + -fno-common + -ffunction-sections + -fdata-sections + -fstrict-volatile-bitfields + -O0 + -ggdb + ) + +add_compile_flags(C -std=gnu11) +add_compile_flags(CXX -std=gnu++17) + +if (BUILDING_SDK) + add_compile_flags(BOTH + -Wall + -Werror=all + -Wno-error=unused-function + -Wno-error=unused-but-set-variable + -Wno-error=unused-variable + -Wno-error=deprecated-declarations + -Wextra + -Werror=frame-larger-than=65536 + -Wno-unused-parameter + -Wno-sign-compare + -Wno-error=missing-braces + -Wno-error=return-type + -Wno-error=pointer-sign + -Wno-missing-braces + -Wno-pointer-to-int-cast + -Wno-strict-aliasing + -Wno-implicit-fallthrough + ) + + add_compile_flags(C -Wno-old-style-declaration) +else () + add_compile_flags(BOTH -L${SDK_ROOT}/include/) +endif () + diff --git a/cmake/dump-config.cmake b/cmake/dump-config.cmake new file mode 100644 index 0000000..d843858 --- /dev/null +++ b/cmake/dump-config.cmake @@ -0,0 +1,13 @@ +message("") +message("Project: ${PROJECT_NAME}") +message(" TOOLCHAIN=${TOOLCHAIN}") +message(" KENDRYTE IDE=${KENDRYTE_IDE}") +message("") +message(" CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}") +message(" CMAKE_C_COMPILER=${CMAKE_C_COMPILER}") +message(" CMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}") +message(" CMAKE_LINKER=${CMAKE_LINKER}") +message(" CMAKE_OBJCOPY=${CMAKE_OBJCOPY}") +message("Makefile created.") +message("") +message("") diff --git a/cmake/executable.cmake b/cmake/executable.cmake new file mode 100644 index 0000000..37d8073 --- /dev/null +++ b/cmake/executable.cmake @@ -0,0 +1,36 @@ +if (NOT BUILDING_SDK) + add_library(kendryte STATIC IMPORTED) + set_property(TARGET kendryte PROPERTY IMPORTED_LOCATION ${SDK_ROOT}/libmaix.a) + include_directories(${SDK_ROOT}/include/) +endif () + +add_executable(${PROJECT_NAME} ${SOURCE_FILES}) +# add_dependencies(${PROJECT_NAME} kendryte) # TODO: third_party +# target_link_libraries(${PROJECT_NAME} kendryte) # TODO: third_party +# link_directories(${CMAKE_BINARY_DIR}) + +set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE C) + +target_link_libraries(${PROJECT_NAME} + -Wl,--start-group + gcc m c kendryte + -Wl,--end-group + ) + +IF(SUFFIX) + SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES SUFFIX ${SUFFIX}) +ENDIF() + +#message("CMAKE_OBJCOPY=${CMAKE_OBJCOPY}") + +# Build target +add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_OBJCOPY} --output-format=binary ${CMAKE_BINARY_DIR}/${PROJECT_NAME}${SUFFIX} ${CMAKE_BINARY_DIR}/${PROJECT_NAME}.bin + DEPENDS ${PROJECT_NAME} + COMMENT "Generating .bin file ...") + + +add_custom_target(firmware DEPENDS ${PROJECT_NAME}.firmware.bin) + +# show information +include(${CMAKE_CURRENT_LIST_DIR}/dump-config.cmake) diff --git a/cmake/fix-9985.cmake b/cmake/fix-9985.cmake new file mode 100644 index 0000000..4402bd3 --- /dev/null +++ b/cmake/fix-9985.cmake @@ -0,0 +1,3 @@ +### http://www.cmake.org/Bug/view.php?id=9985 +string(REPLACE "-rdynamic" "" CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "${CMAKE_SHARED_LIBRARY_LINK_C_FLAGS}") +string(REPLACE "-rdynamic" "" CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "${CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS}") diff --git a/cmake/macros.cmake b/cmake/macros.cmake new file mode 100644 index 0000000..9ef8728 --- /dev/null +++ b/cmake/macros.cmake @@ -0,0 +1,65 @@ +macro(global_set Name Value) + # message("set ${Name} to " ${ARGN}) + set(${Name} "${Value}" CACHE STRING "NoDesc" FORCE) +endmacro() + +macro(condition_set Name Value) + if (NOT ${Name}) + global_set(${Name} ${Value}) + else () + # message("exists ${Name} is " ${ARGN}) + endif () +endmacro() + + +set(SOURCE_FILES "" CACHE STRING "Source Files" FORCE) +macro(add_source_files) + # message(" + add_source_files ${ARGN}") + file(GLOB_RECURSE newlist ${ARGN}) + + foreach (filepath ${newlist}) + string(FIND ${filepath} ${CMAKE_BINARY_DIR} found) + if (NOT found EQUAL 0) + set(SOURCE_FILES ${SOURCE_FILES} ${filepath} CACHE STRING "Source Files" FORCE) + endif () + endforeach () +endmacro() + +function(JOIN VALUES GLUE OUTPUT) + string(REGEX REPLACE "([^\\]|^);" "\\1${GLUE}" _TMP_STR "${VALUES}") + string(REGEX REPLACE "[\\](.)" "\\1" _TMP_STR "${_TMP_STR}") #fixes escaping + set(${OUTPUT} "${_TMP_STR}" PARENT_SCOPE) +endfunction() + +global_set(LDFLAGS "") +global_set(CMAKE_EXE_LINKER_FLAGS "") +global_set(CMAKE_SHARED_LINKER_FLAGS "") +global_set(CMAKE_MODULE_LINKER_FLAGS "") + +macro(add_compile_flags WHERE) + JOIN("${ARGN}" " " STRING_ARGS) + if (${WHERE} STREQUAL C) + global_set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${STRING_ARGS}") + + elseif (${WHERE} STREQUAL CXX) + global_set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${STRING_ARGS}") + + elseif (${WHERE} STREQUAL LD) + global_set(LDFLAGS "${LDFLAGS} ${STRING_ARGS}") + global_set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${STRING_ARGS}") + global_set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${STRING_ARGS}") + global_set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${STRING_ARGS}") + + elseif (${WHERE} STREQUAL BOTH) + add_compile_flags(C ${ARGN}) + add_compile_flags(CXX ${ARGN}) + + elseif (${WHERE} STREQUAL ALL) + add_compile_flags(C ${ARGN}) + add_compile_flags(CXX ${ARGN}) + add_compile_flags(LD ${ARGN}) + + else () + message(FATAL_ERROR "add_compile_flags - only support: C, CXX, BOTH, LD, ALL") + endif () +endmacro() diff --git a/cmake/macros.internal.cmake b/cmake/macros.internal.cmake new file mode 100644 index 0000000..a38b56d --- /dev/null +++ b/cmake/macros.internal.cmake @@ -0,0 +1,12 @@ +# Add lib headers +macro(header_directories parent) + file(GLOB_RECURSE newList ${parent}/*.h) + set(dir_list "") + foreach (file_path ${newList}) + get_filename_component(dir_path ${file_path} DIRECTORY) + set(dir_list ${dir_list} ${dir_path}) + endforeach () + list(REMOVE_DUPLICATES dir_list) + + include_directories(${dir_list}) +endmacro() \ No newline at end of file diff --git a/cmake/toolchain.cmake b/cmake/toolchain.cmake new file mode 100644 index 0000000..163ddac --- /dev/null +++ b/cmake/toolchain.cmake @@ -0,0 +1,22 @@ +if (NOT TOOLCHAIN) + message(FATAL_ERROR "TOOLCHAIN must be set, to absolute path of kendryte-toolchain dist/bin folder.") +endif () + +if (WIN32) + set(EXT ".exe") +else () + set(EXT "") +endif () + +condition_set(CMAKE_C_COMPILER "${TOOLCHAIN}/riscv64-unknown-elf-gcc${EXT}" CACHE INTERNAL "") +condition_set(CMAKE_CXX_COMPILER "${TOOLCHAIN}/riscv64-unknown-elf-g++${EXT}" CACHE INTERNAL "") +condition_set(CMAKE_LINKER "${TOOLCHAIN}/riscv64-unknown-elf-ld${EXT}" CACHE INTERNAL "") +condition_set(CMAKE_AR "${TOOLCHAIN}/riscv64-unknown-elf-ar${EXT}" CACHE INTERNAL "") +condition_set(CMAKE_CXX_COMPILER_AR "${CMAKE_AR}${EXT}" CACHE INTERNAL "") +condition_set(CMAKE_C_COMPILER_AR "${CMAKE_AR}${EXT}" CACHE INTERNAL "") +condition_set(CMAKE_OBJCOPY "${TOOLCHAIN}/riscv64-unknown-elf-objcopy${EXT}" CACHE INTERNAL "") + +get_filename_component(_BIN_DIR "${CMAKE_C_COMPILER}" DIRECTORY) +if (NOT "${TOOLCHAIN}" STREQUAL "${_BIN_DIR}") + message(FATAL_ERROR "CMAKE_C_COMPILER is not in kendryte-toolchain dist/bin folder.") +endif () diff --git a/lds/kendryte.ld b/lds/kendryte.ld new file mode 100644 index 0000000..e082a1d --- /dev/null +++ b/lds/kendryte.ld @@ -0,0 +1,250 @@ +/* + * The MEMORY command describes the location and size of blocks of memory + * in the target. You can use it to describe which memory regions may be + * used by the linker, and which memory regions it must avoid. + */ +MEMORY +{ + /* + * Memory with CPU cache. + *6M CPU SRAM + */ + ram (wxa!ri) : ORIGIN = 0x80000000, LENGTH = (6 * 1024 * 1024) + /* + * Memory without CPU cache + * 6M CPU SRAM + */ + ram_nocache (wxa!ri) : ORIGIN = 0x40000000, LENGTH = (6 * 1024 * 1024) +} + +PROVIDE( _rom_start = ORIGIN(rom) ); +PROVIDE( _rom_end = ORIGIN(rom) + LENGTH(rom) ); +PROVIDE( _ram_start = ORIGIN(ram) ); +PROVIDE( _ram_end = ORIGIN(ram) + LENGTH(ram) ); +PROVIDE( _io_start = 0x40000000 ); +PROVIDE( _io_end = _io_start + LENGTH(ram) ); +PROVIDE( _stack_size = 1 << 17 ); + + +/* + * The OUTPUT_ARCH command specifies the machine architecture where the + * argument is one of the names used in the Kendryte library. + */ +OUTPUT_ARCH( "riscv" ) + +/* + * The ENTRY command specifies the entry point (ie. first instruction to + * execute). The symbol _start is defined in crt0.S + */ +ENTRY(_start) + +/* + * The GROUP command is special since the listed archives will be + * searched repeatedly until there are no new undefined references. We + * need this since -lc depends on -lgloss and -lgloss depends on -lc. I + * thought gcc would automatically include -lgcc when needed, but + * in this file includes it explicitly here and I was seeing link errors + * without it. + */ +/* GROUP( -lc -lgloss -lgcc ) */ + +/* + * The linker only pays attention to the PHDRS command when generating + * an ELF output file. In other cases, the linker will simply ignore PHDRS. + */ +PHDRS +{ + ram_ro PT_LOAD; + ram_init PT_LOAD; + ram PT_NULL; +} + +/* + * This is where we specify how the input sections map to output + * sections. + */ +SECTIONS +{ + /* Program code segment, also known as a text segment */ + .text : + { + PROVIDE( _text = ABSOLUTE(.) ); + /* Initialization code segment */ + KEEP( *(.text.start) ) + *(.text.unlikely .text.unlikely.*) + *(.text.startup .text.startup.*) + /* Normal code segment */ + *(.text .text.*) + *(.gnu.linkonce.t.*) + + . = ALIGN(8); + PROVIDE( _etext = ABSOLUTE(.) ); + } >ram AT>ram :ram_ro + + /* Read-only data segment */ + .rodata : + { + *(.rdata) + *(.rodata .rodata.*) + *(.gnu.linkonce.r.*) + } >ram AT>ram :ram_ro + + . = ALIGN(8); + + /* Init array and fini array */ + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } >ram AT>ram :ram_ro + + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } >ram AT>ram :ram_ro + + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } >ram AT>ram :ram_ro + + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } >ram AT>ram :ram_ro + + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } >ram AT>ram :ram_ro + + . = ALIGN(8); + + .lalign : + { + . = ALIGN(8); + PROVIDE( _data_lma = . ); + } >ram AT>ram :ram_ro + + .dalign : + { + . = ALIGN(8); + PROVIDE( _data = . ); + } >ram AT>ram :ram_init + + . = ALIGN(8); + + /* .data, .sdata and .srodata segment */ + .data : + { + /* Writable data segment (.data segment) */ + *(.data .data.*) + *(.gnu.linkonce.d.*) + /* Have _gp point to middle of sdata/sbss to maximize displacement range */ + . = ALIGN(8); + PROVIDE( _gp = ABSOLUTE(.) + 0x800); + /* Writable small data segment (.sdata segment) */ + *(.sdata .sdata.*) + *(.gnu.linkonce.s.*) + /* Read-only small data segment (.srodata segment) */ + . = ALIGN(8); + *(.srodata.cst16) + *(.srodata.cst8) + *(.srodata.cst4) + *(.srodata.cst2) + *(.srodata .srodata.*) + /* Align _edata to cache line size */ + . = ALIGN(64); + PROVIDE( _edata = ABSOLUTE(.) ); + } >ram AT>ram :ram_init + + /* .bss and .sbss segment */ + .bss : + { + PROVIDE( _bss = ABSOLUTE(.) ); + /* Writable uninitialized small data segment (.sbss segment)*/ + *(.sbss .sbss.*) + *(.gnu.linkonce.sb.*) + *(.scommon) + /* Uninitialized writeable data section (.bss segment)*/ + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + + . = ALIGN(8); + PROVIDE( _ebss = ABSOLUTE(.) ); + } >ram AT>ram :ram + + PROVIDE( _tls_data = ABSOLUTE(.) ); + /* + * Thread Local Storage (TLS) are per-thread global variables. + * Compilers such as GCC provide a __thread keyword to mark global + * variables as per-thread. Support is required in the program loader + * and thread creator. + */ + + /* Thread-local data segment, .tdata (initialized tls). */ + .tdata : + { + KEEP( *(.tdata.begin) ) + *(.tdata .tdata.*) + *(.gnu.linkonce.td.*) + KEEP( *(.tdata.end) ) + } >ram AT>ram :ram + + /* Thread-local bss segment, .tbss (zero-initialized tls). */ + .tbss : + { + *(.tbss .tbss.*) + *(.gnu.linkonce.tb.*) + KEEP( *(.tbss.end) ) + } >ram AT>ram :ram + + /* + * End of uninitalized data segement + * + * Actually the stack needs 16B alignment, and it won't hurt to also slightly + * increase the alignment to 32 or even 64 (cache line size). + * + * Align _heap_start to cache line size + */ + . = ALIGN(64); + PROVIDE( _end = ABSOLUTE(.) ); + /* Leave 2 holes for stack & TLS, the size can set in kconfig */ + PROVIDE( _heap_start = ABSOLUTE(.) + _stack_size * 2 ); + PROVIDE( _tp0 = (_end + 63) & (-64) ); + PROVIDE( _tp1 = _tp0 + _stack_size ); + PROVIDE( _sp0 = _tp0 + _stack_size ); + PROVIDE( _sp1 = _tp1 + _stack_size ); + /* Heap end is at the end of memory, the memory size can set in kconfig */ + PROVIDE( _heap_end = _ram_end ); +} + diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt new file mode 100644 index 0000000..c6c2d82 --- /dev/null +++ b/lib/CMakeLists.txt @@ -0,0 +1,33 @@ +#project(maix_drivers) + +# create driver library + +FILE(GLOB_RECURSE LIB_SRC + "${CMAKE_CURRENT_LIST_DIR}/*.h" + "${CMAKE_CURRENT_LIST_DIR}/*.hpp" + "${CMAKE_CURRENT_LIST_DIR}/*.cpp" + "${CMAKE_CURRENT_LIST_DIR}/*.c" + "${CMAKE_CURRENT_LIST_DIR}/*.s" + "${CMAKE_CURRENT_LIST_DIR}/*.S" + ) + +FILE(GLOB_RECURSE ASSEMBLY_FILES + "${CMAKE_CURRENT_LIST_DIR}/*.s" + "${CMAKE_CURRENT_LIST_DIR}/*.S" + ) + +include_directories(${CMAKE_CURRENT_LIST_DIR}/drivers/include ${CMAKE_CURRENT_LIST_DIR}/bsp/include ${CMAKE_CURRENT_LIST_DIR}/firmware/include) +# +#HEADER_DIRECTORIES(LIB_HEADERS) +# +#INCLUDE_DIRECTORIES(${LIB_HEADERS}) + +SET_PROPERTY(SOURCE ${ASSEMBLY_FILES} PROPERTY LANGUAGE C) +SET_SOURCE_FILES_PROPERTIES(${ASSEMBLY_FILES} PROPERTIES COMPILE_FLAGS "-x assembler-with-cpp -D __riscv64") + +#MESSAGE("CMAKE_C_FLAGS: ${CMAKE_C_FLAGS}") + +ADD_LIBRARY(kendryte + ${LIB_SRC} + ) +SET_TARGET_PROPERTIES(kendryte PROPERTIES LINKER_LANGUAGE C) diff --git a/lib/bsp/config/fpioa_cfg.c b/lib/bsp/config/fpioa_cfg.c new file mode 100644 index 0000000..4235efb --- /dev/null +++ b/lib/bsp/config/fpioa_cfg.c @@ -0,0 +1,29 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "fpioa_cfg.h" + +const fpioa_cfg_t g_fpioa_cfg = +{ + .version = 1, + .io_count = FPIOA_NUM_IO, + .io_functions = + { + [0] = FUNC_JTAG_TCLK, + + } +}; + diff --git a/lib/bsp/config/fpioa_cfg.h b/lib/bsp/config/fpioa_cfg.h new file mode 100644 index 0000000..77b8df8 --- /dev/null +++ b/lib/bsp/config/fpioa_cfg.h @@ -0,0 +1,42 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef _FPIOA_CFG_H +#define _FPIOA_CFG_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + uint32_t version; + uint32_t io_count; + enum fpioa_function_e io_functions[FPIOA_NUM_IO]; +} fpioa_cfg_t; + +extern const fpioa_cfg_t g_fpioa_cfg; +int fpioa_get_io_by_func(enum fpioa_function_e function); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib/bsp/crt.S b/lib/bsp/crt.S new file mode 100644 index 0000000..5608ff2 --- /dev/null +++ b/lib/bsp/crt.S @@ -0,0 +1,296 @@ +# Copyright 2018 Canaan Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +#include "env/encoding.h" + +# define LREG ld +# define SREG sd +# define LFREG fld +# define SFREG fsd +# define REGBYTES 8 +# define STKSHIFT 17 + + +.section .text.start, "ax", @progbits +.globl _start +_start: + j 1f + .word 0xdeadbeef +1: + csrw mideleg, 0 + csrw medeleg, 0 + csrw mie, 0 + csrw mip, 0 + la t0, trap_entry + csrw mtvec, t0 + + li x1, 0 + li x2, 0 + li x3, 0 + li x4, 0 + li x5, 0 + li x6, 0 + li x7, 0 + li x8, 0 + li x9, 0 + li x10,0 + li x11,0 + li x12,0 + li x13,0 + li x14,0 + li x15,0 + li x16,0 + li x17,0 + li x18,0 + li x19,0 + li x20,0 + li x21,0 + li x22,0 + li x23,0 + li x24,0 + li x25,0 + li x26,0 + li x27,0 + li x28,0 + li x29,0 + li x30,0 + li x31,0 + + csrr t0, misa + bltz t0, 1f + li a0, 1234 + j sys_exit +1: + + andi t0, t0, 1 << ('f' - 'a') + beqz t0, 1f + li t0, MSTATUS_FS + csrs mstatus, t0 + + fssr x0 + fmv.d.x f0, x0 + fmv.d.x f1, x0 + fmv.d.x f2, x0 + fmv.d.x f3, x0 + fmv.d.x f4, x0 + fmv.d.x f5, x0 + fmv.d.x f6, x0 + fmv.d.x f7, x0 + fmv.d.x f8, x0 + fmv.d.x f9, x0 + fmv.d.x f10,x0 + fmv.d.x f11,x0 + fmv.d.x f12,x0 + fmv.d.x f13,x0 + fmv.d.x f14,x0 + fmv.d.x f15,x0 + fmv.d.x f16,x0 + fmv.d.x f17,x0 + fmv.d.x f18,x0 + fmv.d.x f19,x0 + fmv.d.x f20,x0 + fmv.d.x f21,x0 + fmv.d.x f22,x0 + fmv.d.x f23,x0 + fmv.d.x f24,x0 + fmv.d.x f25,x0 + fmv.d.x f26,x0 + fmv.d.x f27,x0 + fmv.d.x f28,x0 + fmv.d.x f29,x0 + fmv.d.x f30,x0 + fmv.d.x f31,x0 + + +1: + + la gp, _gp + la tp, _end + 63 + and tp, tp, -64 + csrr a0, mhartid + li a1, 2 + +1:bgeu a0, a1, 1b + + sll a2, a0, STKSHIFT + add tp, tp, a2 + add sp, a0, 1 + sll sp, sp, STKSHIFT + add sp, sp, tp + + j _init_bsp + + .globl trap_entry + .type trap_entry, @function + .align 2 +trap_entry: + addi sp, sp, -64*REGBYTES + + SREG x1, 1*REGBYTES(sp) + SREG x2, 2*REGBYTES(sp) + SREG x3, 3*REGBYTES(sp) + SREG x4, 4*REGBYTES(sp) + SREG x5, 5*REGBYTES(sp) + SREG x6, 6*REGBYTES(sp) + SREG x7, 7*REGBYTES(sp) + SREG x8, 8*REGBYTES(sp) + SREG x9, 9*REGBYTES(sp) + SREG x10, 10*REGBYTES(sp) + SREG x11, 11*REGBYTES(sp) + SREG x12, 12*REGBYTES(sp) + SREG x13, 13*REGBYTES(sp) + SREG x14, 14*REGBYTES(sp) + SREG x15, 15*REGBYTES(sp) + SREG x16, 16*REGBYTES(sp) + SREG x17, 17*REGBYTES(sp) + SREG x18, 18*REGBYTES(sp) + SREG x19, 19*REGBYTES(sp) + SREG x20, 20*REGBYTES(sp) + SREG x21, 21*REGBYTES(sp) + SREG x22, 22*REGBYTES(sp) + SREG x23, 23*REGBYTES(sp) + SREG x24, 24*REGBYTES(sp) + SREG x25, 25*REGBYTES(sp) + SREG x26, 26*REGBYTES(sp) + SREG x27, 27*REGBYTES(sp) + SREG x28, 28*REGBYTES(sp) + SREG x29, 29*REGBYTES(sp) + SREG x30, 30*REGBYTES(sp) + SREG x31, 31*REGBYTES(sp) + + SFREG f0, ( 0 + 32)*REGBYTES(sp) + SFREG f1, ( 1 + 32)*REGBYTES(sp) + SFREG f2, ( 2 + 32)*REGBYTES(sp) + SFREG f3, ( 3 + 32)*REGBYTES(sp) + SFREG f4, ( 4 + 32)*REGBYTES(sp) + SFREG f5, ( 5 + 32)*REGBYTES(sp) + SFREG f6, ( 6 + 32)*REGBYTES(sp) + SFREG f7, ( 7 + 32)*REGBYTES(sp) + SFREG f8, ( 8 + 32)*REGBYTES(sp) + SFREG f9, ( 9 + 32)*REGBYTES(sp) + SFREG f10,( 10 + 32)*REGBYTES(sp) + SFREG f11,( 11 + 32)*REGBYTES(sp) + SFREG f12,( 12 + 32)*REGBYTES(sp) + SFREG f13,( 13 + 32)*REGBYTES(sp) + SFREG f14,( 14 + 32)*REGBYTES(sp) + SFREG f15,( 15 + 32)*REGBYTES(sp) + SFREG f16,( 16 + 32)*REGBYTES(sp) + SFREG f17,( 17 + 32)*REGBYTES(sp) + SFREG f18,( 18 + 32)*REGBYTES(sp) + SFREG f19,( 19 + 32)*REGBYTES(sp) + SFREG f20,( 20 + 32)*REGBYTES(sp) + SFREG f21,( 21 + 32)*REGBYTES(sp) + SFREG f22,( 22 + 32)*REGBYTES(sp) + SFREG f23,( 23 + 32)*REGBYTES(sp) + SFREG f24,( 24 + 32)*REGBYTES(sp) + SFREG f25,( 25 + 32)*REGBYTES(sp) + SFREG f26,( 26 + 32)*REGBYTES(sp) + SFREG f27,( 27 + 32)*REGBYTES(sp) + SFREG f28,( 28 + 32)*REGBYTES(sp) + SFREG f29,( 29 + 32)*REGBYTES(sp) + SFREG f30,( 30 + 32)*REGBYTES(sp) + SFREG f31,( 31 + 32)*REGBYTES(sp) + + csrr a0, mcause + csrr a1, mepc + mv a2, sp + add a3, sp, 32*REGBYTES + bgez a0, .handle_syscall +.handle_irq: + jal handle_irq + j .restore +.handle_syscall: + jal handle_syscall +.restore: + csrw mepc, a0 + LREG x1, 1*REGBYTES(sp) + LREG x2, 2*REGBYTES(sp) + LREG x3, 3*REGBYTES(sp) + LREG x4, 4*REGBYTES(sp) + LREG x5, 5*REGBYTES(sp) + LREG x6, 6*REGBYTES(sp) + LREG x7, 7*REGBYTES(sp) + LREG x8, 8*REGBYTES(sp) + LREG x9, 9*REGBYTES(sp) + LREG x10, 10*REGBYTES(sp) + LREG x11, 11*REGBYTES(sp) + LREG x12, 12*REGBYTES(sp) + LREG x13, 13*REGBYTES(sp) + LREG x14, 14*REGBYTES(sp) + LREG x15, 15*REGBYTES(sp) + LREG x16, 16*REGBYTES(sp) + LREG x17, 17*REGBYTES(sp) + LREG x18, 18*REGBYTES(sp) + LREG x19, 19*REGBYTES(sp) + LREG x20, 20*REGBYTES(sp) + LREG x21, 21*REGBYTES(sp) + LREG x22, 22*REGBYTES(sp) + LREG x23, 23*REGBYTES(sp) + LREG x24, 24*REGBYTES(sp) + LREG x25, 25*REGBYTES(sp) + LREG x26, 26*REGBYTES(sp) + LREG x27, 27*REGBYTES(sp) + LREG x28, 28*REGBYTES(sp) + LREG x29, 29*REGBYTES(sp) + LREG x30, 30*REGBYTES(sp) + LREG x31, 31*REGBYTES(sp) + + LFREG f0, ( 0 + 32)*REGBYTES(sp) + LFREG f1, ( 1 + 32)*REGBYTES(sp) + LFREG f2, ( 2 + 32)*REGBYTES(sp) + LFREG f3, ( 3 + 32)*REGBYTES(sp) + LFREG f4, ( 4 + 32)*REGBYTES(sp) + LFREG f5, ( 5 + 32)*REGBYTES(sp) + LFREG f6, ( 6 + 32)*REGBYTES(sp) + LFREG f7, ( 7 + 32)*REGBYTES(sp) + LFREG f8, ( 8 + 32)*REGBYTES(sp) + LFREG f9, ( 9 + 32)*REGBYTES(sp) + LFREG f10,( 10 + 32)*REGBYTES(sp) + LFREG f11,( 11 + 32)*REGBYTES(sp) + LFREG f12,( 12 + 32)*REGBYTES(sp) + LFREG f13,( 13 + 32)*REGBYTES(sp) + LFREG f14,( 14 + 32)*REGBYTES(sp) + LFREG f15,( 15 + 32)*REGBYTES(sp) + LFREG f16,( 16 + 32)*REGBYTES(sp) + LFREG f17,( 17 + 32)*REGBYTES(sp) + LFREG f18,( 18 + 32)*REGBYTES(sp) + LFREG f19,( 19 + 32)*REGBYTES(sp) + LFREG f20,( 20 + 32)*REGBYTES(sp) + LFREG f21,( 21 + 32)*REGBYTES(sp) + LFREG f22,( 22 + 32)*REGBYTES(sp) + LFREG f23,( 23 + 32)*REGBYTES(sp) + LFREG f24,( 24 + 32)*REGBYTES(sp) + LFREG f25,( 25 + 32)*REGBYTES(sp) + LFREG f26,( 26 + 32)*REGBYTES(sp) + LFREG f27,( 27 + 32)*REGBYTES(sp) + LFREG f28,( 28 + 32)*REGBYTES(sp) + LFREG f29,( 29 + 32)*REGBYTES(sp) + LFREG f30,( 30 + 32)*REGBYTES(sp) + LFREG f31,( 31 + 32)*REGBYTES(sp) + + addi sp, sp, 64*REGBYTES + mret + +.section ".tdata.begin" +.globl _tdata_begin +_tdata_begin: + +.section ".tdata.end" +.globl _tdata_end +_tdata_end: + +.section ".tbss.end" +.globl _tbss_end +_tbss_end: + diff --git a/lib/bsp/entry.c b/lib/bsp/entry.c new file mode 100644 index 0000000..50385a3 --- /dev/null +++ b/lib/bsp/entry.c @@ -0,0 +1,37 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "entry.h" + +/** + * @brief Dummy function for __libc_init_array called + */ +void __attribute__((weak)) _init(void) +{ + /** + * These don't have to do anything since we use init_array/fini_array. + */ +} + +/** + * @brief Dummy function for __libc_fini_array called + */ +void __attribute__((weak)) _fini(void) +{ + /** + * These don't have to do anything since we use init_array/fini_array. + */ +} + diff --git a/lib/bsp/entry_user.c b/lib/bsp/entry_user.c new file mode 100644 index 0000000..3b008d4 --- /dev/null +++ b/lib/bsp/entry_user.c @@ -0,0 +1,112 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "atomic.h" +#include "clint.h" +#include "dmac.h" +#include "entry.h" +#include "fpioa.h" +#include "platform.h" +#include "plic.h" +#include "sysclock.h" +#include "sysctl.h" +#include "syslog.h" +#include "uarths.h" + +volatile char * const ram = (volatile char*)RAM_BASE_ADDR; + +extern char _heap_start[]; +extern char _heap_end[]; + +uint32_t g_wake_up[2] = {1}; + +void thread_entry(int core_id) +{ + /* Clear IPI flag if pending */ + clint_ipi_clear(core_id); + /* Enable software interrupt */ + clint_ipi_enable(); + /* Wait for interrupt form core 0 */ + asm volatile("wfi"); + atomic_set(&g_wake_up[core_id], 1); +} + +void core_enable(int core_id) +{ + clint_ipi_send(core_id); + uint32_t cpu_freq = sysctl_clock_get_freq(SYSCTL_CLOCK_CPU); + uint32_t old_cycle = read_csr(mcycle); + while (!atomic_read(&g_wake_up[core_id])) + { + if (read_csr(mcycle) - old_cycle > cpu_freq / 1000) /* wait for 1ms */ + { + clint_ipi_send(core_id); /* wakeup again */ + old_cycle = read_csr(mcycle); + } + } +} + +int __attribute__((weak)) os_entry(int core_id, int number_of_cores, int (*user_main)(int, char**)) +{ + /* Call main if there is no OS */ + return user_main(0, 0); +} + +void _init_bsp(int core_id, int number_of_cores) +{ + extern int main(int argc, char* argv[]); + extern void __libc_init_array(void); + extern void __libc_fini_array(void); + /* Initialize thread local data */ + init_tls(); + + if (core_id == 0) + { + /* Copy lma data to memory */ + init_lma(); + /* Initialize bss data to 0 */ + init_bss(); + /* Init FPIOA */ + fpioa_init(); + /* PLL init */ + sys_clock_init(); + /* Init UART */ + uart_init(); + /* Dmac init */ + dmac_init(); + /* Plic init */ + plic_init(); + /* Register finalization function */ + atexit(__libc_fini_array); + /* Init libc array for C++ */ + __libc_init_array(); + } + else + { + thread_entry(core_id); + } + + if (core_id == 0) + { + /* Enable Core 1 to run main */ + core_enable(1); + } + + int ret = os_entry(core_id, number_of_cores, main); + + exit(ret); +} + diff --git a/lib/bsp/include/atomic.h b/lib/bsp/include/atomic.h new file mode 100644 index 0000000..c01b677 --- /dev/null +++ b/lib/bsp/include/atomic.h @@ -0,0 +1,244 @@ + +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _BSP_ATOMIC_H +#define _BSP_ATOMIC_H + +#ifdef __cplusplus +extern "C" { +#endif + + +#define SPINLOCK_INIT \ + { \ + 0 \ + } + +#define HARTLOCK_INIT \ + { \ + .lock = SPINLOCK_INIT, \ + .count = 0, \ + .hart = -1 \ + } + + +/* Defination of memory barrier macro */ +#define mb() \ + { \ + asm volatile("fence" :: \ + : "memory"); \ + } + +#define atomic_set(ptr, val) (*(volatile typeof(*(ptr))*)(ptr) = val) +#define atomic_read(ptr) (*(volatile typeof(*(ptr))*)(ptr)) + +#ifndef __riscv_atomic +#error "atomic extension is required." +#endif +#define atomic_add(ptr, inc) __sync_fetch_and_add(ptr, inc) +#define atomic_or(ptr, inc) __sync_fetch_and_or(ptr, inc) +#define atomic_swap(ptr, swp) __sync_lock_test_and_set(ptr, swp) +#define atomic_cas(ptr, cmp, swp) __sync_val_compare_and_swap(ptr, cmp, swp) + +typedef struct +{ + int lock; +} spinlock_t; + +typedef struct +{ + spinlock_t lock; + int count; + int waiting; +} semaphore_t; + + +typedef struct +{ + spinlock_t lock; + int count; + int hart; +} hartlock_t; + + +static inline int spinlock_trylock(spinlock_t *lock) +{ + int res = atomic_swap(&lock->lock, -1); + /* Use memory barrier to keep coherency */ + mb(); + return res; +} + +static inline void spinlock_lock(spinlock_t *lock) +{ + do + { + while (atomic_read(&lock->lock)) + ; + } while (spinlock_trylock(lock)); +} + +static inline void spinlock_unlock(spinlock_t *lock) +{ + /* Use memory barrier to keep coherency */ + mb(); + atomic_set(&lock->lock, 0); +} + +static inline void semaphore_signal(semaphore_t *semaphore, int i) +{ + spinlock_lock(&(semaphore->lock)); + semaphore->count += i; + spinlock_unlock(&(semaphore->lock)); +} + +static inline void semaphore_wait(semaphore_t *semaphore, int i) +{ + atomic_add(&(semaphore->waiting), 1); + while (1) + { + spinlock_lock(&(semaphore->lock)); + if (semaphore->count >= i) + { + semaphore->count -= i; + atomic_add(&(semaphore->waiting), -1); + spinlock_unlock(&(semaphore->lock)); + break; + } + spinlock_unlock(&(semaphore->lock)); + } +} + +static inline int semaphore_count(semaphore_t *semaphore) +{ + int res = 0; + + spinlock_lock(&(semaphore->lock)); + res = semaphore->count; + spinlock_unlock(&(semaphore->lock)); + return res; +} + +static inline int semaphore_waiting(semaphore_t *semaphore) +{ + return atomic_read(&(semaphore->waiting)); +} + +static inline int hartlock_trylock(hartlock_t *lock) +{ + int res = 0; + unsigned long hart; + + asm volatile("csrr %0, mhartid;" + : "=r"(hart)); + spinlock_lock(&lock->lock); + + if (lock->count == 0) + { + /* First time get lock */ + lock->count++; + lock->hart = hart; + res = 0; + } + else if (lock->hart == hart) + { + /* Same core get lock */ + lock->count++; + res = 0; + } + else + { + /* Different core get lock */ + res = -1; + } + spinlock_unlock(&lock->lock); + + return res; +} + +static inline void hartlock_lock(hartlock_t *lock) +{ + unsigned long hart; + + asm volatile("csrr %0, mhartid;" + : "=r"(hart)); + spinlock_lock(&lock->lock); + + if (lock->count == 0) + { + /* First time get lock */ + lock->count++; + lock->hart = hart; + } + else if (lock->hart == hart) + { + /* Same core get lock */ + lock->count++; + } + else + { + /* Different core get lock */ + spinlock_unlock(&lock->lock); + + do + { + while (atomic_read(&lock->count)) + ; + } while (hartlock_trylock(lock)); + } + spinlock_unlock(&lock->lock); +} + +static inline void hartlock_unlock(hartlock_t *lock) +{ + unsigned long hart; + + asm volatile("csrr %0, mhartid;" + : "=r"(hart)); + spinlock_lock(&lock->lock); + + if (lock->hart == hart) + { + /* Same core release lock */ + lock->count--; + if (lock->count <= 0) + { + lock->hart = -1; + lock->count = 0; + } + } + else + { + /* Different core release lock */ + spinlock_unlock(&lock->lock); + + register unsigned long a7 asm("a7") = 93; + register unsigned long a0 asm("a0") = 0; + register unsigned long a1 asm("a1") = 0; + register unsigned long a2 asm("a2") = 0; + + asm volatile("scall" + : "+r"(a0) + : "r"(a1), "r"(a2), "r"(a7)); + } + spinlock_unlock(&lock->lock); +} + +#ifdef __cplusplus +} +#endif + +#endif /* _BSP_ATOMIC_H */ + diff --git a/lib/bsp/include/dump.h b/lib/bsp/include/dump.h new file mode 100644 index 0000000..da807b1 --- /dev/null +++ b/lib/bsp/include/dump.h @@ -0,0 +1,141 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _BSP_DUMP_H +#define _BSP_DUMP_H + +#include +#include +#include "syslog.h" +#include "uarths.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define DUMP_PRINTF printk + +static inline void +dump_core(const char *reason, uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]) +{ + static const char *const reg_usage[][2] = + { + {"zero ", "Hard-wired zero"}, + {"ra ", "Return address"}, + {"sp ", "Stack pointer"}, + {"gp ", "Global pointer"}, + {"tp ", "Thread pointer"}, + {"t0 ", "Temporaries Caller"}, + {"t1 ", "Temporaries Caller"}, + {"t2 ", "Temporaries Caller"}, + {"s0/fp", "Saved register/frame pointer"}, + {"s1 ", "Saved register"}, + {"a0 ", "Function arguments/return values"}, + {"a1 ", "Function arguments/return values"}, + {"a2 ", "Function arguments values"}, + {"a3 ", "Function arguments values"}, + {"a4 ", "Function arguments values"}, + {"a5 ", "Function arguments values"}, + {"a6 ", "Function arguments values"}, + {"a7 ", "Function arguments values"}, + {"s2 ", "Saved registers"}, + {"s3 ", "Saved registers"}, + {"s4 ", "Saved registers"}, + {"s5 ", "Saved registers"}, + {"s6 ", "Saved registers"}, + {"s7 ", "Saved registers"}, + {"s8 ", "Saved registers"}, + {"s9 ", "Saved registers"}, + {"s10 ", "Saved registers"}, + {"s11 ", "Saved registers"}, + {"t3 ", "Temporaries Caller"}, + {"t4 ", "Temporaries Caller"}, + {"t5 ", "Temporaries Caller"}, + {"t6 ", "Temporaries Caller"}, + }; + + static const char *const regf_usage[][2] = + { + {"ft0 ", "FP temporaries"}, + {"ft1 ", "FP temporaries"}, + {"ft2 ", "FP temporaries"}, + {"ft3 ", "FP temporaries"}, + {"ft4 ", "FP temporaries"}, + {"ft5 ", "FP temporaries"}, + {"ft6 ", "FP temporaries"}, + {"ft7 ", "FP temporaries"}, + {"fs0 ", "FP saved registers"}, + {"fs1 ", "FP saved registers"}, + {"fa0 ", "FP arguments/return values"}, + {"fa1 ", "FP arguments/return values"}, + {"fa2 ", "FP arguments values"}, + {"fa3 ", "FP arguments values"}, + {"fa4 ", "FP arguments values"}, + {"fa5 ", "FP arguments values"}, + {"fa6 ", "FP arguments values"}, + {"fa7 ", "FP arguments values"}, + {"fs2 ", "FP Saved registers"}, + {"fs3 ", "FP Saved registers"}, + {"fs4 ", "FP Saved registers"}, + {"fs5 ", "FP Saved registers"}, + {"fs6 ", "FP Saved registers"}, + {"fs7 ", "FP Saved registers"}, + {"fs8 ", "FP Saved registers"}, + {"fs9 ", "FP Saved registers"}, + {"fs10", "FP Saved registers"}, + {"fs11", "FP Saved registers"}, + {"ft8 ", "FP Temporaries Caller"}, + {"ft9 ", "FP Temporaries Caller"}, + {"ft10", "FP Temporaries Caller"}, + {"ft11", "FP Temporaries Caller"}, + }; + + if (CONFIG_LOG_LEVEL >= LOG_ERROR) + { + const char unknown_reason[] = "unknown"; + + if (!reason) + reason = unknown_reason; + + DUMP_PRINTF("core dump: %s\n", reason); + DUMP_PRINTF("Cause 0x%016lx, EPC 0x%016lx\n", cause, epc); + + int i = 0; + for (i = 0; i < 32 / 2; i++) + { + DUMP_PRINTF( + "reg[%02d](%s) = 0x%016lx, reg[%02d](%s) = 0x%016lx\n", + i * 2, reg_usage[i * 2][0], regs[i * 2], + i * 2 + 1, reg_usage[i * 2 + 1][0], regs[i * 2 + 1]); + } + + for (i = 0; i < 32 / 2; i++) + { + DUMP_PRINTF( + "freg[%02d](%s) = 0x%016lx(%f), freg[%02d](%s) = 0x%016lx(%f)\n", + i * 2, regf_usage[i * 2][0], fregs[i * 2], (float)fregs[i * 2], + i * 2 + 1, regf_usage[i * 2 + 1][0], fregs[i * 2 + 1], (float)fregs[i * 2 + 1]); + } + } +} + +#undef DUMP_PRINTF + +#ifdef __cplusplus +} +#endif + +#endif /* _BSP_DUMP_H */ + diff --git a/lib/bsp/include/entry.h b/lib/bsp/include/entry.h new file mode 100644 index 0000000..2aded61 --- /dev/null +++ b/lib/bsp/include/entry.h @@ -0,0 +1,71 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _BSP_ENTRY_H +#define _BSP_ENTRY_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +static inline void init_lma(void) +{ + extern unsigned int _data_lma; + extern unsigned int _data; + extern unsigned int _edata; + unsigned int *src, *dst; + + src = &_data_lma; + dst = &_data; + while (dst < &_edata) + *dst++ = *src++; +} + +static inline void init_bss(void) +{ + extern unsigned int _bss; + extern unsigned int _ebss; + unsigned int *dst; + + dst = &_bss; + while (dst < &_ebss) + *dst++ = 0; +} + +static inline void init_tls(void) +{ + register void *thread_pointer asm("tp"); + extern char _tls_data; + + extern __thread char _tdata_begin, _tdata_end, _tbss_end; + + size_t tdata_size = &_tdata_end - &_tdata_begin; + + memcpy(thread_pointer, &_tls_data, tdata_size); + + size_t tbss_size = &_tbss_end - &_tdata_end; + + memset(thread_pointer + tdata_size, 0, tbss_size); +} + +#ifdef __cplusplus +} +#endif + +#endif /* _BSP_ENTRY_H */ + diff --git a/lib/bsp/include/env/encoding.h b/lib/bsp/include/env/encoding.h new file mode 100644 index 0000000..80b774d --- /dev/null +++ b/lib/bsp/include/env/encoding.h @@ -0,0 +1,1340 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _BSP_ENV_ENCODING_H +#define _BSP_ENV_ENCODING_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef RISCV_CSR_ENCODING_H +#define RISCV_CSR_ENCODING_H + +#define MSTATUS_UIE 0x00000001U +#define MSTATUS_SIE 0x00000002U +#define MSTATUS_HIE 0x00000004U +#define MSTATUS_MIE 0x00000008U +#define MSTATUS_UPIE 0x00000010U +#define MSTATUS_SPIE 0x00000020U +#define MSTATUS_HPIE 0x00000040U +#define MSTATUS_MPIE 0x00000080U +#define MSTATUS_SPP 0x00000100U +#define MSTATUS_HPP 0x00000600U +#define MSTATUS_MPP 0x00001800U +#define MSTATUS_FS 0x00006000U +#define MSTATUS_XS 0x00018000U +#define MSTATUS_MPRV 0x00020000U +#define MSTATUS_PUM 0x00040000U +#define MSTATUS_MXR 0x00080000U +#define MSTATUS_VM 0x1F000000U +#define MSTATUS32_SD 0x80000000U +#define MSTATUS64_SD 0x8000000000000000U + +#define SSTATUS_UIE 0x00000001U +#define SSTATUS_SIE 0x00000002U +#define SSTATUS_UPIE 0x00000010U +#define SSTATUS_SPIE 0x00000020U +#define SSTATUS_SPP 0x00000100U +#define SSTATUS_FS 0x00006000U +#define SSTATUS_XS 0x00018000U +#define SSTATUS_PUM 0x00040000U +#define SSTATUS32_SD 0x80000000U +#define SSTATUS64_SD 0x8000000000000000U + +#define DCSR_XDEBUGVER (3U<<30) +#define DCSR_NDRESET (1U<<29) +#define DCSR_FULLRESET (1U<<28) +#define DCSR_EBREAKM (1U<<15) +#define DCSR_EBREAKH (1U<<14) +#define DCSR_EBREAKS (1U<<13) +#define DCSR_EBREAKU (1U<<12) +#define DCSR_STOPCYCLE (1U<<10) +#define DCSR_STOPTIME (1U<<9) +#define DCSR_CAUSE (7U<<6) +#define DCSR_DEBUGINT (1U<<5) +#define DCSR_HALT (1U<<3) +#define DCSR_STEP (1U<<2) +#define DCSR_PRV (3U<<0) + +#define DCSR_CAUSE_NONE 0 +#define DCSR_CAUSE_SWBP 1 +#define DCSR_CAUSE_HWBP 2 +#define DCSR_CAUSE_DEBUGINT 3 +#define DCSR_CAUSE_STEP 4 +#define DCSR_CAUSE_HALT 5 + +#define MCONTROL_SELECT (1U<<19) +#define MCONTROL_TIMING (1U<<18) +#define MCONTROL_ACTION (0x3fU<<12) +#define MCONTROL_CHAIN (1U<<11) +#define MCONTROL_MATCH (0xfU<<7) +#define MCONTROL_M (1U<<6) +#define MCONTROL_H (1U<<5) +#define MCONTROL_S (1U<<4) +#define MCONTROL_U (1U<<3) +#define MCONTROL_EXECUTE (1U<<2) +#define MCONTROL_STORE (1U<<1) +#define MCONTROL_LOAD (1U<<0) + +#define MCONTROL_TYPE_NONE 0 +#define MCONTROL_TYPE_MATCH 2 + +#define MCONTROL_ACTION_DEBUG_EXCEPTION 0 +#define MCONTROL_ACTION_DEBUG_MODE 1 +#define MCONTROL_ACTION_TRACE_START 2 +#define MCONTROL_ACTION_TRACE_STOP 3 +#define MCONTROL_ACTION_TRACE_EMIT 4 + +#define MCONTROL_MATCH_EQUAL 0 +#define MCONTROL_MATCH_NAPOT 1 +#define MCONTROL_MATCH_GE 2 +#define MCONTROL_MATCH_LT 3 +#define MCONTROL_MATCH_MASK_LOW 4 +#define MCONTROL_MATCH_MASK_HIGH 5 + +#define MIP_SSIP (1U << IRQ_S_SOFT) +#define MIP_HSIP (1U << IRQ_H_SOFT) +#define MIP_MSIP (1U << IRQ_M_SOFT) +#define MIP_STIP (1U << IRQ_S_TIMER) +#define MIP_HTIP (1U << IRQ_H_TIMER) +#define MIP_MTIP (1U << IRQ_M_TIMER) +#define MIP_SEIP (1U << IRQ_S_EXT) +#define MIP_HEIP (1U << IRQ_H_EXT) +#define MIP_MEIP (1U << IRQ_M_EXT) + +#define SIP_SSIP MIP_SSIP +#define SIP_STIP MIP_STIP + +#define PRV_U 0 +#define PRV_S 1 +#define PRV_H 2 +#define PRV_M 3 + +#define VM_MBARE 0 +#define VM_MBB 1 +#define VM_MBBID 2 +#define VM_SV32 8 +#define VM_SV39 9 +#define VM_SV48 10 + +#define IRQ_S_SOFT 1 +#define IRQ_H_SOFT 2 +#define IRQ_M_SOFT 3 +#define IRQ_S_TIMER 5 +#define IRQ_H_TIMER 6 +#define IRQ_M_TIMER 7 +#define IRQ_S_EXT 9 +#define IRQ_H_EXT 10 +#define IRQ_M_EXT 11 +#define IRQ_COP 12 +#define IRQ_HOST 13 + +#define DEFAULT_RSTVEC 0x00001000U +#define DEFAULT_NMIVEC 0x00001004U +#define DEFAULT_MTVEC 0x00001010U +#define CONFIG_STRING_ADDR 0x0000100CU +#define EXT_IO_BASE 0x40000000U +#define DRAM_BASE 0x80000000U + +/* page table entry (PTE) fields */ +#define PTE_V 0x001U /* Valid */ +#define PTE_R 0x002U /* Read */ +#define PTE_W 0x004U /* Write */ +#define PTE_X 0x008U /* Execute */ +#define PTE_U 0x010U /* User */ +#define PTE_G 0x020U /* Global */ +#define PTE_A 0x040U /* Accessed */ +#define PTE_D 0x080U /* Dirty */ +#define PTE_SOFT 0x300U /* Reserved for Software */ + +#define PTE_PPN_SHIFT 10 + +#define MCONTROL_TYPE(xlen) (0xfULL<<((xlen)-4)) +#define MCONTROL_DMODE(xlen) (1ULL<<((xlen)-5)) +#define MCONTROL_MASKMAX(xlen) (0x3fULL<<((xlen)-11)) + +#define PTE_TABLE(PTE) (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V) + +#if defined(__riscv) + +#if defined(__riscv64) +# define MSTATUS_SD MSTATUS64_SD +# define SSTATUS_SD SSTATUS64_SD +# define RISCV_PGLEVEL_BITS 9 +#else +# define MSTATUS_SD MSTATUS32_SD +# define SSTATUS_SD SSTATUS32_SD +# define RISCV_PGLEVEL_BITS 10 +#endif +#define RISCV_PGSHIFT 12 +#define RISCV_PGSIZE (1 << RISCV_PGSHIFT) + +#ifndef __ASSEMBLER__ + +#if defined(__GNUC__) + +#define read_csr(reg) ({ unsigned long __tmp; \ + asm volatile ("csrr %0, " #reg : "=r"(__tmp)); \ + __tmp; }) + +#define write_csr(reg, val) ({ \ + if (__builtin_constant_p(val) && (unsigned long)(val) < 32) \ + asm volatile ("csrw " #reg ", %0" :: "i"(val)); \ + else \ + asm volatile ("csrw " #reg ", %0" :: "r"(val)); }) + +#define swap_csr(reg, val) ({ unsigned long __tmp; \ + if (__builtin_constant_p(val) && (unsigned long)(val) < 32) \ + asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "i"(val)); \ + else \ + asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "r"(val)); \ + __tmp; }) + +#define set_csr(reg, bit) ({ unsigned long __tmp; \ + if (__builtin_constant_p(bit) && (unsigned long)(bit) < 32) \ + asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "i"(bit)); \ + else \ + asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "r"(bit)); \ + __tmp; }) + +#define clear_csr(reg, bit) ({ unsigned long __tmp; \ + if (__builtin_constant_p(bit) && (unsigned long)(bit) < 32) \ + asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "i"(bit)); \ + else \ + asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "r"(bit)); \ + __tmp; }) + +#define rdtime() read_csr(time) +#define rdcycle() read_csr(cycle) +#define rdinstret() read_csr(instret) + +#endif + +#endif + +#endif + +#endif + +#ifndef RISCV_ENCODING_H +#define RISCV_ENCODING_H +#define MATCH_BEQ 0x63U +#define MASK_BEQ 0x707fU +#define MATCH_BNE 0x1063U +#define MASK_BNE 0x707fU +#define MATCH_BLT 0x4063U +#define MASK_BLT 0x707fU +#define MATCH_BGE 0x5063U +#define MASK_BGE 0x707fU +#define MATCH_BLTU 0x6063U +#define MASK_BLTU 0x707fU +#define MATCH_BGEU 0x7063U +#define MASK_BGEU 0x707fU +#define MATCH_JALR 0x67U +#define MASK_JALR 0x707fU +#define MATCH_JAL 0x6fU +#define MASK_JAL 0x7fU +#define MATCH_LUI 0x37U +#define MASK_LUI 0x7fU +#define MATCH_AUIPC 0x17U +#define MASK_AUIPC 0x7fU +#define MATCH_ADDI 0x13U +#define MASK_ADDI 0x707fU +#define MATCH_SLLI 0x1013U +#define MASK_SLLI 0xfc00707fU +#define MATCH_SLTI 0x2013U +#define MASK_SLTI 0x707fU +#define MATCH_SLTIU 0x3013U +#define MASK_SLTIU 0x707fU +#define MATCH_XORI 0x4013U +#define MASK_XORI 0x707fU +#define MATCH_SRLI 0x5013U +#define MASK_SRLI 0xfc00707fU +#define MATCH_SRAI 0x40005013U +#define MASK_SRAI 0xfc00707fU +#define MATCH_ORI 0x6013U +#define MASK_ORI 0x707fU +#define MATCH_ANDI 0x7013U +#define MASK_ANDI 0x707fU +#define MATCH_ADD 0x33U +#define MASK_ADD 0xfe00707fU +#define MATCH_SUB 0x40000033U +#define MASK_SUB 0xfe00707fU +#define MATCH_SLL 0x1033U +#define MASK_SLL 0xfe00707fU +#define MATCH_SLT 0x2033U +#define MASK_SLT 0xfe00707fU +#define MATCH_SLTU 0x3033U +#define MASK_SLTU 0xfe00707fU +#define MATCH_XOR 0x4033U +#define MASK_XOR 0xfe00707fU +#define MATCH_SRL 0x5033U +#define MASK_SRL 0xfe00707fU +#define MATCH_SRA 0x40005033U +#define MASK_SRA 0xfe00707fU +#define MATCH_OR 0x6033U +#define MASK_OR 0xfe00707fU +#define MATCH_AND 0x7033U +#define MASK_AND 0xfe00707fU +#define MATCH_ADDIW 0x1bU +#define MASK_ADDIW 0x707fU +#define MATCH_SLLIW 0x101bU +#define MASK_SLLIW 0xfe00707fU +#define MATCH_SRLIW 0x501bU +#define MASK_SRLIW 0xfe00707fU +#define MATCH_SRAIW 0x4000501bU +#define MASK_SRAIW 0xfe00707fU +#define MATCH_ADDW 0x3bU +#define MASK_ADDW 0xfe00707fU +#define MATCH_SUBW 0x4000003bU +#define MASK_SUBW 0xfe00707fU +#define MATCH_SLLW 0x103bU +#define MASK_SLLW 0xfe00707fU +#define MATCH_SRLW 0x503bU +#define MASK_SRLW 0xfe00707fU +#define MATCH_SRAW 0x4000503bU +#define MASK_SRAW 0xfe00707fU +#define MATCH_LB 0x3U +#define MASK_LB 0x707fU +#define MATCH_LH 0x1003U +#define MASK_LH 0x707fU +#define MATCH_LW 0x2003U +#define MASK_LW 0x707fU +#define MATCH_LD 0x3003U +#define MASK_LD 0x707fU +#define MATCH_LBU 0x4003U +#define MASK_LBU 0x707fU +#define MATCH_LHU 0x5003U +#define MASK_LHU 0x707fU +#define MATCH_LWU 0x6003U +#define MASK_LWU 0x707fU +#define MATCH_SB 0x23U +#define MASK_SB 0x707fU +#define MATCH_SH 0x1023U +#define MASK_SH 0x707fU +#define MATCH_SW 0x2023U +#define MASK_SW 0x707fU +#define MATCH_SD 0x3023U +#define MASK_SD 0x707fU +#define MATCH_FENCE 0xfU +#define MASK_FENCE 0x707fU +#define MATCH_FENCE_I 0x100fU +#define MASK_FENCE_I 0x707fU +#define MATCH_MUL 0x2000033U +#define MASK_MUL 0xfe00707fU +#define MATCH_MULH 0x2001033U +#define MASK_MULH 0xfe00707fU +#define MATCH_MULHSU 0x2002033U +#define MASK_MULHSU 0xfe00707fU +#define MATCH_MULHU 0x2003033U +#define MASK_MULHU 0xfe00707fU +#define MATCH_DIV 0x2004033U +#define MASK_DIV 0xfe00707fU +#define MATCH_DIVU 0x2005033U +#define MASK_DIVU 0xfe00707fU +#define MATCH_REM 0x2006033U +#define MASK_REM 0xfe00707fU +#define MATCH_REMU 0x2007033U +#define MASK_REMU 0xfe00707fU +#define MATCH_MULW 0x200003bU +#define MASK_MULW 0xfe00707fU +#define MATCH_DIVW 0x200403bU +#define MASK_DIVW 0xfe00707fU +#define MATCH_DIVUW 0x200503bU +#define MASK_DIVUW 0xfe00707fU +#define MATCH_REMW 0x200603bU +#define MASK_REMW 0xfe00707fU +#define MATCH_REMUW 0x200703bU +#define MASK_REMUW 0xfe00707fU +#define MATCH_AMOADD_W 0x202fU +#define MASK_AMOADD_W 0xf800707fU +#define MATCH_AMOXOR_W 0x2000202fU +#define MASK_AMOXOR_W 0xf800707fU +#define MATCH_AMOOR_W 0x4000202fU +#define MASK_AMOOR_W 0xf800707fU +#define MATCH_AMOAND_W 0x6000202fU +#define MASK_AMOAND_W 0xf800707fU +#define MATCH_AMOMIN_W 0x8000202fU +#define MASK_AMOMIN_W 0xf800707fU +#define MATCH_AMOMAX_W 0xa000202fU +#define MASK_AMOMAX_W 0xf800707fU +#define MATCH_AMOMINU_W 0xc000202fU +#define MASK_AMOMINU_W 0xf800707fU +#define MATCH_AMOMAXU_W 0xe000202fU +#define MASK_AMOMAXU_W 0xf800707fU +#define MATCH_AMOSWAP_W 0x800202fU +#define MASK_AMOSWAP_W 0xf800707fU +#define MATCH_LR_W 0x1000202fU +#define MASK_LR_W 0xf9f0707fU +#define MATCH_SC_W 0x1800202fU +#define MASK_SC_W 0xf800707fU +#define MATCH_AMOADD_D 0x302fU +#define MASK_AMOADD_D 0xf800707fU +#define MATCH_AMOXOR_D 0x2000302fU +#define MASK_AMOXOR_D 0xf800707fU +#define MATCH_AMOOR_D 0x4000302fU +#define MASK_AMOOR_D 0xf800707fU +#define MATCH_AMOAND_D 0x6000302fU +#define MASK_AMOAND_D 0xf800707fU +#define MATCH_AMOMIN_D 0x8000302fU +#define MASK_AMOMIN_D 0xf800707fU +#define MATCH_AMOMAX_D 0xa000302fU +#define MASK_AMOMAX_D 0xf800707fU +#define MATCH_AMOMINU_D 0xc000302fU +#define MASK_AMOMINU_D 0xf800707fU +#define MATCH_AMOMAXU_D 0xe000302fU +#define MASK_AMOMAXU_D 0xf800707fU +#define MATCH_AMOSWAP_D 0x800302fU +#define MASK_AMOSWAP_D 0xf800707fU +#define MATCH_LR_D 0x1000302fU +#define MASK_LR_D 0xf9f0707fU +#define MATCH_SC_D 0x1800302fU +#define MASK_SC_D 0xf800707fU +#define MATCH_ECALL 0x73U +#define MASK_ECALL 0xffffffffU +#define MATCH_EBREAK 0x100073U +#define MASK_EBREAK 0xffffffffU +#define MATCH_URET 0x200073U +#define MASK_URET 0xffffffffU +#define MATCH_SRET 0x10200073U +#define MASK_SRET 0xffffffffU +#define MATCH_HRET 0x20200073U +#define MASK_HRET 0xffffffffU +#define MATCH_MRET 0x30200073U +#define MASK_MRET 0xffffffffU +#define MATCH_DRET 0x7b200073U +#define MASK_DRET 0xffffffffU +#define MATCH_SFENCE_VM 0x10400073U +#define MASK_SFENCE_VM 0xfff07fffU +#define MATCH_WFI 0x10500073U +#define MASK_WFI 0xffffffffU +#define MATCH_CSRRW 0x1073U +#define MASK_CSRRW 0x707fU +#define MATCH_CSRRS 0x2073U +#define MASK_CSRRS 0x707fU +#define MATCH_CSRRC 0x3073U +#define MASK_CSRRC 0x707fU +#define MATCH_CSRRWI 0x5073U +#define MASK_CSRRWI 0x707fU +#define MATCH_CSRRSI 0x6073U +#define MASK_CSRRSI 0x707fU +#define MATCH_CSRRCI 0x7073U +#define MASK_CSRRCI 0x707fU +#define MATCH_FADD_S 0x53U +#define MASK_FADD_S 0xfe00007fU +#define MATCH_FSUB_S 0x8000053U +#define MASK_FSUB_S 0xfe00007fU +#define MATCH_FMUL_S 0x10000053U +#define MASK_FMUL_S 0xfe00007fU +#define MATCH_FDIV_S 0x18000053U +#define MASK_FDIV_S 0xfe00007fU +#define MATCH_FSGNJ_S 0x20000053U +#define MASK_FSGNJ_S 0xfe00707fU +#define MATCH_FSGNJN_S 0x20001053U +#define MASK_FSGNJN_S 0xfe00707fU +#define MATCH_FSGNJX_S 0x20002053U +#define MASK_FSGNJX_S 0xfe00707fU +#define MATCH_FMIN_S 0x28000053U +#define MASK_FMIN_S 0xfe00707fU +#define MATCH_FMAX_S 0x28001053U +#define MASK_FMAX_S 0xfe00707fU +#define MATCH_FSQRT_S 0x58000053U +#define MASK_FSQRT_S 0xfff0007fU +#define MATCH_FADD_D 0x2000053U +#define MASK_FADD_D 0xfe00007fU +#define MATCH_FSUB_D 0xa000053U +#define MASK_FSUB_D 0xfe00007fU +#define MATCH_FMUL_D 0x12000053U +#define MASK_FMUL_D 0xfe00007fU +#define MATCH_FDIV_D 0x1a000053U +#define MASK_FDIV_D 0xfe00007fU +#define MATCH_FSGNJ_D 0x22000053U +#define MASK_FSGNJ_D 0xfe00707fU +#define MATCH_FSGNJN_D 0x22001053U +#define MASK_FSGNJN_D 0xfe00707fU +#define MATCH_FSGNJX_D 0x22002053U +#define MASK_FSGNJX_D 0xfe00707fU +#define MATCH_FMIN_D 0x2a000053U +#define MASK_FMIN_D 0xfe00707fU +#define MATCH_FMAX_D 0x2a001053U +#define MASK_FMAX_D 0xfe00707fU +#define MATCH_FCVT_S_D 0x40100053U +#define MASK_FCVT_S_D 0xfff0007fU +#define MATCH_FCVT_D_S 0x42000053U +#define MASK_FCVT_D_S 0xfff0007fU +#define MATCH_FSQRT_D 0x5a000053U +#define MASK_FSQRT_D 0xfff0007fU +#define MATCH_FLE_S 0xa0000053U +#define MASK_FLE_S 0xfe00707fU +#define MATCH_FLT_S 0xa0001053U +#define MASK_FLT_S 0xfe00707fU +#define MATCH_FEQ_S 0xa0002053U +#define MASK_FEQ_S 0xfe00707fU +#define MATCH_FLE_D 0xa2000053U +#define MASK_FLE_D 0xfe00707fU +#define MATCH_FLT_D 0xa2001053U +#define MASK_FLT_D 0xfe00707fU +#define MATCH_FEQ_D 0xa2002053U +#define MASK_FEQ_D 0xfe00707fU +#define MATCH_FCVT_W_S 0xc0000053U +#define MASK_FCVT_W_S 0xfff0007fU +#define MATCH_FCVT_WU_S 0xc0100053U +#define MASK_FCVT_WU_S 0xfff0007fU +#define MATCH_FCVT_L_S 0xc0200053U +#define MASK_FCVT_L_S 0xfff0007fU +#define MATCH_FCVT_LU_S 0xc0300053U +#define MASK_FCVT_LU_S 0xfff0007fU +#define MATCH_FMV_X_S 0xe0000053U +#define MASK_FMV_X_S 0xfff0707fU +#define MATCH_FCLASS_S 0xe0001053U +#define MASK_FCLASS_S 0xfff0707fU +#define MATCH_FCVT_W_D 0xc2000053U +#define MASK_FCVT_W_D 0xfff0007fU +#define MATCH_FCVT_WU_D 0xc2100053U +#define MASK_FCVT_WU_D 0xfff0007fU +#define MATCH_FCVT_L_D 0xc2200053U +#define MASK_FCVT_L_D 0xfff0007fU +#define MATCH_FCVT_LU_D 0xc2300053U +#define MASK_FCVT_LU_D 0xfff0007fU +#define MATCH_FMV_X_D 0xe2000053U +#define MASK_FMV_X_D 0xfff0707fU +#define MATCH_FCLASS_D 0xe2001053U +#define MASK_FCLASS_D 0xfff0707fU +#define MATCH_FCVT_S_W 0xd0000053U +#define MASK_FCVT_S_W 0xfff0007fU +#define MATCH_FCVT_S_WU 0xd0100053U +#define MASK_FCVT_S_WU 0xfff0007fU +#define MATCH_FCVT_S_L 0xd0200053U +#define MASK_FCVT_S_L 0xfff0007fU +#define MATCH_FCVT_S_LU 0xd0300053U +#define MASK_FCVT_S_LU 0xfff0007fU +#define MATCH_FMV_S_X 0xf0000053U +#define MASK_FMV_S_X 0xfff0707fU +#define MATCH_FCVT_D_W 0xd2000053U +#define MASK_FCVT_D_W 0xfff0007fU +#define MATCH_FCVT_D_WU 0xd2100053U +#define MASK_FCVT_D_WU 0xfff0007fU +#define MATCH_FCVT_D_L 0xd2200053U +#define MASK_FCVT_D_L 0xfff0007fU +#define MATCH_FCVT_D_LU 0xd2300053U +#define MASK_FCVT_D_LU 0xfff0007fU +#define MATCH_FMV_D_X 0xf2000053U +#define MASK_FMV_D_X 0xfff0707fU +#define MATCH_FLW 0x2007U +#define MASK_FLW 0x707fU +#define MATCH_FLD 0x3007U +#define MASK_FLD 0x707fU +#define MATCH_FSW 0x2027U +#define MASK_FSW 0x707fU +#define MATCH_FSD 0x3027U +#define MASK_FSD 0x707fU +#define MATCH_FMADD_S 0x43U +#define MASK_FMADD_S 0x600007fU +#define MATCH_FMSUB_S 0x47U +#define MASK_FMSUB_S 0x600007fU +#define MATCH_FNMSUB_S 0x4bU +#define MASK_FNMSUB_S 0x600007fU +#define MATCH_FNMADD_S 0x4fU +#define MASK_FNMADD_S 0x600007fU +#define MATCH_FMADD_D 0x2000043U +#define MASK_FMADD_D 0x600007fU +#define MATCH_FMSUB_D 0x2000047U +#define MASK_FMSUB_D 0x600007fU +#define MATCH_FNMSUB_D 0x200004bU +#define MASK_FNMSUB_D 0x600007fU +#define MATCH_FNMADD_D 0x200004fU +#define MASK_FNMADD_D 0x600007fU +#define MATCH_C_NOP 0x1U +#define MASK_C_NOP 0xffffU +#define MATCH_C_ADDI16SP 0x6101U +#define MASK_C_ADDI16SP 0xef83U +#define MATCH_C_JR 0x8002U +#define MASK_C_JR 0xf07fU +#define MATCH_C_JALR 0x9002U +#define MASK_C_JALR 0xf07fU +#define MATCH_C_EBREAK 0x9002U +#define MASK_C_EBREAK 0xffffU +#define MATCH_C_LD 0x6000U +#define MASK_C_LD 0xe003U +#define MATCH_C_SD 0xe000U +#define MASK_C_SD 0xe003U +#define MATCH_C_ADDIW 0x2001U +#define MASK_C_ADDIW 0xe003U +#define MATCH_C_LDSP 0x6002U +#define MASK_C_LDSP 0xe003U +#define MATCH_C_SDSP 0xe002U +#define MASK_C_SDSP 0xe003U +#define MATCH_C_ADDI4SPN 0x0U +#define MASK_C_ADDI4SPN 0xe003U +#define MATCH_C_FLD 0x2000U +#define MASK_C_FLD 0xe003U +#define MATCH_C_LW 0x4000U +#define MASK_C_LW 0xe003U +#define MATCH_C_FLW 0x6000U +#define MASK_C_FLW 0xe003U +#define MATCH_C_FSD 0xa000U +#define MASK_C_FSD 0xe003U +#define MATCH_C_SW 0xc000U +#define MASK_C_SW 0xe003U +#define MATCH_C_FSW 0xe000U +#define MASK_C_FSW 0xe003U +#define MATCH_C_ADDI 0x1U +#define MASK_C_ADDI 0xe003U +#define MATCH_C_JAL 0x2001U +#define MASK_C_JAL 0xe003U +#define MATCH_C_LI 0x4001U +#define MASK_C_LI 0xe003U +#define MATCH_C_LUI 0x6001U +#define MASK_C_LUI 0xe003U +#define MATCH_C_SRLI 0x8001U +#define MASK_C_SRLI 0xec03U +#define MATCH_C_SRAI 0x8401U +#define MASK_C_SRAI 0xec03U +#define MATCH_C_ANDI 0x8801U +#define MASK_C_ANDI 0xec03U +#define MATCH_C_SUB 0x8c01U +#define MASK_C_SUB 0xfc63U +#define MATCH_C_XOR 0x8c21U +#define MASK_C_XOR 0xfc63U +#define MATCH_C_OR 0x8c41U +#define MASK_C_OR 0xfc63U +#define MATCH_C_AND 0x8c61U +#define MASK_C_AND 0xfc63U +#define MATCH_C_SUBW 0x9c01U +#define MASK_C_SUBW 0xfc63U +#define MATCH_C_ADDW 0x9c21U +#define MASK_C_ADDW 0xfc63U +#define MATCH_C_J 0xa001U +#define MASK_C_J 0xe003U +#define MATCH_C_BEQZ 0xc001U +#define MASK_C_BEQZ 0xe003U +#define MATCH_C_BNEZ 0xe001U +#define MASK_C_BNEZ 0xe003U +#define MATCH_C_SLLI 0x2U +#define MASK_C_SLLI 0xe003U +#define MATCH_C_FLDSP 0x2002U +#define MASK_C_FLDSP 0xe003U +#define MATCH_C_LWSP 0x4002U +#define MASK_C_LWSP 0xe003U +#define MATCH_C_FLWSP 0x6002U +#define MASK_C_FLWSP 0xe003U +#define MATCH_C_MV 0x8002U +#define MASK_C_MV 0xf003U +#define MATCH_C_ADD 0x9002U +#define MASK_C_ADD 0xf003U +#define MATCH_C_FSDSP 0xa002U +#define MASK_C_FSDSP 0xe003U +#define MATCH_C_SWSP 0xc002U +#define MASK_C_SWSP 0xe003U +#define MATCH_C_FSWSP 0xe002U +#define MASK_C_FSWSP 0xe003U +#define MATCH_CUSTOM0 0xbU +#define MASK_CUSTOM0 0x707fU +#define MATCH_CUSTOM0_RS1 0x200bU +#define MASK_CUSTOM0_RS1 0x707fU +#define MATCH_CUSTOM0_RS1_RS2 0x300bU +#define MASK_CUSTOM0_RS1_RS2 0x707fU +#define MATCH_CUSTOM0_RD 0x400bU +#define MASK_CUSTOM0_RD 0x707fU +#define MATCH_CUSTOM0_RD_RS1 0x600bU +#define MASK_CUSTOM0_RD_RS1 0x707fU +#define MATCH_CUSTOM0_RD_RS1_RS2 0x700bU +#define MASK_CUSTOM0_RD_RS1_RS2 0x707fU +#define MATCH_CUSTOM1 0x2bU +#define MASK_CUSTOM1 0x707fU +#define MATCH_CUSTOM1_RS1 0x202bU +#define MASK_CUSTOM1_RS1 0x707fU +#define MATCH_CUSTOM1_RS1_RS2 0x302bU +#define MASK_CUSTOM1_RS1_RS2 0x707fU +#define MATCH_CUSTOM1_RD 0x402bU +#define MASK_CUSTOM1_RD 0x707fU +#define MATCH_CUSTOM1_RD_RS1 0x602bU +#define MASK_CUSTOM1_RD_RS1 0x707fU +#define MATCH_CUSTOM1_RD_RS1_RS2 0x702bU +#define MASK_CUSTOM1_RD_RS1_RS2 0x707fU +#define MATCH_CUSTOM2 0x5bU +#define MASK_CUSTOM2 0x707fU +#define MATCH_CUSTOM2_RS1 0x205bU +#define MASK_CUSTOM2_RS1 0x707fU +#define MATCH_CUSTOM2_RS1_RS2 0x305bU +#define MASK_CUSTOM2_RS1_RS2 0x707fU +#define MATCH_CUSTOM2_RD 0x405bU +#define MASK_CUSTOM2_RD 0x707fU +#define MATCH_CUSTOM2_RD_RS1 0x605bU +#define MASK_CUSTOM2_RD_RS1 0x707fU +#define MATCH_CUSTOM2_RD_RS1_RS2 0x705bU +#define MASK_CUSTOM2_RD_RS1_RS2 0x707fU +#define MATCH_CUSTOM3 0x7bU +#define MASK_CUSTOM3 0x707fU +#define MATCH_CUSTOM3_RS1 0x207bU +#define MASK_CUSTOM3_RS1 0x707fU +#define MATCH_CUSTOM3_RS1_RS2 0x307bU +#define MASK_CUSTOM3_RS1_RS2 0x707fU +#define MATCH_CUSTOM3_RD 0x407bU +#define MASK_CUSTOM3_RD 0x707fU +#define MATCH_CUSTOM3_RD_RS1 0x607bU +#define MASK_CUSTOM3_RD_RS1 0x707fU +#define MATCH_CUSTOM3_RD_RS1_RS2 0x707bU +#define MASK_CUSTOM3_RD_RS1_RS2 0x707fU +#define CSR_FFLAGS 0x1U +#define CSR_FRM 0x2U +#define CSR_FCSR 0x3U +#define CSR_CYCLE 0xc00U +#define CSR_TIME 0xc01U +#define CSR_INSTRET 0xc02U +#define CSR_HPMCOUNTER3 0xc03U +#define CSR_HPMCOUNTER4 0xc04U +#define CSR_HPMCOUNTER5 0xc05U +#define CSR_HPMCOUNTER6 0xc06U +#define CSR_HPMCOUNTER7 0xc07U +#define CSR_HPMCOUNTER8 0xc08U +#define CSR_HPMCOUNTER9 0xc09U +#define CSR_HPMCOUNTER10 0xc0aU +#define CSR_HPMCOUNTER11 0xc0bU +#define CSR_HPMCOUNTER12 0xc0cU +#define CSR_HPMCOUNTER13 0xc0dU +#define CSR_HPMCOUNTER14 0xc0eU +#define CSR_HPMCOUNTER15 0xc0fU +#define CSR_HPMCOUNTER16 0xc10U +#define CSR_HPMCOUNTER17 0xc11U +#define CSR_HPMCOUNTER18 0xc12U +#define CSR_HPMCOUNTER19 0xc13U +#define CSR_HPMCOUNTER20 0xc14U +#define CSR_HPMCOUNTER21 0xc15U +#define CSR_HPMCOUNTER22 0xc16U +#define CSR_HPMCOUNTER23 0xc17U +#define CSR_HPMCOUNTER24 0xc18U +#define CSR_HPMCOUNTER25 0xc19U +#define CSR_HPMCOUNTER26 0xc1aU +#define CSR_HPMCOUNTER27 0xc1bU +#define CSR_HPMCOUNTER28 0xc1cU +#define CSR_HPMCOUNTER29 0xc1dU +#define CSR_HPMCOUNTER30 0xc1eU +#define CSR_HPMCOUNTER31 0xc1fU +#define CSR_SSTATUS 0x100U +#define CSR_SIE 0x104U +#define CSR_STVEC 0x105U +#define CSR_SSCRATCH 0x140U +#define CSR_SEPC 0x141U +#define CSR_SCAUSE 0x142U +#define CSR_SBADADDR 0x143U +#define CSR_SIP 0x144U +#define CSR_SPTBR 0x180U +#define CSR_MSTATUS 0x300U +#define CSR_MISA 0x301U +#define CSR_MEDELEG 0x302U +#define CSR_MIDELEG 0x303U +#define CSR_MIE 0x304U +#define CSR_MTVEC 0x305U +#define CSR_MSCRATCH 0x340U +#define CSR_MEPC 0x341U +#define CSR_MCAUSE 0x342U +#define CSR_MBADADDR 0x343U +#define CSR_MIP 0x344U +#define CSR_TSELECT 0x7a0U +#define CSR_TDATA1 0x7a1U +#define CSR_TDATA2 0x7a2U +#define CSR_TDATA3 0x7a3U +#define CSR_DCSR 0x7b0U +#define CSR_DPC 0x7b1U +#define CSR_DSCRATCH 0x7b2U +#define CSR_MCYCLE 0xb00U +#define CSR_MINSTRET 0xb02U +#define CSR_MHPMCOUNTER3 0xb03U +#define CSR_MHPMCOUNTER4 0xb04U +#define CSR_MHPMCOUNTER5 0xb05U +#define CSR_MHPMCOUNTER6 0xb06U +#define CSR_MHPMCOUNTER7 0xb07U +#define CSR_MHPMCOUNTER8 0xb08U +#define CSR_MHPMCOUNTER9 0xb09U +#define CSR_MHPMCOUNTER10 0xb0aU +#define CSR_MHPMCOUNTER11 0xb0bU +#define CSR_MHPMCOUNTER12 0xb0cU +#define CSR_MHPMCOUNTER13 0xb0dU +#define CSR_MHPMCOUNTER14 0xb0eU +#define CSR_MHPMCOUNTER15 0xb0fU +#define CSR_MHPMCOUNTER16 0xb10U +#define CSR_MHPMCOUNTER17 0xb11U +#define CSR_MHPMCOUNTER18 0xb12U +#define CSR_MHPMCOUNTER19 0xb13U +#define CSR_MHPMCOUNTER20 0xb14U +#define CSR_MHPMCOUNTER21 0xb15U +#define CSR_MHPMCOUNTER22 0xb16U +#define CSR_MHPMCOUNTER23 0xb17U +#define CSR_MHPMCOUNTER24 0xb18U +#define CSR_MHPMCOUNTER25 0xb19U +#define CSR_MHPMCOUNTER26 0xb1aU +#define CSR_MHPMCOUNTER27 0xb1bU +#define CSR_MHPMCOUNTER28 0xb1cU +#define CSR_MHPMCOUNTER29 0xb1dU +#define CSR_MHPMCOUNTER30 0xb1eU +#define CSR_MHPMCOUNTER31 0xb1fU +#define CSR_MUCOUNTEREN 0x320U +#define CSR_MSCOUNTEREN 0x321U +#define CSR_MHPMEVENT3 0x323U +#define CSR_MHPMEVENT4 0x324U +#define CSR_MHPMEVENT5 0x325U +#define CSR_MHPMEVENT6 0x326U +#define CSR_MHPMEVENT7 0x327U +#define CSR_MHPMEVENT8 0x328U +#define CSR_MHPMEVENT9 0x329U +#define CSR_MHPMEVENT10 0x32aU +#define CSR_MHPMEVENT11 0x32bU +#define CSR_MHPMEVENT12 0x32cU +#define CSR_MHPMEVENT13 0x32dU +#define CSR_MHPMEVENT14 0x32eU +#define CSR_MHPMEVENT15 0x32fU +#define CSR_MHPMEVENT16 0x330U +#define CSR_MHPMEVENT17 0x331U +#define CSR_MHPMEVENT18 0x332U +#define CSR_MHPMEVENT19 0x333U +#define CSR_MHPMEVENT20 0x334U +#define CSR_MHPMEVENT21 0x335U +#define CSR_MHPMEVENT22 0x336U +#define CSR_MHPMEVENT23 0x337U +#define CSR_MHPMEVENT24 0x338U +#define CSR_MHPMEVENT25 0x339U +#define CSR_MHPMEVENT26 0x33aU +#define CSR_MHPMEVENT27 0x33bU +#define CSR_MHPMEVENT28 0x33cU +#define CSR_MHPMEVENT29 0x33dU +#define CSR_MHPMEVENT30 0x33eU +#define CSR_MHPMEVENT31 0x33fU +#define CSR_MVENDORID 0xf11U +#define CSR_MARCHID 0xf12U +#define CSR_MIMPID 0xf13U +#define CSR_MHARTID 0xf14U +#define CSR_CYCLEH 0xc80U +#define CSR_TIMEH 0xc81U +#define CSR_INSTRETH 0xc82U +#define CSR_HPMCOUNTER3H 0xc83U +#define CSR_HPMCOUNTER4H 0xc84U +#define CSR_HPMCOUNTER5H 0xc85U +#define CSR_HPMCOUNTER6H 0xc86U +#define CSR_HPMCOUNTER7H 0xc87U +#define CSR_HPMCOUNTER8H 0xc88U +#define CSR_HPMCOUNTER9H 0xc89U +#define CSR_HPMCOUNTER10H 0xc8aU +#define CSR_HPMCOUNTER11H 0xc8bU +#define CSR_HPMCOUNTER12H 0xc8cU +#define CSR_HPMCOUNTER13H 0xc8dU +#define CSR_HPMCOUNTER14H 0xc8eU +#define CSR_HPMCOUNTER15H 0xc8fU +#define CSR_HPMCOUNTER16H 0xc90U +#define CSR_HPMCOUNTER17H 0xc91U +#define CSR_HPMCOUNTER18H 0xc92U +#define CSR_HPMCOUNTER19H 0xc93U +#define CSR_HPMCOUNTER20H 0xc94U +#define CSR_HPMCOUNTER21H 0xc95U +#define CSR_HPMCOUNTER22H 0xc96U +#define CSR_HPMCOUNTER23H 0xc97U +#define CSR_HPMCOUNTER24H 0xc98U +#define CSR_HPMCOUNTER25H 0xc99U +#define CSR_HPMCOUNTER26H 0xc9aU +#define CSR_HPMCOUNTER27H 0xc9bU +#define CSR_HPMCOUNTER28H 0xc9cU +#define CSR_HPMCOUNTER29H 0xc9dU +#define CSR_HPMCOUNTER30H 0xc9eU +#define CSR_HPMCOUNTER31H 0xc9fU +#define CSR_MCYCLEH 0xb80U +#define CSR_MINSTRETH 0xb82U +#define CSR_MHPMCOUNTER3H 0xb83U +#define CSR_MHPMCOUNTER4H 0xb84U +#define CSR_MHPMCOUNTER5H 0xb85U +#define CSR_MHPMCOUNTER6H 0xb86U +#define CSR_MHPMCOUNTER7H 0xb87U +#define CSR_MHPMCOUNTER8H 0xb88U +#define CSR_MHPMCOUNTER9H 0xb89U +#define CSR_MHPMCOUNTER10H 0xb8aU +#define CSR_MHPMCOUNTER11H 0xb8bU +#define CSR_MHPMCOUNTER12H 0xb8cU +#define CSR_MHPMCOUNTER13H 0xb8dU +#define CSR_MHPMCOUNTER14H 0xb8eU +#define CSR_MHPMCOUNTER15H 0xb8fU +#define CSR_MHPMCOUNTER16H 0xb90U +#define CSR_MHPMCOUNTER17H 0xb91U +#define CSR_MHPMCOUNTER18H 0xb92U +#define CSR_MHPMCOUNTER19H 0xb93U +#define CSR_MHPMCOUNTER20H 0xb94U +#define CSR_MHPMCOUNTER21H 0xb95U +#define CSR_MHPMCOUNTER22H 0xb96U +#define CSR_MHPMCOUNTER23H 0xb97U +#define CSR_MHPMCOUNTER24H 0xb98U +#define CSR_MHPMCOUNTER25H 0xb99U +#define CSR_MHPMCOUNTER26H 0xb9aU +#define CSR_MHPMCOUNTER27H 0xb9bU +#define CSR_MHPMCOUNTER28H 0xb9cU +#define CSR_MHPMCOUNTER29H 0xb9dU +#define CSR_MHPMCOUNTER30H 0xb9eU +#define CSR_MHPMCOUNTER31H 0xb9fU +#define CAUSE_MISALIGNED_FETCH 0x0 +#define CAUSE_FAULT_FETCH 0x1 +#define CAUSE_ILLEGAL_INSTRUCTION 0x2 +#define CAUSE_BREAKPOINT 0x3 +#define CAUSE_MISALIGNED_LOAD 0x4 +#define CAUSE_FAULT_LOAD 0x5 +#define CAUSE_MISALIGNED_STORE 0x6 +#define CAUSE_FAULT_STORE 0x7 +#define CAUSE_USER_ECALL 0x8 +#define CAUSE_SUPERVISOR_ECALL 0x9 +#define CAUSE_HYPERVISOR_ECALL 0xa +#define CAUSE_MACHINE_ECALL 0xb +#endif +#if defined(DECLARE_INSN) +DECLARE_INSN(beq, MATCH_BEQ, MASK_BEQ) +DECLARE_INSN(bne, MATCH_BNE, MASK_BNE) +DECLARE_INSN(blt, MATCH_BLT, MASK_BLT) +DECLARE_INSN(bge, MATCH_BGE, MASK_BGE) +DECLARE_INSN(bltu, MATCH_BLTU, MASK_BLTU) +DECLARE_INSN(bgeu, MATCH_BGEU, MASK_BGEU) +DECLARE_INSN(jalr, MATCH_JALR, MASK_JALR) +DECLARE_INSN(jal, MATCH_JAL, MASK_JAL) +DECLARE_INSN(lui, MATCH_LUI, MASK_LUI) +DECLARE_INSN(auipc, MATCH_AUIPC, MASK_AUIPC) +DECLARE_INSN(addi, MATCH_ADDI, MASK_ADDI) +DECLARE_INSN(slli, MATCH_SLLI, MASK_SLLI) +DECLARE_INSN(slti, MATCH_SLTI, MASK_SLTI) +DECLARE_INSN(sltiu, MATCH_SLTIU, MASK_SLTIU) +DECLARE_INSN(xori, MATCH_XORI, MASK_XORI) +DECLARE_INSN(srli, MATCH_SRLI, MASK_SRLI) +DECLARE_INSN(srai, MATCH_SRAI, MASK_SRAI) +DECLARE_INSN(ori, MATCH_ORI, MASK_ORI) +DECLARE_INSN(andi, MATCH_ANDI, MASK_ANDI) +DECLARE_INSN(add, MATCH_ADD, MASK_ADD) +DECLARE_INSN(sub, MATCH_SUB, MASK_SUB) +DECLARE_INSN(sll, MATCH_SLL, MASK_SLL) +DECLARE_INSN(slt, MATCH_SLT, MASK_SLT) +DECLARE_INSN(sltu, MATCH_SLTU, MASK_SLTU) +DECLARE_INSN(xor, MATCH_XOR, MASK_XOR) +DECLARE_INSN(srl, MATCH_SRL, MASK_SRL) +DECLARE_INSN(sra, MATCH_SRA, MASK_SRA) +DECLARE_INSN(or, MATCH_OR, MASK_OR) +DECLARE_INSN(and, MATCH_AND, MASK_AND) +DECLARE_INSN(addiw, MATCH_ADDIW, MASK_ADDIW) +DECLARE_INSN(slliw, MATCH_SLLIW, MASK_SLLIW) +DECLARE_INSN(srliw, MATCH_SRLIW, MASK_SRLIW) +DECLARE_INSN(sraiw, MATCH_SRAIW, MASK_SRAIW) +DECLARE_INSN(addw, MATCH_ADDW, MASK_ADDW) +DECLARE_INSN(subw, MATCH_SUBW, MASK_SUBW) +DECLARE_INSN(sllw, MATCH_SLLW, MASK_SLLW) +DECLARE_INSN(srlw, MATCH_SRLW, MASK_SRLW) +DECLARE_INSN(sraw, MATCH_SRAW, MASK_SRAW) +DECLARE_INSN(lb, MATCH_LB, MASK_LB) +DECLARE_INSN(lh, MATCH_LH, MASK_LH) +DECLARE_INSN(lw, MATCH_LW, MASK_LW) +DECLARE_INSN(ld, MATCH_LD, MASK_LD) +DECLARE_INSN(lbu, MATCH_LBU, MASK_LBU) +DECLARE_INSN(lhu, MATCH_LHU, MASK_LHU) +DECLARE_INSN(lwu, MATCH_LWU, MASK_LWU) +DECLARE_INSN(sb, MATCH_SB, MASK_SB) +DECLARE_INSN(sh, MATCH_SH, MASK_SH) +DECLARE_INSN(sw, MATCH_SW, MASK_SW) +DECLARE_INSN(sd, MATCH_SD, MASK_SD) +DECLARE_INSN(fence, MATCH_FENCE, MASK_FENCE) +DECLARE_INSN(fence_i, MATCH_FENCE_I, MASK_FENCE_I) +DECLARE_INSN(mul, MATCH_MUL, MASK_MUL) +DECLARE_INSN(mulh, MATCH_MULH, MASK_MULH) +DECLARE_INSN(mulhsu, MATCH_MULHSU, MASK_MULHSU) +DECLARE_INSN(mulhu, MATCH_MULHU, MASK_MULHU) +DECLARE_INSN(div, MATCH_DIV, MASK_DIV) +DECLARE_INSN(divu, MATCH_DIVU, MASK_DIVU) +DECLARE_INSN(rem, MATCH_REM, MASK_REM) +DECLARE_INSN(remu, MATCH_REMU, MASK_REMU) +DECLARE_INSN(mulw, MATCH_MULW, MASK_MULW) +DECLARE_INSN(divw, MATCH_DIVW, MASK_DIVW) +DECLARE_INSN(divuw, MATCH_DIVUW, MASK_DIVUW) +DECLARE_INSN(remw, MATCH_REMW, MASK_REMW) +DECLARE_INSN(remuw, MATCH_REMUW, MASK_REMUW) +DECLARE_INSN(amoadd_w, MATCH_AMOADD_W, MASK_AMOADD_W) +DECLARE_INSN(amoxor_w, MATCH_AMOXOR_W, MASK_AMOXOR_W) +DECLARE_INSN(amoor_w, MATCH_AMOOR_W, MASK_AMOOR_W) +DECLARE_INSN(amoand_w, MATCH_AMOAND_W, MASK_AMOAND_W) +DECLARE_INSN(amomin_w, MATCH_AMOMIN_W, MASK_AMOMIN_W) +DECLARE_INSN(amomax_w, MATCH_AMOMAX_W, MASK_AMOMAX_W) +DECLARE_INSN(amominu_w, MATCH_AMOMINU_W, MASK_AMOMINU_W) +DECLARE_INSN(amomaxu_w, MATCH_AMOMAXU_W, MASK_AMOMAXU_W) +DECLARE_INSN(amoswap_w, MATCH_AMOSWAP_W, MASK_AMOSWAP_W) +DECLARE_INSN(lr_w, MATCH_LR_W, MASK_LR_W) +DECLARE_INSN(sc_w, MATCH_SC_W, MASK_SC_W) +DECLARE_INSN(amoadd_d, MATCH_AMOADD_D, MASK_AMOADD_D) +DECLARE_INSN(amoxor_d, MATCH_AMOXOR_D, MASK_AMOXOR_D) +DECLARE_INSN(amoor_d, MATCH_AMOOR_D, MASK_AMOOR_D) +DECLARE_INSN(amoand_d, MATCH_AMOAND_D, MASK_AMOAND_D) +DECLARE_INSN(amomin_d, MATCH_AMOMIN_D, MASK_AMOMIN_D) +DECLARE_INSN(amomax_d, MATCH_AMOMAX_D, MASK_AMOMAX_D) +DECLARE_INSN(amominu_d, MATCH_AMOMINU_D, MASK_AMOMINU_D) +DECLARE_INSN(amomaxu_d, MATCH_AMOMAXU_D, MASK_AMOMAXU_D) +DECLARE_INSN(amoswap_d, MATCH_AMOSWAP_D, MASK_AMOSWAP_D) +DECLARE_INSN(lr_d, MATCH_LR_D, MASK_LR_D) +DECLARE_INSN(sc_d, MATCH_SC_D, MASK_SC_D) +DECLARE_INSN(ecall, MATCH_ECALL, MASK_ECALL) +DECLARE_INSN(ebreak, MATCH_EBREAK, MASK_EBREAK) +DECLARE_INSN(uret, MATCH_URET, MASK_URET) +DECLARE_INSN(sret, MATCH_SRET, MASK_SRET) +DECLARE_INSN(hret, MATCH_HRET, MASK_HRET) +DECLARE_INSN(mret, MATCH_MRET, MASK_MRET) +DECLARE_INSN(dret, MATCH_DRET, MASK_DRET) +DECLARE_INSN(sfence_vm, MATCH_SFENCE_VM, MASK_SFENCE_VM) +DECLARE_INSN(wfi, MATCH_WFI, MASK_WFI) +DECLARE_INSN(csrrw, MATCH_CSRRW, MASK_CSRRW) +DECLARE_INSN(csrrs, MATCH_CSRRS, MASK_CSRRS) +DECLARE_INSN(csrrc, MATCH_CSRRC, MASK_CSRRC) +DECLARE_INSN(csrrwi, MATCH_CSRRWI, MASK_CSRRWI) +DECLARE_INSN(csrrsi, MATCH_CSRRSI, MASK_CSRRSI) +DECLARE_INSN(csrrci, MATCH_CSRRCI, MASK_CSRRCI) +DECLARE_INSN(fadd_s, MATCH_FADD_S, MASK_FADD_S) +DECLARE_INSN(fsub_s, MATCH_FSUB_S, MASK_FSUB_S) +DECLARE_INSN(fmul_s, MATCH_FMUL_S, MASK_FMUL_S) +DECLARE_INSN(fdiv_s, MATCH_FDIV_S, MASK_FDIV_S) +DECLARE_INSN(fsgnj_s, MATCH_FSGNJ_S, MASK_FSGNJ_S) +DECLARE_INSN(fsgnjn_s, MATCH_FSGNJN_S, MASK_FSGNJN_S) +DECLARE_INSN(fsgnjx_s, MATCH_FSGNJX_S, MASK_FSGNJX_S) +DECLARE_INSN(fmin_s, MATCH_FMIN_S, MASK_FMIN_S) +DECLARE_INSN(fmax_s, MATCH_FMAX_S, MASK_FMAX_S) +DECLARE_INSN(fsqrt_s, MATCH_FSQRT_S, MASK_FSQRT_S) +DECLARE_INSN(fadd_d, MATCH_FADD_D, MASK_FADD_D) +DECLARE_INSN(fsub_d, MATCH_FSUB_D, MASK_FSUB_D) +DECLARE_INSN(fmul_d, MATCH_FMUL_D, MASK_FMUL_D) +DECLARE_INSN(fdiv_d, MATCH_FDIV_D, MASK_FDIV_D) +DECLARE_INSN(fsgnj_d, MATCH_FSGNJ_D, MASK_FSGNJ_D) +DECLARE_INSN(fsgnjn_d, MATCH_FSGNJN_D, MASK_FSGNJN_D) +DECLARE_INSN(fsgnjx_d, MATCH_FSGNJX_D, MASK_FSGNJX_D) +DECLARE_INSN(fmin_d, MATCH_FMIN_D, MASK_FMIN_D) +DECLARE_INSN(fmax_d, MATCH_FMAX_D, MASK_FMAX_D) +DECLARE_INSN(fcvt_s_d, MATCH_FCVT_S_D, MASK_FCVT_S_D) +DECLARE_INSN(fcvt_d_s, MATCH_FCVT_D_S, MASK_FCVT_D_S) +DECLARE_INSN(fsqrt_d, MATCH_FSQRT_D, MASK_FSQRT_D) +DECLARE_INSN(fle_s, MATCH_FLE_S, MASK_FLE_S) +DECLARE_INSN(flt_s, MATCH_FLT_S, MASK_FLT_S) +DECLARE_INSN(feq_s, MATCH_FEQ_S, MASK_FEQ_S) +DECLARE_INSN(fle_d, MATCH_FLE_D, MASK_FLE_D) +DECLARE_INSN(flt_d, MATCH_FLT_D, MASK_FLT_D) +DECLARE_INSN(feq_d, MATCH_FEQ_D, MASK_FEQ_D) +DECLARE_INSN(fcvt_w_s, MATCH_FCVT_W_S, MASK_FCVT_W_S) +DECLARE_INSN(fcvt_wu_s, MATCH_FCVT_WU_S, MASK_FCVT_WU_S) +DECLARE_INSN(fcvt_l_s, MATCH_FCVT_L_S, MASK_FCVT_L_S) +DECLARE_INSN(fcvt_lu_s, MATCH_FCVT_LU_S, MASK_FCVT_LU_S) +DECLARE_INSN(fmv_x_s, MATCH_FMV_X_S, MASK_FMV_X_S) +DECLARE_INSN(fclass_s, MATCH_FCLASS_S, MASK_FCLASS_S) +DECLARE_INSN(fcvt_w_d, MATCH_FCVT_W_D, MASK_FCVT_W_D) +DECLARE_INSN(fcvt_wu_d, MATCH_FCVT_WU_D, MASK_FCVT_WU_D) +DECLARE_INSN(fcvt_l_d, MATCH_FCVT_L_D, MASK_FCVT_L_D) +DECLARE_INSN(fcvt_lu_d, MATCH_FCVT_LU_D, MASK_FCVT_LU_D) +DECLARE_INSN(fmv_x_d, MATCH_FMV_X_D, MASK_FMV_X_D) +DECLARE_INSN(fclass_d, MATCH_FCLASS_D, MASK_FCLASS_D) +DECLARE_INSN(fcvt_s_w, MATCH_FCVT_S_W, MASK_FCVT_S_W) +DECLARE_INSN(fcvt_s_wu, MATCH_FCVT_S_WU, MASK_FCVT_S_WU) +DECLARE_INSN(fcvt_s_l, MATCH_FCVT_S_L, MASK_FCVT_S_L) +DECLARE_INSN(fcvt_s_lu, MATCH_FCVT_S_LU, MASK_FCVT_S_LU) +DECLARE_INSN(fmv_s_x, MATCH_FMV_S_X, MASK_FMV_S_X) +DECLARE_INSN(fcvt_d_w, MATCH_FCVT_D_W, MASK_FCVT_D_W) +DECLARE_INSN(fcvt_d_wu, MATCH_FCVT_D_WU, MASK_FCVT_D_WU) +DECLARE_INSN(fcvt_d_l, MATCH_FCVT_D_L, MASK_FCVT_D_L) +DECLARE_INSN(fcvt_d_lu, MATCH_FCVT_D_LU, MASK_FCVT_D_LU) +DECLARE_INSN(fmv_d_x, MATCH_FMV_D_X, MASK_FMV_D_X) +DECLARE_INSN(flw, MATCH_FLW, MASK_FLW) +DECLARE_INSN(fld, MATCH_FLD, MASK_FLD) +DECLARE_INSN(fsw, MATCH_FSW, MASK_FSW) +DECLARE_INSN(fsd, MATCH_FSD, MASK_FSD) +DECLARE_INSN(fmadd_s, MATCH_FMADD_S, MASK_FMADD_S) +DECLARE_INSN(fmsub_s, MATCH_FMSUB_S, MASK_FMSUB_S) +DECLARE_INSN(fnmsub_s, MATCH_FNMSUB_S, MASK_FNMSUB_S) +DECLARE_INSN(fnmadd_s, MATCH_FNMADD_S, MASK_FNMADD_S) +DECLARE_INSN(fmadd_d, MATCH_FMADD_D, MASK_FMADD_D) +DECLARE_INSN(fmsub_d, MATCH_FMSUB_D, MASK_FMSUB_D) +DECLARE_INSN(fnmsub_d, MATCH_FNMSUB_D, MASK_FNMSUB_D) +DECLARE_INSN(fnmadd_d, MATCH_FNMADD_D, MASK_FNMADD_D) +DECLARE_INSN(c_nop, MATCH_C_NOP, MASK_C_NOP) +DECLARE_INSN(c_addi16sp, MATCH_C_ADDI16SP, MASK_C_ADDI16SP) +DECLARE_INSN(c_jr, MATCH_C_JR, MASK_C_JR) +DECLARE_INSN(c_jalr, MATCH_C_JALR, MASK_C_JALR) +DECLARE_INSN(c_ebreak, MATCH_C_EBREAK, MASK_C_EBREAK) +DECLARE_INSN(c_ld, MATCH_C_LD, MASK_C_LD) +DECLARE_INSN(c_sd, MATCH_C_SD, MASK_C_SD) +DECLARE_INSN(c_addiw, MATCH_C_ADDIW, MASK_C_ADDIW) +DECLARE_INSN(c_ldsp, MATCH_C_LDSP, MASK_C_LDSP) +DECLARE_INSN(c_sdsp, MATCH_C_SDSP, MASK_C_SDSP) +DECLARE_INSN(c_addi4spn, MATCH_C_ADDI4SPN, MASK_C_ADDI4SPN) +DECLARE_INSN(c_fld, MATCH_C_FLD, MASK_C_FLD) +DECLARE_INSN(c_lw, MATCH_C_LW, MASK_C_LW) +DECLARE_INSN(c_flw, MATCH_C_FLW, MASK_C_FLW) +DECLARE_INSN(c_fsd, MATCH_C_FSD, MASK_C_FSD) +DECLARE_INSN(c_sw, MATCH_C_SW, MASK_C_SW) +DECLARE_INSN(c_fsw, MATCH_C_FSW, MASK_C_FSW) +DECLARE_INSN(c_addi, MATCH_C_ADDI, MASK_C_ADDI) +DECLARE_INSN(c_jal, MATCH_C_JAL, MASK_C_JAL) +DECLARE_INSN(c_li, MATCH_C_LI, MASK_C_LI) +DECLARE_INSN(c_lui, MATCH_C_LUI, MASK_C_LUI) +DECLARE_INSN(c_srli, MATCH_C_SRLI, MASK_C_SRLI) +DECLARE_INSN(c_srai, MATCH_C_SRAI, MASK_C_SRAI) +DECLARE_INSN(c_andi, MATCH_C_ANDI, MASK_C_ANDI) +DECLARE_INSN(c_sub, MATCH_C_SUB, MASK_C_SUB) +DECLARE_INSN(c_xor, MATCH_C_XOR, MASK_C_XOR) +DECLARE_INSN(c_or, MATCH_C_OR, MASK_C_OR) +DECLARE_INSN(c_and, MATCH_C_AND, MASK_C_AND) +DECLARE_INSN(c_subw, MATCH_C_SUBW, MASK_C_SUBW) +DECLARE_INSN(c_addw, MATCH_C_ADDW, MASK_C_ADDW) +DECLARE_INSN(c_j, MATCH_C_J, MASK_C_J) +DECLARE_INSN(c_beqz, MATCH_C_BEQZ, MASK_C_BEQZ) +DECLARE_INSN(c_bnez, MATCH_C_BNEZ, MASK_C_BNEZ) +DECLARE_INSN(c_slli, MATCH_C_SLLI, MASK_C_SLLI) +DECLARE_INSN(c_fldsp, MATCH_C_FLDSP, MASK_C_FLDSP) +DECLARE_INSN(c_lwsp, MATCH_C_LWSP, MASK_C_LWSP) +DECLARE_INSN(c_flwsp, MATCH_C_FLWSP, MASK_C_FLWSP) +DECLARE_INSN(c_mv, MATCH_C_MV, MASK_C_MV) +DECLARE_INSN(c_add, MATCH_C_ADD, MASK_C_ADD) +DECLARE_INSN(c_fsdsp, MATCH_C_FSDSP, MASK_C_FSDSP) +DECLARE_INSN(c_swsp, MATCH_C_SWSP, MASK_C_SWSP) +DECLARE_INSN(c_fswsp, MATCH_C_FSWSP, MASK_C_FSWSP) +DECLARE_INSN(custom0, MATCH_CUSTOM0, MASK_CUSTOM0) +DECLARE_INSN(custom0_rs1, MATCH_CUSTOM0_RS1, MASK_CUSTOM0_RS1) +DECLARE_INSN(custom0_rs1_rs2, MATCH_CUSTOM0_RS1_RS2, MASK_CUSTOM0_RS1_RS2) +DECLARE_INSN(custom0_rd, MATCH_CUSTOM0_RD, MASK_CUSTOM0_RD) +DECLARE_INSN(custom0_rd_rs1, MATCH_CUSTOM0_RD_RS1, MASK_CUSTOM0_RD_RS1) +DECLARE_INSN(custom0_rd_rs1_rs2, MATCH_CUSTOM0_RD_RS1_RS2, MASK_CUSTOM0_RD_RS1_RS2) +DECLARE_INSN(custom1, MATCH_CUSTOM1, MASK_CUSTOM1) +DECLARE_INSN(custom1_rs1, MATCH_CUSTOM1_RS1, MASK_CUSTOM1_RS1) +DECLARE_INSN(custom1_rs1_rs2, MATCH_CUSTOM1_RS1_RS2, MASK_CUSTOM1_RS1_RS2) +DECLARE_INSN(custom1_rd, MATCH_CUSTOM1_RD, MASK_CUSTOM1_RD) +DECLARE_INSN(custom1_rd_rs1, MATCH_CUSTOM1_RD_RS1, MASK_CUSTOM1_RD_RS1) +DECLARE_INSN(custom1_rd_rs1_rs2, MATCH_CUSTOM1_RD_RS1_RS2, MASK_CUSTOM1_RD_RS1_RS2) +DECLARE_INSN(custom2, MATCH_CUSTOM2, MASK_CUSTOM2) +DECLARE_INSN(custom2_rs1, MATCH_CUSTOM2_RS1, MASK_CUSTOM2_RS1) +DECLARE_INSN(custom2_rs1_rs2, MATCH_CUSTOM2_RS1_RS2, MASK_CUSTOM2_RS1_RS2) +DECLARE_INSN(custom2_rd, MATCH_CUSTOM2_RD, MASK_CUSTOM2_RD) +DECLARE_INSN(custom2_rd_rs1, MATCH_CUSTOM2_RD_RS1, MASK_CUSTOM2_RD_RS1) +DECLARE_INSN(custom2_rd_rs1_rs2, MATCH_CUSTOM2_RD_RS1_RS2, MASK_CUSTOM2_RD_RS1_RS2) +DECLARE_INSN(custom3, MATCH_CUSTOM3, MASK_CUSTOM3) +DECLARE_INSN(custom3_rs1, MATCH_CUSTOM3_RS1, MASK_CUSTOM3_RS1) +DECLARE_INSN(custom3_rs1_rs2, MATCH_CUSTOM3_RS1_RS2, MASK_CUSTOM3_RS1_RS2) +DECLARE_INSN(custom3_rd, MATCH_CUSTOM3_RD, MASK_CUSTOM3_RD) +DECLARE_INSN(custom3_rd_rs1, MATCH_CUSTOM3_RD_RS1, MASK_CUSTOM3_RD_RS1) +DECLARE_INSN(custom3_rd_rs1_rs2, MATCH_CUSTOM3_RD_RS1_RS2, MASK_CUSTOM3_RD_RS1_RS2) +#endif +#if defined(DECLARE_CSR) +DECLARE_CSR(fflags, CSR_FFLAGS) +DECLARE_CSR(frm, CSR_FRM) +DECLARE_CSR(fcsr, CSR_FCSR) +DECLARE_CSR(cycle, CSR_CYCLE) +DECLARE_CSR(time, CSR_TIME) +DECLARE_CSR(instret, CSR_INSTRET) +DECLARE_CSR(hpmcounter3, CSR_HPMCOUNTER3) +DECLARE_CSR(hpmcounter4, CSR_HPMCOUNTER4) +DECLARE_CSR(hpmcounter5, CSR_HPMCOUNTER5) +DECLARE_CSR(hpmcounter6, CSR_HPMCOUNTER6) +DECLARE_CSR(hpmcounter7, CSR_HPMCOUNTER7) +DECLARE_CSR(hpmcounter8, CSR_HPMCOUNTER8) +DECLARE_CSR(hpmcounter9, CSR_HPMCOUNTER9) +DECLARE_CSR(hpmcounter10, CSR_HPMCOUNTER10) +DECLARE_CSR(hpmcounter11, CSR_HPMCOUNTER11) +DECLARE_CSR(hpmcounter12, CSR_HPMCOUNTER12) +DECLARE_CSR(hpmcounter13, CSR_HPMCOUNTER13) +DECLARE_CSR(hpmcounter14, CSR_HPMCOUNTER14) +DECLARE_CSR(hpmcounter15, CSR_HPMCOUNTER15) +DECLARE_CSR(hpmcounter16, CSR_HPMCOUNTER16) +DECLARE_CSR(hpmcounter17, CSR_HPMCOUNTER17) +DECLARE_CSR(hpmcounter18, CSR_HPMCOUNTER18) +DECLARE_CSR(hpmcounter19, CSR_HPMCOUNTER19) +DECLARE_CSR(hpmcounter20, CSR_HPMCOUNTER20) +DECLARE_CSR(hpmcounter21, CSR_HPMCOUNTER21) +DECLARE_CSR(hpmcounter22, CSR_HPMCOUNTER22) +DECLARE_CSR(hpmcounter23, CSR_HPMCOUNTER23) +DECLARE_CSR(hpmcounter24, CSR_HPMCOUNTER24) +DECLARE_CSR(hpmcounter25, CSR_HPMCOUNTER25) +DECLARE_CSR(hpmcounter26, CSR_HPMCOUNTER26) +DECLARE_CSR(hpmcounter27, CSR_HPMCOUNTER27) +DECLARE_CSR(hpmcounter28, CSR_HPMCOUNTER28) +DECLARE_CSR(hpmcounter29, CSR_HPMCOUNTER29) +DECLARE_CSR(hpmcounter30, CSR_HPMCOUNTER30) +DECLARE_CSR(hpmcounter31, CSR_HPMCOUNTER31) +DECLARE_CSR(sstatus, CSR_SSTATUS) +DECLARE_CSR(sie, CSR_SIE) +DECLARE_CSR(stvec, CSR_STVEC) +DECLARE_CSR(sscratch, CSR_SSCRATCH) +DECLARE_CSR(sepc, CSR_SEPC) +DECLARE_CSR(scause, CSR_SCAUSE) +DECLARE_CSR(sbadaddr, CSR_SBADADDR) +DECLARE_CSR(sip, CSR_SIP) +DECLARE_CSR(sptbr, CSR_SPTBR) +DECLARE_CSR(mstatus, CSR_MSTATUS) +DECLARE_CSR(misa, CSR_MISA) +DECLARE_CSR(medeleg, CSR_MEDELEG) +DECLARE_CSR(mideleg, CSR_MIDELEG) +DECLARE_CSR(mie, CSR_MIE) +DECLARE_CSR(mtvec, CSR_MTVEC) +DECLARE_CSR(mscratch, CSR_MSCRATCH) +DECLARE_CSR(mepc, CSR_MEPC) +DECLARE_CSR(mcause, CSR_MCAUSE) +DECLARE_CSR(mbadaddr, CSR_MBADADDR) +DECLARE_CSR(mip, CSR_MIP) +DECLARE_CSR(tselect, CSR_TSELECT) +DECLARE_CSR(tdata1, CSR_TDATA1) +DECLARE_CSR(tdata2, CSR_TDATA2) +DECLARE_CSR(tdata3, CSR_TDATA3) +DECLARE_CSR(dcsr, CSR_DCSR) +DECLARE_CSR(dpc, CSR_DPC) +DECLARE_CSR(dscratch, CSR_DSCRATCH) +DECLARE_CSR(mcycle, CSR_MCYCLE) +DECLARE_CSR(minstret, CSR_MINSTRET) +DECLARE_CSR(mhpmcounter3, CSR_MHPMCOUNTER3) +DECLARE_CSR(mhpmcounter4, CSR_MHPMCOUNTER4) +DECLARE_CSR(mhpmcounter5, CSR_MHPMCOUNTER5) +DECLARE_CSR(mhpmcounter6, CSR_MHPMCOUNTER6) +DECLARE_CSR(mhpmcounter7, CSR_MHPMCOUNTER7) +DECLARE_CSR(mhpmcounter8, CSR_MHPMCOUNTER8) +DECLARE_CSR(mhpmcounter9, CSR_MHPMCOUNTER9) +DECLARE_CSR(mhpmcounter10, CSR_MHPMCOUNTER10) +DECLARE_CSR(mhpmcounter11, CSR_MHPMCOUNTER11) +DECLARE_CSR(mhpmcounter12, CSR_MHPMCOUNTER12) +DECLARE_CSR(mhpmcounter13, CSR_MHPMCOUNTER13) +DECLARE_CSR(mhpmcounter14, CSR_MHPMCOUNTER14) +DECLARE_CSR(mhpmcounter15, CSR_MHPMCOUNTER15) +DECLARE_CSR(mhpmcounter16, CSR_MHPMCOUNTER16) +DECLARE_CSR(mhpmcounter17, CSR_MHPMCOUNTER17) +DECLARE_CSR(mhpmcounter18, CSR_MHPMCOUNTER18) +DECLARE_CSR(mhpmcounter19, CSR_MHPMCOUNTER19) +DECLARE_CSR(mhpmcounter20, CSR_MHPMCOUNTER20) +DECLARE_CSR(mhpmcounter21, CSR_MHPMCOUNTER21) +DECLARE_CSR(mhpmcounter22, CSR_MHPMCOUNTER22) +DECLARE_CSR(mhpmcounter23, CSR_MHPMCOUNTER23) +DECLARE_CSR(mhpmcounter24, CSR_MHPMCOUNTER24) +DECLARE_CSR(mhpmcounter25, CSR_MHPMCOUNTER25) +DECLARE_CSR(mhpmcounter26, CSR_MHPMCOUNTER26) +DECLARE_CSR(mhpmcounter27, CSR_MHPMCOUNTER27) +DECLARE_CSR(mhpmcounter28, CSR_MHPMCOUNTER28) +DECLARE_CSR(mhpmcounter29, CSR_MHPMCOUNTER29) +DECLARE_CSR(mhpmcounter30, CSR_MHPMCOUNTER30) +DECLARE_CSR(mhpmcounter31, CSR_MHPMCOUNTER31) +DECLARE_CSR(mucounteren, CSR_MUCOUNTEREN) +DECLARE_CSR(mscounteren, CSR_MSCOUNTEREN) +DECLARE_CSR(mhpmevent3, CSR_MHPMEVENT3) +DECLARE_CSR(mhpmevent4, CSR_MHPMEVENT4) +DECLARE_CSR(mhpmevent5, CSR_MHPMEVENT5) +DECLARE_CSR(mhpmevent6, CSR_MHPMEVENT6) +DECLARE_CSR(mhpmevent7, CSR_MHPMEVENT7) +DECLARE_CSR(mhpmevent8, CSR_MHPMEVENT8) +DECLARE_CSR(mhpmevent9, CSR_MHPMEVENT9) +DECLARE_CSR(mhpmevent10, CSR_MHPMEVENT10) +DECLARE_CSR(mhpmevent11, CSR_MHPMEVENT11) +DECLARE_CSR(mhpmevent12, CSR_MHPMEVENT12) +DECLARE_CSR(mhpmevent13, CSR_MHPMEVENT13) +DECLARE_CSR(mhpmevent14, CSR_MHPMEVENT14) +DECLARE_CSR(mhpmevent15, CSR_MHPMEVENT15) +DECLARE_CSR(mhpmevent16, CSR_MHPMEVENT16) +DECLARE_CSR(mhpmevent17, CSR_MHPMEVENT17) +DECLARE_CSR(mhpmevent18, CSR_MHPMEVENT18) +DECLARE_CSR(mhpmevent19, CSR_MHPMEVENT19) +DECLARE_CSR(mhpmevent20, CSR_MHPMEVENT20) +DECLARE_CSR(mhpmevent21, CSR_MHPMEVENT21) +DECLARE_CSR(mhpmevent22, CSR_MHPMEVENT22) +DECLARE_CSR(mhpmevent23, CSR_MHPMEVENT23) +DECLARE_CSR(mhpmevent24, CSR_MHPMEVENT24) +DECLARE_CSR(mhpmevent25, CSR_MHPMEVENT25) +DECLARE_CSR(mhpmevent26, CSR_MHPMEVENT26) +DECLARE_CSR(mhpmevent27, CSR_MHPMEVENT27) +DECLARE_CSR(mhpmevent28, CSR_MHPMEVENT28) +DECLARE_CSR(mhpmevent29, CSR_MHPMEVENT29) +DECLARE_CSR(mhpmevent30, CSR_MHPMEVENT30) +DECLARE_CSR(mhpmevent31, CSR_MHPMEVENT31) +DECLARE_CSR(mvendorid, CSR_MVENDORID) +DECLARE_CSR(marchid, CSR_MARCHID) +DECLARE_CSR(mimpid, CSR_MIMPID) +DECLARE_CSR(mhartid, CSR_MHARTID) +DECLARE_CSR(cycleh, CSR_CYCLEH) +DECLARE_CSR(timeh, CSR_TIMEH) +DECLARE_CSR(instreth, CSR_INSTRETH) +DECLARE_CSR(hpmcounter3h, CSR_HPMCOUNTER3H) +DECLARE_CSR(hpmcounter4h, CSR_HPMCOUNTER4H) +DECLARE_CSR(hpmcounter5h, CSR_HPMCOUNTER5H) +DECLARE_CSR(hpmcounter6h, CSR_HPMCOUNTER6H) +DECLARE_CSR(hpmcounter7h, CSR_HPMCOUNTER7H) +DECLARE_CSR(hpmcounter8h, CSR_HPMCOUNTER8H) +DECLARE_CSR(hpmcounter9h, CSR_HPMCOUNTER9H) +DECLARE_CSR(hpmcounter10h, CSR_HPMCOUNTER10H) +DECLARE_CSR(hpmcounter11h, CSR_HPMCOUNTER11H) +DECLARE_CSR(hpmcounter12h, CSR_HPMCOUNTER12H) +DECLARE_CSR(hpmcounter13h, CSR_HPMCOUNTER13H) +DECLARE_CSR(hpmcounter14h, CSR_HPMCOUNTER14H) +DECLARE_CSR(hpmcounter15h, CSR_HPMCOUNTER15H) +DECLARE_CSR(hpmcounter16h, CSR_HPMCOUNTER16H) +DECLARE_CSR(hpmcounter17h, CSR_HPMCOUNTER17H) +DECLARE_CSR(hpmcounter18h, CSR_HPMCOUNTER18H) +DECLARE_CSR(hpmcounter19h, CSR_HPMCOUNTER19H) +DECLARE_CSR(hpmcounter20h, CSR_HPMCOUNTER20H) +DECLARE_CSR(hpmcounter21h, CSR_HPMCOUNTER21H) +DECLARE_CSR(hpmcounter22h, CSR_HPMCOUNTER22H) +DECLARE_CSR(hpmcounter23h, CSR_HPMCOUNTER23H) +DECLARE_CSR(hpmcounter24h, CSR_HPMCOUNTER24H) +DECLARE_CSR(hpmcounter25h, CSR_HPMCOUNTER25H) +DECLARE_CSR(hpmcounter26h, CSR_HPMCOUNTER26H) +DECLARE_CSR(hpmcounter27h, CSR_HPMCOUNTER27H) +DECLARE_CSR(hpmcounter28h, CSR_HPMCOUNTER28H) +DECLARE_CSR(hpmcounter29h, CSR_HPMCOUNTER29H) +DECLARE_CSR(hpmcounter30h, CSR_HPMCOUNTER30H) +DECLARE_CSR(hpmcounter31h, CSR_HPMCOUNTER31H) +DECLARE_CSR(mcycleh, CSR_MCYCLEH) +DECLARE_CSR(minstreth, CSR_MINSTRETH) +DECLARE_CSR(mhpmcounter3h, CSR_MHPMCOUNTER3H) +DECLARE_CSR(mhpmcounter4h, CSR_MHPMCOUNTER4H) +DECLARE_CSR(mhpmcounter5h, CSR_MHPMCOUNTER5H) +DECLARE_CSR(mhpmcounter6h, CSR_MHPMCOUNTER6H) +DECLARE_CSR(mhpmcounter7h, CSR_MHPMCOUNTER7H) +DECLARE_CSR(mhpmcounter8h, CSR_MHPMCOUNTER8H) +DECLARE_CSR(mhpmcounter9h, CSR_MHPMCOUNTER9H) +DECLARE_CSR(mhpmcounter10h, CSR_MHPMCOUNTER10H) +DECLARE_CSR(mhpmcounter11h, CSR_MHPMCOUNTER11H) +DECLARE_CSR(mhpmcounter12h, CSR_MHPMCOUNTER12H) +DECLARE_CSR(mhpmcounter13h, CSR_MHPMCOUNTER13H) +DECLARE_CSR(mhpmcounter14h, CSR_MHPMCOUNTER14H) +DECLARE_CSR(mhpmcounter15h, CSR_MHPMCOUNTER15H) +DECLARE_CSR(mhpmcounter16h, CSR_MHPMCOUNTER16H) +DECLARE_CSR(mhpmcounter17h, CSR_MHPMCOUNTER17H) +DECLARE_CSR(mhpmcounter18h, CSR_MHPMCOUNTER18H) +DECLARE_CSR(mhpmcounter19h, CSR_MHPMCOUNTER19H) +DECLARE_CSR(mhpmcounter20h, CSR_MHPMCOUNTER20H) +DECLARE_CSR(mhpmcounter21h, CSR_MHPMCOUNTER21H) +DECLARE_CSR(mhpmcounter22h, CSR_MHPMCOUNTER22H) +DECLARE_CSR(mhpmcounter23h, CSR_MHPMCOUNTER23H) +DECLARE_CSR(mhpmcounter24h, CSR_MHPMCOUNTER24H) +DECLARE_CSR(mhpmcounter25h, CSR_MHPMCOUNTER25H) +DECLARE_CSR(mhpmcounter26h, CSR_MHPMCOUNTER26H) +DECLARE_CSR(mhpmcounter27h, CSR_MHPMCOUNTER27H) +DECLARE_CSR(mhpmcounter28h, CSR_MHPMCOUNTER28H) +DECLARE_CSR(mhpmcounter29h, CSR_MHPMCOUNTER29H) +DECLARE_CSR(mhpmcounter30h, CSR_MHPMCOUNTER30H) +DECLARE_CSR(mhpmcounter31h, CSR_MHPMCOUNTER31H) +#endif +#if defined(DECLARE_CAUSE) +DECLARE_CAUSE("misaligned fetch", CAUSE_MISALIGNED_FETCH) +DECLARE_CAUSE("fault fetch", CAUSE_FAULT_FETCH) +DECLARE_CAUSE("illegal instruction", CAUSE_ILLEGAL_INSTRUCTION) +DECLARE_CAUSE("breakpoint", CAUSE_BREAKPOINT) +DECLARE_CAUSE("misaligned load", CAUSE_MISALIGNED_LOAD) +DECLARE_CAUSE("fault load", CAUSE_FAULT_LOAD) +DECLARE_CAUSE("misaligned store", CAUSE_MISALIGNED_STORE) +DECLARE_CAUSE("fault store", CAUSE_FAULT_STORE) +DECLARE_CAUSE("user_ecall", CAUSE_USER_ECALL) +DECLARE_CAUSE("supervisor_ecall", CAUSE_SUPERVISOR_ECALL) +DECLARE_CAUSE("hypervisor_ecall", CAUSE_HYPERVISOR_ECALL) +DECLARE_CAUSE("machine_ecall", CAUSE_MACHINE_ECALL) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _BSP_ENV_ENCODING_H */ + diff --git a/lib/bsp/include/interrupt.h b/lib/bsp/include/interrupt.h new file mode 100644 index 0000000..160690e --- /dev/null +++ b/lib/bsp/include/interrupt.h @@ -0,0 +1,47 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _BSP_INTERRUPT_H +#define _BSP_INTERRUPT_H + +#ifdef __cplusplus +extern "C" { +#endif +/* clang-format off */ +/* Machine interrupt mask for 64 bit system, 0x8000 0000 0000 0000 */ +#define CAUSE_MACHINE_IRQ_MASK (0x1ULL << 63) + +/* Machine interrupt reason mask for 64 bit system, 0x7FFF FFFF FFFF FFFF */ +#define CAUSE_MACHINE_IRQ_REASON_MASK (CAUSE_MACHINE_IRQ_MASK - 1) + +/* Hypervisor interrupt mask for 64 bit system, 0x8000 0000 0000 0000 */ +#define CAUSE_HYPERVISOR_IRQ_MASK (0x1ULL << 63) + +/* Hypervisor interrupt reason mask for 64 bit system, 0x7FFF FFFF FFFF FFFF */ +#define CAUSE_HYPERVISOR_IRQ_REASON_MASK (CAUSE_HYPERVISOR_IRQ_MASK - 1) + +/* Supervisor interrupt mask for 64 bit system, 0x8000 0000 0000 0000 */ +#define CAUSE_SUPERVISOR_IRQ_MASK (0x1ULL << 63) + +/* Supervisor interrupt reason mask for 64 bit system, 0x7FFF FFFF FFFF FFFF */ +#define CAUSE_SUPERVISOR_IRQ_REASON_MASK (CAUSE_SUPERVISOR_IRQ_MASK - 1) +/* clang-format on */ + +#ifdef __cplusplus +} +#endif + +#endif /* _BSP_INTERRUPT_H */ + diff --git a/lib/bsp/include/platform.h b/lib/bsp/include/platform.h new file mode 100644 index 0000000..6ce0355 --- /dev/null +++ b/lib/bsp/include/platform.h @@ -0,0 +1,99 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _BSP_PLATFORM_H +#define _BSP_PLATFORM_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* clang-format off */ +/* Register base address */ + +/* Under Coreplex */ +#define CLINT_BASE_ADDR (0x02000000U) +#define PLIC_BASE_ADDR (0x0C000000U) + +/* Under TileLink */ +#define UARTHS_BASE_ADDR (0x38000000U) +#define GPIOHS_BASE_ADDR (0x38001000U) + +/* Under AXI 64 bit */ +#define RAM_BASE_ADDR (0x80000000U) +#define RAM_SIZE (6 * 1024 * 1024U) + +#define IO_BASE_ADDR (0x40000000U) +#define IO_SIZE (6 * 1024 * 1024U) + +#define AI_RAM_BASE_ADDR (0x80600000U) +#define AI_RAM_SIZE (2 * 1024 * 1024U) + +#define AI_IO_BASE_ADDR (0x40600000U) +#define AI_IO_SIZE (2 * 1024 * 1024U) + +#define AI_BASE_ADDR (0x40800000U) +#define AI_SIZE (12 * 1024 * 1024U) + +#define FFT_BASE_ADDR (0x42000000U) +#define FFT_SIZE (4 * 1024 * 1024U) + +#define ROM_BASE_ADDR (0x88000000U) +#define ROM_SIZE (128 * 1024U) + +/* Under AHB 32 bit */ +#define DMAC_BASE_ADDR (0x50000000U) + +/* Under APB1 32 bit */ +#define GPIO_BASE_ADDR (0x50200000U) +#define UART1_BASE_ADDR (0x50210000U) +#define UART2_BASE_ADDR (0x50220000U) +#define UART3_BASE_ADDR (0x50230000U) +#define SPI_SLAVE_BASE_ADDR (0x50240000U) +#define I2S0_BASE_ADDR (0x50250000U) +#define I2S1_BASE_ADDR (0x50260000U) +#define I2S2_BASE_ADDR (0x50270000U) +#define I2C0_BASE_ADDR (0x50280000U) +#define I2C1_BASE_ADDR (0x50290000U) +#define I2C2_BASE_ADDR (0x502A0000U) +#define FPIOA_BASE_ADDR (0x502B0000U) +#define SHA256_BASE_ADDR (0x502C0000U) +#define TIMER0_BASE_ADDR (0x502D0000U) +#define TIMER1_BASE_ADDR (0x502E0000U) +#define TIMER2_BASE_ADDR (0x502F0000U) + +/* Under APB2 32 bit */ +#define WDT0_BASE_ADDR (0x50400000U) +#define WDT1_BASE_ADDR (0x50410000U) +#define OTP_BASE_ADDR (0x50420000U) +#define DVP_BASE_ADDR (0x50430000U) +#define SYSCTL_BASE_ADDR (0x50440000U) +#define AES_BASE_ADDR (0x50450000U) +#define RTC_BASE_ADDR (0x50460000U) + + +/* Under APB3 32 bit */ +#define SPI0_BASE_ADDR (0x52000000U) +#define SPI1_BASE_ADDR (0x53000000U) +#define SPI3_BASE_ADDR (0x54000000U) + +/* clang-format on */ + +#ifdef __cplusplus +} +#endif + +#endif /* _BSP_PLATFORM_H */ + diff --git a/lib/bsp/include/printf.h b/lib/bsp/include/printf.h new file mode 100644 index 0000000..fa19cd4 --- /dev/null +++ b/lib/bsp/include/printf.h @@ -0,0 +1,209 @@ +/** + * File: printf.h + * + * Copyright (c) 2004,2012 Kustaa Nyholm / SpareTimeLabs + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Kustaa Nyholm or SpareTimeLabs 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 COPYRIGHT HOLDER 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. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * This library is really just two files: 'tinyprintf.h' and 'tinyprintf.c'. + * + * They provide a simple and small (+400 loc) printf functionality to be used + * in embedded systems. + * + * I've found them so useful in debugging that I do not bother with a debugger + * at all. + * + * They are distributed in source form, so to use them, just compile them into + * your project. + * + * Two printf variants are provided: printf and the 'sprintf' family of + * functions ('snprintf', 'sprintf', 'vsnprintf', 'vsprintf'). + * + * The formats supported by this implementation are: 'c' 'd' 'i' 'o' 'p' 'u' + * 's' 'x' 'X'. + * + * Zero padding, field width, and precision are also supported. + * + * If the library is compiled with 'PRINTF_SUPPORT_LONG' defined, then the + * long specifier is also supported. Note that this will pull in some long + * math routines (pun intended!) and thus make your executable noticeably + * longer. Likewise with 'PRINTF_LONG_LONG_SUPPORT' for the long long + * specifier, and with 'PRINTF_SIZE_T_SUPPORT' for the size_t specifier. + * + * The memory footprint of course depends on the target CPU, compiler and + * compiler options, but a rough guesstimate (based on a H8S target) is about + * 1.4 kB for code and some twenty 'int's and 'char's, say 60 bytes of stack + * space. Not too bad. Your mileage may vary. By hacking the source code you + * can get rid of some hundred bytes, I'm sure, but personally I feel the + * balance of functionality and flexibility versus code size is close to + * optimal for many embedded systems. + * + * To use the printf, you need to supply your own character output function, + * something like : + * + * void putc ( void* p, char c) { while (!SERIAL_PORT_EMPTY) ; + * SERIAL_PORT_TX_REGISTER = c; } + * + * Before you can call printf, you need to initialize it to use your character + * output function with something like: + * + * init_printf(NULL,putc); + * + * Notice the 'NULL' in 'init_printf' and the parameter 'void* p' in 'putc', + * the NULL (or any pointer) you pass into the 'init_printf' will eventually + * be passed to your 'putc' routine. This allows you to pass some storage + * space (or anything really) to the character output function, if necessary. + * This is not often needed but it was implemented like that because it made + * implementing the sprintf function so neat (look at the source code). + * + * The code is re-entrant, except for the 'init_printf' function, so it is + * safe to call it from interrupts too, although this may result in mixed + * output. If you rely on re-entrancy, take care that your 'putc' function is + * re-entrant! + * + * The printf and sprintf functions are actually macros that translate to + * 'tfp_printf' and 'tfp_sprintf' when 'TINYPRINTF_OVERRIDE_LIBC' is set + * (default). Setting it to 0 makes it possible to use them along with + * 'stdio.h' printf's in a single source file. When 'TINYPRINTF_OVERRIDE_LIBC' + * is set, please note that printf/sprintf are not function-like macros, so if + * you have variables or struct members with these names, things will explode + * in your face. Without variadic macros this is the best we can do to wrap + * these function. If it is a problem, just give up the macros and use the + * functions directly, or rename them. + * + * It is also possible to avoid defining tfp_printf and/or tfp_sprintf by + * clearing 'TINYPRINTF_DEFINE_TFP_PRINTF' and/or + * 'TINYPRINTF_DEFINE_TFP_SPRINTF' to 0. This allows for example to export + * only tfp_format, which is at the core of all the other functions. + * + * For further details see source code. + * + * regs Kusti, 23.10.2004 + */ + +#ifndef _BSP_PRINTF_H +#define _BSP_PRINTF_H + +#include +#include + +/* Global configuration */ + +/* Set this to 0 if you do not want to provide tfp_printf */ +#ifndef TINYPRINTF_DEFINE_TFP_PRINTF +#define TINYPRINTF_DEFINE_TFP_PRINTF 1 +#endif + +/** + * Set this to 0 if you do not want to provide + * tfp_sprintf/snprintf/vsprintf/vsnprintf + */ +#ifndef TINYPRINTF_DEFINE_TFP_SPRINTF +#define TINYPRINTF_DEFINE_TFP_SPRINTF 1 +#endif + +/** + * Set this to 0 if you do not want tfp_printf and + * tfp_{vsn,sn,vs,s}printf to be also available as + * printf/{vsn,sn,vs,s}printf + */ +#ifndef TINYPRINTF_OVERRIDE_LIBC +#define TINYPRINTF_OVERRIDE_LIBC 0 +#endif + +/* Optional external types dependencies */ + +/* Declarations */ + +#if defined(__GNUC__) +#define _TFP_SPECIFY_PRINTF_FMT(fmt_idx, arg1_idx) \ + __attribute__((format(printf, fmt_idx, arg1_idx))) +#else +#define _TFP_SPECIFY_PRINTF_FMT(fmt_idx, arg1_idx) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*putcf)(void*, char); + +/** + * 'tfp_format' really is the central function for all tinyprintf. For + * each output character after formatting, the 'putf' callback is + * called with 2 args: + * - an arbitrary void* 'putp' param defined by the user and + * passed unmodified from 'tfp_format', + * - the character. + * The 'tfp_printf' and 'tfp_sprintf' functions simply define their own + * callback and pass to it the right 'putp' it is expecting. + */ +void tfp_format(void *putp, putcf putf, const char *fmt, va_list va); + +#if TINYPRINTF_DEFINE_TFP_SPRINTF +int tfp_vsnprintf(char *str, size_t size, const char *fmt, va_list ap); +int tfp_snprintf(char *str, size_t size, const char *fmt, ...) + _TFP_SPECIFY_PRINTF_FMT(3, 4); +int tfp_vsprintf(char *str, const char *fmt, va_list ap); +int tfp_sprintf(char *str, const char *fmt, ...) _TFP_SPECIFY_PRINTF_FMT(2, 3); +#if TINYPRINTF_OVERRIDE_LIBC +#define vsnprintf tfp_vsnprintf +#define snprintf tfp_snprintf +#define vsprintf tfp_vsprintf +#define sprintf tfp_sprintf +#endif +#endif + +#if TINYPRINTF_DEFINE_TFP_PRINTF +void init_printf(void *putp, putcf putf); +void tfp_printf(char *fmt, ...) _TFP_SPECIFY_PRINTF_FMT(1, 2); +#if TINYPRINTF_OVERRIDE_LIBC +#define printf tfp_printf + +#ifdef __cplusplus +#include +namespace std +{ + template + auto tfp_printf(Args&&... args) -> decltype(::tfp_printf(std::forward(args)...)) + { + return ::tfp_printf(std::forward(args)...); + } +} +#endif +#endif +#endif + +int printk(const char *format, ...) _TFP_SPECIFY_PRINTF_FMT(1, 2); + +#ifdef __cplusplus +} +#endif + +#endif /* _BSP_PRINTF_H */ + diff --git a/lib/bsp/include/sleep.h b/lib/bsp/include/sleep.h new file mode 100644 index 0000000..f80cc92 --- /dev/null +++ b/lib/bsp/include/sleep.h @@ -0,0 +1,36 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _BSP_SLEEP_H +#define _BSP_SLEEP_H + +#include "env/encoding.h" +#include "clint.h" +#include "syscalls.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int usleep(uint64_t usec); +int msleep(uint64_t msec); +unsigned int sleep(unsigned int seconds); + +#ifdef __cplusplus +} +#endif + +#endif /* _BSP_SLEEP_H */ + diff --git a/lib/bsp/include/syscalls.h b/lib/bsp/include/syscalls.h new file mode 100644 index 0000000..12713c3 --- /dev/null +++ b/lib/bsp/include/syscalls.h @@ -0,0 +1,46 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _BSP_SYSCALLS_H +#define _BSP_SYSCALLS_H + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void __attribute__((noreturn)) sys_exit(int code); + +void setStats(int enable); + +#undef putchar +int putchar(int ch); +void printstr(const char *s); + +void printhex(uint64_t x); + +size_t get_free_heap_size(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _BSP_SYSCALLS_H */ + diff --git a/lib/bsp/include/util.h b/lib/bsp/include/util.h new file mode 100644 index 0000000..db71a78 --- /dev/null +++ b/lib/bsp/include/util.h @@ -0,0 +1,198 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _BSP_UTIL_H +#define _BSP_UTIL_H + + +#include +#if defined(__riscv) +#include "env/encoding.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +/** + * -------------------------------------------------------------------------- + * Macros + + * Set HOST_DEBUG to 1 if you are going to compile this for a host + * machine (ie Athena/Linux) for debug purposes and set HOST_DEBUG + * to 0 if you are compiling with the smips-gcc toolchain. + */ + +#ifndef HOST_DEBUG +#define HOST_DEBUG 0 +#endif + +/** + * Set PREALLOCATE to 1 if you want to preallocate the benchmark + * function before starting stats. If you have instruction/data + * caches and you don't want to count the overhead of misses, then + * you will need to use preallocation. +*/ + +#ifndef PREALLOCATE +#define PREALLOCATE 0 +#endif + + +#define static_assert(cond) \ + { \ + switch (0) \ + { \ + case 0: \ + case !!(long)(cond):; \ + } \ + } + +#define stringify_1(s) #s +#define stringify(s) stringify_1(s) +#define stats(code, iter) \ + do \ + { \ + unsigned long _c = -read_csr(mcycle), _i = -read_csr(minstret); \ + code; \ + _c += read_csr(mcycle), _i += read_csr(minstret); \ + if (cid == 0) \ + printf("\n%s: %ld cycles, %ld.%ld cycles/iter, %ld.%ld CPI\n", \ + stringify(code), _c, _c / iter, 10 * _c / iter % 10, _c / _i, 10 * _c / _i % 10); \ + } while (0) + + +/** + * Set SET_STATS to 1 if you want to carve out the piece that actually + * does the computation. + */ + +#if HOST_DEBUG +#include +static void setStats(int enable) {} +#else +extern void setStats(int enable); +#endif + + +static void printArray(const char name[], int n, const int arr[]) +{ +#if HOST_DEBUG + int i; + + printf(" %10s :", name); + for (i = 0; i < n; i++) + printf(" %3d ", arr[i]); + printf("\n"); +#endif +} + +static void printDoubleArray(const char name[], int n, const double arr[]) +{ +#if HOST_DEBUG + int i; + + printf(" %10s :", name); + for (i = 0; i < n; i++) + printf(" %g ", arr[i]); + printf("\n"); +#endif +} + +static int verify(int n, const volatile int *test, const int *verify) +{ + int i; + /* Unrolled for faster verification */ + for (i = 0; i < n / 2 * 2; i += 2) + { + int t0 = test[i], t1 = test[i + 1]; + int v0 = verify[i], v1 = verify[i + 1]; + + if (t0 != v0) + return i + 1; + if (t1 != v1) + return i + 2; + } + if (n % 2 != 0 && test[n - 1] != verify[n - 1]) + return n; + return 0; +} + +static int verifyDouble(int n, const volatile double *test, const double *verify) +{ + int i; + /* Unrolled for faster verification */ + for (i = 0; i < n / 2 * 2; i += 2) + { + double t0 = test[i], t1 = test[i + 1]; + double v0 = verify[i], v1 = verify[i + 1]; + int eq1 = t0 == v0, eq2 = t1 == v1; + + if (!(eq1 & eq2)) + return i + 1 + eq1; + } + if (n % 2 != 0 && test[n - 1] != verify[n - 1]) + return n; + return 0; +} + +static void __attribute__((noinline)) barrier(int ncores) +{ + static volatile int sense = 0; + static volatile int count = 0; + + static __thread int threadsense; + + __sync_synchronize(); + + threadsense = !threadsense; + if (__sync_fetch_and_add(&count, 1) == ncores - 1) + { + count = 0; + sense = threadsense; + } + else + { + while (sense != threadsense) + ; + } + + __sync_synchronize(); +} + +static uint64_t lfsr(uint64_t x) +{ + uint64_t bit = (x ^ (x >> 1)) & 1; + + return (x >> 1) | (bit << 62); +} + + +#if defined(__GNUC__) +#pragma GCC diagnostic warning "-Wunused-parameter" +#pragma GCC diagnostic warning "-Wunused-function" +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _BSP_UTIL_H */ + diff --git a/lib/bsp/interrupt.c b/lib/bsp/interrupt.c new file mode 100644 index 0000000..802a6e5 --- /dev/null +++ b/lib/bsp/interrupt.c @@ -0,0 +1,66 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Enable kernel-mode log API */ + +#include +#include +#include "interrupt.h" +#include "dump.h" +#include "syscalls.h" +#include "syslog.h" + +uintptr_t __attribute__((weak)) +handle_irq_dummy(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]) +{ + dump_core("unhandled interrupt", cause, epc, regs, fregs); + sys_exit(1337); + return epc; +} + +uintptr_t __attribute__((weak, alias("handle_irq_dummy"))) +handle_irq_m_soft(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]); + +uintptr_t __attribute__((weak, alias("handle_irq_dummy"))) +handle_irq_m_timer(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]); + +uintptr_t __attribute__((weak, alias("handle_irq_dummy"))) +handle_irq_m_ext(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]); + +uintptr_t __attribute__((weak)) +handle_irq(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]) +{ +#if defined(__GNUC__) +#pragma GCC diagnostic ignored "-Woverride-init" +#endif + /* clang-format off */ + static uintptr_t (* const irq_table[])( + uintptr_t cause, + uintptr_t epc, + uintptr_t regs[32], + uintptr_t fregs[32]) = + { + [0 ... 14] = handle_irq_dummy, + [IRQ_M_SOFT] = handle_irq_m_soft, + [IRQ_M_TIMER] = handle_irq_m_timer, + [IRQ_M_EXT] = handle_irq_m_ext, + }; + /* clang-format on */ +#if defined(__GNUC__) +#pragma GCC diagnostic warning "-Woverride-init" +#endif + return irq_table[cause & CAUSE_MACHINE_IRQ_REASON_MASK](cause, epc, regs, fregs); +} + diff --git a/lib/bsp/printf.c b/lib/bsp/printf.c new file mode 100644 index 0000000..4239249 --- /dev/null +++ b/lib/bsp/printf.c @@ -0,0 +1,668 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * File: printf.c + * + * Copyright (c) 2004,2012 Kustaa Nyholm / SpareTimeLabs + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Kustaa Nyholm or SpareTimeLabs 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 COPYRIGHT HOLDER BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include "printf.h" +#include "atomic.h" +#include "uarths.h" + + +/** + * Configuration + */ + +/* Enable long int support */ +#define PRINTF_LONG_SUPPORT + +/* Enable long long int support (implies long int support) */ +#define PRINTF_LONG_LONG_SUPPORT + +/* Enable %z (size_t) support */ +#define PRINTF_SIZE_T_SUPPORT + +/** + * Configuration adjustments + */ +#if defined(PRINTF_LONG_LONG_SUPPORT) +#define PRINTF_LONG_SUPPORT +#endif + +/* __SIZEOF___ defined at least by gcc */ +#if defined(__SIZEOF_POINTER__) +#define SIZEOF_POINTER __SIZEOF_POINTER__ +#endif +#if defined(__SIZEOF_LONG_LONG__) +#define SIZEOF_LONG_LONG __SIZEOF_LONG_LONG__ +#endif +#if defined(__SIZEOF_LONG__) +#define SIZEOF_LONG __SIZEOF_LONG__ +#endif +#if defined(__SIZEOF_INT__) +#define SIZEOF_INT __SIZEOF_INT__ +#endif + +#if defined(__GNUC__) +#define _TFP_GCC_NO_INLINE_ __attribute__((noinline)) +#else +#define _TFP_GCC_NO_INLINE_ +#endif + + +#if defined(PRINTF_LONG_SUPPORT) +#define BF_MAX 20 /* long = 64b on some architectures */ +#else +#define BF_MAX 10 /* int = 32b on some architectures */ +#endif + + +#define IS_DIGIT(x) ((x) >= '0' && (x) <= '9') + +/* Clear unused warnings for actually unused variables */ +#define UNUSED(x) (void)(x) + + + +/** + * Implementation + */ +struct param +{ + char lz : 1; /* Leading zeros */ + char alt : 1; /* alternate form */ + char uc : 1; /* Upper case (for base16 only) */ + char align_left : 1; /* 0 == align right (default), 1 == align left */ + int width; /* field width */ + int prec; /* precision */ + char sign; /* The sign to display (if any) */ + unsigned int base; /* number base (e.g.: 8, 10, 16) */ + char *bf; /* Buffer to output */ + size_t bf_len; /* Buffer length */ +}; + +static hartlock_t lock = HARTLOCK_INIT; + + + +#if defined(PRINTF_LONG_LONG_SUPPORT) +static void _TFP_GCC_NO_INLINE_ ulli2a(unsigned long long int num, struct param *p) +{ + unsigned long long int d = 1; + char *bf = p->bf; + if ((p->prec == 0) && (num == 0)) + return; + while (num / d >= p->base) + { + d *= p->base; + } + while (d != 0) + { + int dgt = num / d; + num %= d; + d /= p->base; + *bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10); + } + p->bf_len = bf - p->bf; +} + +static void lli2a(long long int num, struct param *p) +{ + if (num < 0) + { + num = -num; + p->sign = '-'; + } + ulli2a(num, p); +} +#endif + +#if defined(PRINTF_LONG_SUPPORT) +static void uli2a(unsigned long int num, struct param *p) +{ + unsigned long int d = 1; + char *bf = p->bf; + if ((p->prec == 0) && (num == 0)) + return; + while (num / d >= p->base) + { + d *= p->base; + } + while (d != 0) + { + int dgt = num / d; + num %= d; + d /= p->base; + *bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10); + } + p->bf_len = bf - p->bf; +} + +static void li2a(long num, struct param *p) +{ + if (num < 0) + { + num = -num; + p->sign = '-'; + } + uli2a(num, p); +} +#endif + +static void ui2a(unsigned int num, struct param *p) +{ + unsigned int d = 1; + char *bf = p->bf; + if ((p->prec == 0) && (num == 0)) + return; + while (num / d >= p->base) + { + d *= p->base; + } + while (d != 0) + { + int dgt = num / d; + num %= d; + d /= p->base; + *bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10); + } + p->bf_len = bf - p->bf; +} + +static void i2a(int num, struct param *p) +{ + if (num < 0) + { + num = -num; + p->sign = '-'; + } + ui2a(num, p); +} + +static int a2d(char ch) +{ + if (IS_DIGIT(ch)) + return ch - '0'; + else if (ch >= 'a' && ch <= 'f') + return ch - 'a' + 10; + else if (ch >= 'A' && ch <= 'F') + return ch - 'A' + 10; + else + return -1; +} + +static char a2u(char ch, const char **src, int base, unsigned int *nump) +{ + const char *p = *src; + unsigned int num = 0; + int digit; + while ((digit = a2d(ch)) >= 0) + { + if (digit > base) + break; + num = num * base + digit; + ch = *p++; + } + *src = p; + *nump = num; + return ch; +} + +static void putchw(void *putp, putcf putf, struct param *p) +{ + char ch; + int width = p->width; + int prec = p->prec; + char *bf = p->bf; + size_t bf_len = p->bf_len; + + /* Number of filling characters */ + width -= bf_len; + prec -= bf_len; + if (p->sign) + width--; + if (p->alt && p->base == 16) + width -= 2; + else if (p->alt && p->base == 8) + width--; + if (prec > 0) + width -= prec; + + /* Fill with space to align to the right, before alternate or sign */ + if (!p->lz && !p->align_left) + { + while (width-- > 0) + putf(putp, ' '); + } + + /* print sign */ + if (p->sign) + putf(putp, p->sign); + + /* Alternate */ + if (p->alt && p->base == 16) + { + putf(putp, '0'); + putf(putp, (p->uc ? 'X' : 'x')); + } + else if (p->alt && p->base == 8) + { + putf(putp, '0'); + } + + /* Fill with zeros, after alternate or sign */ + while (prec-- > 0) + putf(putp, '0'); + if (p->lz) + { + while (width-- > 0) + putf(putp, '0'); + } + + /* Put actual buffer */ + while ((bf_len-- > 0) && (ch = *bf++)) + putf(putp, ch); + + /* Fill with space to align to the left, after string */ + if (!p->lz && p->align_left) + { + while (width-- > 0) + putf(putp, ' '); + } +} + +void tfp_format(void *putp, putcf putf, const char *fmt, va_list va) +{ + struct param p; + char bf[BF_MAX]; + char ch; + + while ((ch = *(fmt++))) + { + if (ch != '%') + { + putf(putp, ch); + } + else + { +#if defined(PRINTF_LONG_SUPPORT) + char lng = 0; /* 1 for long, 2 for long long */ +#endif + /* Init parameter struct */ + p.lz = 0; + p.alt = 0; + p.uc = 0; + p.align_left = 0; + p.width = 0; + p.prec = -1; + p.sign = 0; + p.bf = bf; + p.bf_len = 0; + + /* Flags */ + while ((ch = *(fmt++))) + { + switch (ch) + { + case '-': + p.align_left = 1; + continue; + case '0': + p.lz = 1; + continue; + case '#': + p.alt = 1; + continue; + default: + break; + } + break; + } + + if (p.align_left) + p.lz = 0; + + /* Width */ + if (ch == '*') + { + ch = *(fmt++); + p.width = va_arg(va, int); + if (p.width < 0) + { + p.align_left = 1; + p.width = -p.width; + } + } + else if (IS_DIGIT(ch)) + { + unsigned int width; + ch = a2u(ch, &fmt, 10, &(width)); + p.width = width; + } + + /* Precision */ + if (ch == '.') + { + ch = *(fmt++); + if (ch == '*') + { + int prec; + ch = *(fmt++); + prec = va_arg(va, int); + if (prec < 0) + /* act as if precision was + * omitted */ + p.prec = -1; + else + p.prec = prec; + } + else if (IS_DIGIT(ch)) + { + unsigned int prec; + ch = a2u(ch, &fmt, 10, &(prec)); + p.prec = prec; + } + else + { + p.prec = 0; + } + } + if (p.prec >= 0) + /* precision causes zero pad to be ignored */ + p.lz = 0; + +#if defined(PRINTF_SIZE_T_SUPPORT) +#if defined(PRINTF_LONG_SUPPORT) + if (ch == 'z') + { + ch = *(fmt++); + if (sizeof(size_t) == sizeof(unsigned long int)) + lng = 1; +#if defined(PRINTF_LONG_LONG_SUPPORT) + else if (sizeof(size_t) == sizeof(unsigned long long int)) + lng = 2; +#endif + } + else +#endif +#endif + +#if defined(PRINTF_LONG_SUPPORT) + if (ch == 'l') + { + ch = *(fmt++); + lng = 1; +#if defined(PRINTF_LONG_LONG_SUPPORT) + if (ch == 'l') + { + ch = *(fmt++); + lng = 2; + } +#endif + } +#endif + switch (ch) + { + case 0: + goto abort; + case 'u': + p.base = 10; + if (p.prec < 0) + p.prec = 1; +#if defined(PRINTF_LONG_SUPPORT) +#if defined(PRINTF_LONG_LONG_SUPPORT) + if (2 == lng) + ulli2a(va_arg(va, unsigned long long int), &p); + else +#endif + if (1 == lng) + uli2a(va_arg(va, unsigned long int), &p); + else +#endif + ui2a(va_arg(va, unsigned int), &p); + putchw(putp, putf, &p); + break; + case 'd': /* No break */ + case 'i': + p.base = 10; + if (p.prec < 0) + p.prec = 1; +#if defined(PRINTF_LONG_SUPPORT) +#if defined(PRINTF_LONG_LONG_SUPPORT) + if (2 == lng) + lli2a(va_arg(va, long long int), &p); + else +#endif + if (1 == lng) + li2a(va_arg(va, long int), &p); + else +#endif + i2a(va_arg(va, int), &p); + putchw(putp, putf, &p); + break; +#if defined(SIZEOF_POINTER) + case 'p': + p.alt = 1; +#if defined(SIZEOF_INT) && SIZEOF_POINTER <= SIZEOF_INT + lng = 0; +#elif defined(SIZEOF_LONG) && SIZEOF_POINTER <= SIZEOF_LONG + lng = 1; +#elif defined(SIZEOF_LONG_LONG) && SIZEOF_POINTER <= SIZEOF_LONG_LONG + lng = 2; +#endif +#endif + /* No break */ + case 'x': /* No break */ + case 'X': + p.base = 16; + p.uc = (ch == 'X') ? 1 : 0; + if (p.prec < 0) + p.prec = 1; +#if defined(PRINTF_LONG_SUPPORT) +#if defined(PRINTF_LONG_LONG_SUPPORT) + if (2 == lng) + ulli2a(va_arg(va, unsigned long long int), &p); + else +#endif + if (1 == lng) + uli2a(va_arg(va, unsigned long int), &p); + else +#endif + ui2a(va_arg(va, unsigned int), &p); + putchw(putp, putf, &p); + break; + case 'o': + p.base = 8; + if (p.prec < 0) + p.prec = 1; + ui2a(va_arg(va, unsigned int), &p); + putchw(putp, putf, &p); + break; + case 'c': + putf(putp, (char)(va_arg(va, int))); + break; + case 's': + { + unsigned int prec = p.prec; + char *b; + p.bf = va_arg(va, char*); + b = p.bf; + while ((prec-- != 0) && *b++) + { + p.bf_len++; + } + p.prec = -1; + putchw(putp, putf, &p); + } + break; + case '%': + putf(putp, ch); + break; + default: + break; + } + } + } +abort:; +} + +#if defined(TINYPRINTF_DEFINE_TFP_PRINTF) +static putcf stdout_putf; +static void *stdout_putp; + +void init_printf(void *putp, putcf putf) +{ + stdout_putf = putf; + stdout_putp = putp; +} + +void tfp_printf(char *fmt, ...) +{ + va_list va; + va_start(va, fmt); + tfp_format(stdout_putp, stdout_putf, fmt, va); + va_end(va); +} +#endif + +#if defined(TINYPRINTF_DEFINE_TFP_SPRINTF) +struct _vsnprintf_putcf_data +{ + size_t dest_capacity; + char *dest; + size_t num_chars; +}; + +static void _vsnprintf_putcf(void *p, char c) +{ + struct _vsnprintf_putcf_data *data = (struct _vsnprintf_putcf_data*)p; + if (data->num_chars < data->dest_capacity) + data->dest[data->num_chars] = c; + data->num_chars++; +} + +int tfp_vsnprintf(char *str, size_t size, const char *format, va_list ap) +{ + struct _vsnprintf_putcf_data data; + + if (size < 1) + return 0; + + data.dest = str; + data.dest_capacity = size - 1; + data.num_chars = 0; + tfp_format(&data, _vsnprintf_putcf, format, ap); + + if (data.num_chars < data.dest_capacity) + data.dest[data.num_chars] = '\0'; + else + data.dest[data.dest_capacity] = '\0'; + + return data.num_chars; +} + +int tfp_snprintf(char *str, size_t size, const char *format, ...) +{ + va_list ap; + int retval; + + va_start(ap, format); + retval = tfp_vsnprintf(str, size, format, ap); + va_end(ap); + return retval; +} + +struct _vsprintf_putcf_data +{ + char *dest; + size_t num_chars; +}; + +static void _vsprintf_putcf(void *p, char c) +{ + struct _vsprintf_putcf_data *data = (struct _vsprintf_putcf_data*)p; + data->dest[data->num_chars++] = c; +} + +int tfp_vsprintf(char *str, const char *format, va_list ap) +{ + struct _vsprintf_putcf_data data; + data.dest = str; + data.num_chars = 0; + tfp_format(&data, _vsprintf_putcf, format, ap); + data.dest[data.num_chars] = '\0'; + return data.num_chars; +} + +int tfp_sprintf(char *str, const char *format, ...) +{ + va_list ap; + int retval; + + va_start(ap, format); + retval = tfp_vsprintf(str, format, ap); + va_end(ap); + return retval; +} +#endif + +static void uart_putf(void *unused, char c) +{ + UNUSED(unused); + uart_putchar(c); +} + +int printk(const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + /* Begin protected code */ + hartlock_lock(&lock); + tfp_format(stdout_putp, uart_putf, format, ap); + /* End protected code */ + hartlock_unlock(&lock); + va_end(ap); + + return 0; +} + diff --git a/lib/bsp/sleep.c b/lib/bsp/sleep.c new file mode 100644 index 0000000..e0383c4 --- /dev/null +++ b/lib/bsp/sleep.c @@ -0,0 +1,38 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "sleep.h" +#include "sysctl.h" + +int usleep(uint64_t usec) +{ + uint64_t nop_all = usec * sysctl_clock_get_freq(SYSCTL_CLOCK_CPU) / 1000000UL / 6; + + while (nop_all--) + { + asm volatile("nop"); + } + return 0; +} + +int msleep(uint64_t msec) +{ + return (unsigned int)usleep(msec * 1000); +} + +unsigned int sleep(unsigned int seconds) +{ + return (unsigned int)msleep(seconds * 1000); +} + diff --git a/lib/bsp/syscalls.c b/lib/bsp/syscalls.c new file mode 100644 index 0000000..e4bcc92 --- /dev/null +++ b/lib/bsp/syscalls.c @@ -0,0 +1,641 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Enable kernel-mode log API */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "syscalls.h" +#include "atomic.h" +#include "clint.h" +#include "fpioa.h" +#include "interrupt.h" +#include "sysctl.h" +#include "uarths.h" +#include "util.h" +#include "syslog.h" +#include "dump.h" + +/** + * @note System call list + * + * See also riscv-newlib/libgloss/riscv/syscalls.c + * + * | System call | Number | + * |------------------|--------| + * | SYS_exit | 93 | + * | SYS_exit_group | 94 | + * | SYS_getpid | 172 | + * | SYS_kill | 129 | + * | SYS_read | 63 | + * | SYS_write | 64 | + * | SYS_open | 1024 | + * | SYS_openat | 56 | + * | SYS_close | 57 | + * | SYS_lseek | 62 | + * | SYS_brk | 214 | + * | SYS_link | 1025 | + * | SYS_unlink | 1026 | + * | SYS_mkdir | 1030 | + * | SYS_chdir | 49 | + * | SYS_getcwd | 17 | + * | SYS_stat | 1038 | + * | SYS_fstat | 80 | + * | SYS_lstat | 1039 | + * | SYS_fstatat | 79 | + * | SYS_access | 1033 | + * | SYS_faccessat | 48 | + * | SYS_pread | 67 | + * | SYS_pwrite | 68 | + * | SYS_uname | 160 | + * | SYS_getuid | 174 | + * | SYS_geteuid | 175 | + * | SYS_getgid | 176 | + * | SYS_getegid | 177 | + * | SYS_mmap | 222 | + * | SYS_munmap | 215 | + * | SYS_mremap | 216 | + * | SYS_time | 1062 | + * | SYS_getmainvars | 2011 | + * | SYS_rt_sigaction | 134 | + * | SYS_writev | 66 | + * | SYS_gettimeofday | 169 | + * | SYS_times | 153 | + * | SYS_fcntl | 25 | + * | SYS_getdents | 61 | + * | SYS_dup | 23 | + * + */ + +#ifndef UNUSED +#define UNUSED(x) (void)(x) +#endif + +static const char *TAG = "SYSCALL"; + +extern char _heap_start[]; +extern char _heap_end[]; +char *_heap_cur = &_heap_start[0]; + + +void __attribute__((noreturn)) sys_exit(int code) +{ + /* Read hart id */ + unsigned long hart_id = read_csr(mhartid); + /* First print some diagnostic information. */ + LOGW(TAG, "sys_exit called by core %ld with 0x%lx\n", hart_id, (uint64_t)code); + /* Write exit register to pause netlist simulation */ + volatile uint32_t *reg = (volatile uint32_t *)0x50440080UL; + /* Write stop bit and write back */ + *reg = (1UL << 31); + + /* Send 0 to uart */ + uart_putchar(0); + + while (1) + continue; +} + +static int sys_nosys(long a0, long a1, long a2, long a3, long a4, long a5, unsigned long n) +{ + UNUSED(a3); + UNUSED(a4); + UNUSED(a5); + + LOGE(TAG, "Unsupported syscall %ld: a0=%lx, a1=%lx, a2=%lx!\n", n, a0, a1, a2); + /* Send 0 to uart */ + uart_putchar(0); + while (1) + continue; + return -ENOSYS; +} + +static int sys_success(void) +{ + return 0; +} + +static size_t sys_brk(size_t pos) +{ + uintptr_t res = 0; + /** + * brk() sets the end of the data segment to the value + * specified by addr, when that value is reasonable, the system + * has enough memory, and the process does not exceed its + * maximum data size. + * + * sbrk() increments the program's data space by increment + * bytes. Calling sbrk() with an increment of 0 can be used to + * find the current location of the program break. + * + * uintptr_t brk(uintptr_t ptr); + * + * IN : regs[10] = ptr + * OUT: regs[10] = ptr + */ + + /** + * First call: Initialization brk pointer. newlib will pass + * ptr = 0 when it is first called. In this case the address + * _heap_start will be return. + * + * Call again: Adjust brk pointer. The ptr never equal with + * 0. If ptr is below _heap_end, then allocate memory. + * Otherwise throw out of memory error, return -1. + */ + + if (pos) + { + /* Call again */ + if ((uintptr_t)pos > (uintptr_t)&_heap_end[0]) + { + /* Memory out, return -ENOMEM */ + LOGE(TAG, "Out of memory\n"); + res = -ENOMEM; + } + else + { + /* Adjust brk pointer. */ + _heap_cur = (char *)(uintptr_t)pos; + /* Return current address. */ + res = (uintptr_t)_heap_cur; + } + } + else + { + /* First call, return initial address */ + res = (uintptr_t)&_heap_start[0]; + } + return (size_t)res; +} + +static ssize_t sys_write(int file, const void *ptr, size_t len) +{ + ssize_t res = -EBADF; + + /** + * Write to a file. + * + * ssize_t write(int file, const void* ptr, size_t len) + * + * IN : regs[10] = file, regs[11] = ptr, regs[12] = len + * OUT: regs[10] = len + */ + + /* Get size to write */ + register size_t length = len; + /* Get data pointer */ + register char *data = (char *)ptr; + + if (STDOUT_FILENO == file || STDERR_FILENO == file) + { + /* Write data */ + while (length-- > 0 && *data != 0) + uart_putchar(*(data++)); + + /* Return the actual size written */ + res = len; + } + else + { + /* Not support yet */ + res = -ENOSYS; + } + + return res; +} + +static int sys_fstat(int file, struct stat *st) +{ + int res = -EBADF; + + /** + * Status of an open file. The sys/stat.h header file required + * is + * distributed in the include subdirectory for this C library. + * + * int fstat(int file, struct stat* st) + * + * IN : regs[10] = file, regs[11] = st + * OUT: regs[10] = Upon successful completion, 0 shall be + * returned. + * Otherwise, -1 shall be returned and errno set to indicate + * the error. + */ + + UNUSED(file); + + if (st != NULL) + memset(st, 0, sizeof(struct stat)); + /* Return the result */ + res = -ENOSYS; + /** + * Note: This value will return to syscall wrapper, syscall + * wrapper will set errno to ENOSYS and return -1 + */ + + return res; +} + +static int sys_close(int file) +{ + int res = -EBADF; + + /** + * Close a file. + * + * int close(int file) + * + * IN : regs[10] = file + * OUT: regs[10] = Upon successful completion, 0 shall be + * returned. + * Otherwise, -1 shall be returned and errno set to indicate + * the error. + */ + + UNUSED(file); + /* Return the result */ + res = 0; + return res; +} + +static int sys_gettimeofday(struct timeval *tp, void *tzp) +{ + /** + * Get the current time. Only relatively correct. + * + * int gettimeofday(struct timeval* tp, void* tzp) + * + * IN : regs[10] = tp + * OUT: regs[10] = Upon successful completion, 0 shall be + * returned. + * Otherwise, -1 shall be returned and errno set to indicate + * the error. + */ + UNUSED(tzp); + + if (tp != NULL) + { + uint64_t clint_usec = clint->mtime / (sysctl_clock_get_freq(SYSCTL_CLOCK_CPU) / CLINT_CLOCK_DIV / 1000000UL); + + tp->tv_sec = clint_usec / 1000000UL; + tp->tv_usec = clint_usec % 1000000UL; + } + /* Return the result */ + return 0; +} + +uintptr_t __attribute__((weak)) +handle_ecall(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]) +{ + UNUSED(cause); + UNUSED(fregs); + enum syscall_id_e + { + SYS_ID_NOSYS, + SYS_ID_SUCCESS, + SYS_ID_EXIT, + SYS_ID_BRK, + SYS_ID_WRITE, + SYS_ID_FSTAT, + SYS_ID_CLOSE, + SYS_ID_GETTIMEOFDAY, + SYS_ID_MAX + }; + + static uintptr_t (* const syscall_table[])(long a0, long a1, long a2, long a3, long a4, long a5, unsigned long n) = + { + [SYS_ID_NOSYS] = (void *)sys_nosys, + [SYS_ID_SUCCESS] = (void *)sys_success, + [SYS_ID_EXIT] = (void *)sys_exit, + [SYS_ID_BRK] = (void *)sys_brk, + [SYS_ID_WRITE] = (void *)sys_write, + [SYS_ID_FSTAT] = (void *)sys_fstat, + [SYS_ID_CLOSE] = (void *)sys_close, + [SYS_ID_GETTIMEOFDAY] = (void *)sys_gettimeofday, + }; + +#if defined(__GNUC__) +#pragma GCC diagnostic ignored "-Woverride-init" +#endif + static const uint8_t syscall_id_table[0x100] = + { + [0x00 ... 0xFF] = SYS_ID_NOSYS, + [0xFF & SYS_exit] = SYS_ID_EXIT, + [0xFF & SYS_exit_group] = SYS_ID_EXIT, + [0xFF & SYS_getpid] = SYS_ID_NOSYS, + [0xFF & SYS_kill] = SYS_ID_NOSYS, + [0xFF & SYS_read] = SYS_ID_NOSYS, + [0xFF & SYS_write] = SYS_ID_WRITE, + [0xFF & SYS_open] = SYS_ID_NOSYS, + [0xFF & SYS_openat] = SYS_ID_NOSYS, + [0xFF & SYS_close] = SYS_ID_CLOSE, + [0xFF & SYS_lseek] = SYS_ID_NOSYS, + [0xFF & SYS_brk] = SYS_ID_BRK, + [0xFF & SYS_link] = SYS_ID_NOSYS, + [0xFF & SYS_unlink] = SYS_ID_NOSYS, + [0xFF & SYS_mkdir] = SYS_ID_NOSYS, + [0xFF & SYS_chdir] = SYS_ID_NOSYS, + [0xFF & SYS_getcwd] = SYS_ID_NOSYS, + [0xFF & SYS_stat] = SYS_ID_NOSYS, + [0xFF & SYS_fstat] = SYS_ID_FSTAT, + [0xFF & SYS_lstat] = SYS_ID_NOSYS, + [0xFF & SYS_fstatat] = SYS_ID_NOSYS, + [0xFF & SYS_access] = SYS_ID_NOSYS, + [0xFF & SYS_faccessat] = SYS_ID_NOSYS, + [0xFF & SYS_pread] = SYS_ID_NOSYS, + [0xFF & SYS_pwrite] = SYS_ID_NOSYS, + [0xFF & SYS_uname] = SYS_ID_NOSYS, + [0xFF & SYS_getuid] = SYS_ID_NOSYS, + [0xFF & SYS_geteuid] = SYS_ID_NOSYS, + [0xFF & SYS_getgid] = SYS_ID_NOSYS, + [0xFF & SYS_getegid] = SYS_ID_NOSYS, + [0xFF & SYS_mmap] = SYS_ID_NOSYS, + [0xFF & SYS_munmap] = SYS_ID_NOSYS, + [0xFF & SYS_mremap] = SYS_ID_NOSYS, + [0xFF & SYS_time] = SYS_ID_NOSYS, + [0xFF & SYS_getmainvars] = SYS_ID_NOSYS, + [0xFF & SYS_rt_sigaction] = SYS_ID_NOSYS, + [0xFF & SYS_writev] = SYS_ID_NOSYS, + [0xFF & SYS_gettimeofday] = SYS_ID_GETTIMEOFDAY, + [0xFF & SYS_times] = SYS_ID_NOSYS, + [0xFF & SYS_fcntl] = SYS_ID_NOSYS, + [0xFF & SYS_getdents] = SYS_ID_NOSYS, + [0xFF & SYS_dup] = SYS_ID_NOSYS, + }; +#if defined(__GNUC__) +#pragma GCC diagnostic warning "-Woverride-init" +#endif + + regs[10] = syscall_table[syscall_id_table[0xFF & regs[17]]] + ( + regs[10], /* a0 */ + regs[11], /* a1 */ + regs[12], /* a2 */ + regs[13], /* a3 */ + regs[14], /* a4 */ + regs[15], /* a5 */ + regs[17] /* n */ + ); + + return epc + ((*(unsigned short *)epc & 3) == 3 ? 4 : 2); +} + +uintptr_t __attribute__((weak, alias("handle_ecall"))) +handle_ecall_u(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]); + +uintptr_t __attribute__((weak, alias("handle_ecall"))) +handle_ecall_h(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]); + +uintptr_t __attribute__((weak, alias("handle_ecall"))) +handle_ecall_s(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]); + +uintptr_t __attribute__((weak, alias("handle_ecall"))) +handle_ecall_m(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]); + +uintptr_t __attribute__((weak)) +handle_misaligned_fetch(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]) +{ + dump_core("misaligned fetch", cause, epc, regs, fregs); + sys_exit(1337); + return epc; +} + +uintptr_t __attribute__((weak)) +handle_fault_fetch(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]) +{ + dump_core("fault fetch", cause, epc, regs, fregs); + sys_exit(1337); + return epc; +} + +uintptr_t __attribute__((weak)) +handle_illegal_instruction(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]) +{ + dump_core("illegal instruction", cause, epc, regs, fregs); + sys_exit(1337); + return epc; +} + +uintptr_t __attribute__((weak)) +handle_breakpoint(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]) +{ + dump_core("breakpoint", cause, epc, regs, fregs); + sys_exit(1337); + return epc; +} + +uintptr_t __attribute__((weak)) +handle_misaligned_load(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]) +{ + /* notice this function only support 16bit or 32bit instruction */ + + bool compressed = (*(unsigned short *)epc & 3) != 3; + bool fpu = 0; /* load to fpu ? */ + uintptr_t addr = 0; /* src addr */ + uint8_t src = 0; /* src register */ + uint8_t dst = 0; /* dst register */ + uint8_t len = 0; /* data length */ + int offset = 0; /* addr offset to addr in reg */ + bool unsigned_ = 0; /* unsigned */ + uint64_t data_load = 0;/* real data load */ + + if (compressed) + { + /* compressed instruction should not get this fault. */ + goto on_error; + } + else + { + uint32_t instruct = *(uint32_t *)epc; + uint8_t opcode = instruct&0x7F; + + dst = (instruct >> 7)&0x1F; + len = (instruct >> 12)&3; + unsigned_ = (instruct >> 14)&1; + src = (instruct >> 15)&0x1F; + offset = (instruct >> 20); + len = 1 << len; + switch (opcode) + { + case 3:/* load */ + break; + case 7:/* fpu load */ + fpu = 1; + break; + default: + goto on_error; + } + } + + if (offset >> 11) + offset = -((offset & 0x3FF) + 1); + + addr = (uint64_t)((uint64_t)regs[src] + offset); + + for (int i = 0; i < len; ++i) + data_load |= ((uint64_t)*((uint8_t *)addr + i)) << (8 * i); + + + if (!unsigned_ & !fpu) + { + /* adjust sign */ + switch (len) + { + case 1: + data_load = (uint64_t)(int64_t)((int8_t)data_load); + break; + case 2: + data_load = (uint64_t)(int64_t)((int16_t)data_load); + break; + case 4: + data_load = (uint64_t)(int64_t)((int32_t)data_load); + break; + default: + break; + } + } + + if (fpu) + fregs[dst] = data_load; + else + regs[dst] = data_load; + + LOGV(TAG, "misaligned load recovered at %08lx. len:%02d,addr:%08lx,reg:%02d,data:%016lx,signed:%1d,float:%1d", (uint64_t)epc, len, (uint64_t)addr, dst, data_load, !unsigned_, fpu); + + return epc + (compressed ? 2 : 4); +on_error: + dump_core("misaligned load", cause, epc, regs, fregs); + sys_exit(1337); + return epc; +} + +uintptr_t __attribute__((weak)) +handle_fault_load(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]) +{ + dump_core("fault load", cause, epc, regs, fregs); + sys_exit(1337); + return epc; +} + +uintptr_t __attribute__((weak)) +handle_misaligned_store(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]) +{ + /* notice this function only support 16bit or 32bit instruction */ + + bool compressed = (*(unsigned short *)epc & 3) != 3; + bool fpu = 0; /* store to fpu*/ + uintptr_t addr = 0; /* src addr*/ + uint8_t src = 0; /* src register*/ + uint8_t dst = 0; /* dst register*/ + uint8_t len = 0; /* data length*/ + int offset = 0; /* addr offset to addr in reg*/ + uint64_t data_store = 0;/* real data store*/ + + if (compressed) + { + /* compressed instruction should not get this fault. */ + goto on_error; + } + else + { + uint32_t instruct = *(uint32_t *)epc; + uint8_t opcode = instruct&0x7F; + + len = (instruct >> 12)&7; + dst = (instruct >> 15)&0x1F; + src = (instruct >> 20)&0x1F; + offset = ((instruct >> 7)&0x1F) | ((instruct >> 20)&0xFE0); + len = 1 << len; + switch (opcode) + { + case 0x23:/* store */ + break; + case 0x27:/* fpu store */ + fpu = 1; + break; + default: + goto on_error; + } + } + + if (offset >> 11) + offset = -((offset & 0x3FF) + 1); + + addr = (uint64_t)((uint64_t)regs[dst] + offset); + + + if (fpu) + data_store = fregs[src]; + else + data_store = regs[src]; + + for (int i = 0; i < len; ++i) + *((uint8_t *)addr + i) = (data_store >> (i*8)) & 0xFF; + + LOGV(TAG, "misaligned store recovered at %08lx. len:%02d,addr:%08lx,reg:%02d,data:%016lx,float:%1d", (uint64_t)epc, len, (uint64_t)addr, src, data_store, fpu); + + return epc + (compressed ? 2 : 4); +on_error: + dump_core("misaligned store", cause, epc, regs, fregs); + sys_exit(1337); + return epc; +} + +uintptr_t __attribute__((weak)) +handle_fault_store(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]) +{ + dump_core("fault store", cause, epc, regs, fregs); + sys_exit(1337); + return epc; +} + +uintptr_t handle_syscall(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]) +{ + + static uintptr_t (* const cause_table[])(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]) = + { + [CAUSE_MISALIGNED_FETCH] = handle_misaligned_fetch, + [CAUSE_FAULT_FETCH] = handle_fault_fetch, + [CAUSE_ILLEGAL_INSTRUCTION] = handle_illegal_instruction, + [CAUSE_BREAKPOINT] = handle_breakpoint, + [CAUSE_MISALIGNED_LOAD] = handle_misaligned_load, + [CAUSE_FAULT_LOAD] = handle_fault_load, + [CAUSE_MISALIGNED_STORE] = handle_misaligned_store, + [CAUSE_FAULT_STORE] = handle_fault_store, + [CAUSE_USER_ECALL] = handle_ecall_u, + [CAUSE_SUPERVISOR_ECALL] = handle_ecall_h, + [CAUSE_HYPERVISOR_ECALL] = handle_ecall_s, + [CAUSE_MACHINE_ECALL] = handle_ecall_m, + }; + + return cause_table[cause](cause, epc, regs, fregs); +} + +size_t get_free_heap_size(void) +{ + return (size_t)(&_heap_end[0] - _heap_cur); +} + diff --git a/lib/drivers/aes.c b/lib/drivers/aes.c new file mode 100644 index 0000000..cc2f476 --- /dev/null +++ b/lib/drivers/aes.c @@ -0,0 +1,365 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include "env/encoding.h" +#include "aes.h" +#include "sysctl.h" + +volatile aes_t* const aes = (volatile aes_t*)AES_BASE_ADDR; + +void aes_clkinit() +{ + sysctl_clock_enable(SYSCTL_CLOCK_AES); + sysctl_reset(SYSCTL_RESET_AES); +} + +int aes_init(uint8_t* key_addr, uint8_t key_length, uint8_t* aes_iv, + uint8_t iv_length, uint8_t* aes_aad, enum aes_cipher_mod cipher_mod, + enum aes_encrypt_sel encrypt_sel, uint32_t add_size, uint32_t data_size) +{ + int i, remainder, num, cnt; + uint32_t u32data; + uint8_t u8data[4] = {0}; + + if ((cipher_mod == AES_ECB) || (cipher_mod == AES_CBC)) + data_size = ((data_size + 15) / 16) * 16; + aes->aes_endian |= 1; + + /* write key Low byte alignment*/ + num = key_length / 4; + for (i = 0; i < num; i++) + aes->aes_key[i] = *((uint32_t*)(&key_addr[key_length - (4 * i) - 4])); + remainder = key_length % 4; + if (remainder) + { + switch (remainder) + { + case 1: + u8data[0] = key_addr[0]; + break; + case 2: + u8data[0] = key_addr[0]; + u8data[1] = key_addr[1]; + break; + case 3: + u8data[0] = key_addr[0]; + u8data[1] = key_addr[1]; + u8data[2] = key_addr[2]; + break; + default: + break; + } + aes->aes_key[num] = *((uint32_t*)(&u8data[0])); + } + + /*write iv Low byte alignment*/ + num = iv_length / 4; + for (i = 0; i < num; i++) + aes->aes_iv[i] = *((uint32_t*)(&aes_iv[iv_length - (4 * i) - 4])); + remainder = iv_length % 4; + if (remainder) + { + switch (remainder) + { + case 1: + u8data[0] = aes_iv[0]; + break; + case 2: + u8data[0] = aes_iv[0]; + u8data[1] = aes_iv[1]; + break; + case 3: + u8data[0] = aes_iv[0]; + u8data[1] = aes_iv[1]; + u8data[2] = aes_iv[2]; + break; + default: + break; + } + aes->aes_iv[num] = *((uint32_t*)(&u8data[0])); + } + + aes->mode_ctl.cipher_mode = cipher_mod; + + /* + * [1:0],set the first bit and second bit 00:ecb; 01:cbc; + * 10,11:aes_gcm + */ + aes->encrypt_sel = encrypt_sel; + aes->gb_aad_end_adr = add_size - 1; + aes->gb_pc_end_adr = data_size - 1; + aes->gb_aes_en |= 1; + + /* write aad */ + if (cipher_mod == AES_GCM) + { + num = add_size / 4; + for (i = 0; i < num; i++) + { + u32data = *((uint32_t*)(&aes_aad[i * 4])); + while (!aes_get_data_in_flag()) + ; + aes_write_aad(u32data); + } + cnt = 4 * num; + remainder = add_size % 4; + if (remainder) + { + switch (remainder) + { + case 1: + u8data[0] = aes_aad[cnt]; + break; + case 2: + u8data[0] = aes_aad[cnt]; + u8data[1] = aes_aad[cnt + 1]; + break; + case 3: + u8data[0] = aes_aad[cnt]; + u8data[1] = aes_aad[cnt + 1]; + u8data[2] = aes_aad[cnt + 2]; + break; + default: + return 0; + } + u32data = *((uint32_t*)(&u8data[0])); + while (!aes_get_data_in_flag()) + ; + aes_write_aad(u32data); + } + } + + return 1; +} + +int aes_write_aad(uint32_t aad_data) +{ + aes->aes_aad_data = aad_data; + return 0; +} + +int aes_write_text(uint32_t text_data) +{ + aes->aes_text_data = text_data; + return 0; +} + +int aes_write_tag(uint32_t* tag) +{ + aes->gcm_in_tag[0] = tag[3]; + aes->gcm_in_tag[1] = tag[2]; + aes->gcm_in_tag[2] = tag[1]; + aes->gcm_in_tag[3] = tag[0]; + return 0; +} + +int aes_get_data_in_flag(void) +{ + /* data can in flag 1: data ready 0: data not ready */ + return aes->data_in_flag; +} + +int aes_get_data_out_flag(void) +{ + /* data can output flag 1: data ready 0: data not ready */ + return aes->data_out_flag; +} + +int aes_get_tag_in_flag(void) +{ + /* data can output flag 1: data ready 0: data not ready */ + return aes->tag_in_flag; +} + +uint32_t aes_read_out_data(void) +{ + return aes->aes_out_data; +} + +int aes_check_tag(void) +{ + return aes->tag_chk; +} + +int aes_get_tag(uint8_t* l_tag) +{ + uint32_t u32tag; + uint8_t i = 0; + + u32tag = aes->gcm_out_tag[3]; + l_tag[i++] = (uint8_t)((u32tag >> 24) & 0xff); + l_tag[i++] = (uint8_t)((u32tag >> 16) & 0xff); + l_tag[i++] = (uint8_t)((u32tag >> 8) & 0xff); + l_tag[i++] = (uint8_t)((u32tag)&0xff); + + u32tag = aes->gcm_out_tag[2]; + l_tag[i++] = (uint8_t)((u32tag >> 24) & 0xff); + l_tag[i++] = (uint8_t)((u32tag >> 16) & 0xff); + l_tag[i++] = (uint8_t)((u32tag >> 8) & 0xff); + l_tag[i++] = (uint8_t)((u32tag)&0xff); + + u32tag = aes->gcm_out_tag[1]; + l_tag[i++] = (uint8_t)((u32tag >> 24) & 0xff); + l_tag[i++] = (uint8_t)((u32tag >> 16) & 0xff); + l_tag[i++] = (uint8_t)((u32tag >> 8) & 0xff); + l_tag[i++] = (uint8_t)((u32tag)&0xff); + + u32tag = aes->gcm_out_tag[0]; + l_tag[i++] = (uint8_t)((u32tag >> 24) & 0xff); + l_tag[i++] = (uint8_t)((u32tag >> 16) & 0xff); + l_tag[i++] = (uint8_t)((u32tag >> 8) & 0xff); + l_tag[i++] = (uint8_t)((u32tag)&0xff); + return 1; +} + +int aes_clear_chk_tag(void) +{ + aes->tag_clear = 0; + return 0; +} + +int aes_process_less_80_bytes(uint8_t* aes_in_data, + uint8_t* aes_out_data, + uint32_t data_size, + enum aes_cipher_mod cipher_mod) +{ + int padding_size; + int num, i, remainder, cnt; + uint32_t u32data; + uint8_t u8data[4] = {0}; + /* Fill 128 bits (16byte) */ + padding_size = ((data_size + 15) / 16) * 16; + + /* write text */ + num = data_size / 4; + for (i = 0; i < num; i++) + { + u32data = *((uint32_t*)(&aes_in_data[i * 4])); + while (!aes_get_data_in_flag()) + ; + aes_write_text(u32data); + } + cnt = 4 * num; + remainder = data_size % 4; + if (remainder) + { + switch (remainder) + { + case 1: + u8data[0] = aes_in_data[cnt]; + break; + case 2: + u8data[0] = aes_in_data[cnt]; + u8data[1] = aes_in_data[cnt + 1]; + break; + case 3: + u8data[0] = aes_in_data[cnt]; + u8data[1] = aes_in_data[cnt + 1]; + u8data[2] = aes_in_data[cnt + 2]; + break; + default: + return 0; + } + u32data = *((uint32_t*)(&u8data[0])); + while (!aes_get_data_in_flag()) + ; + aes_write_text(u32data); + } + if ((cipher_mod == AES_ECB) || (cipher_mod == AES_CBC)) + { + /* use 0 to Fill 128 bits */ + num = (padding_size - data_size) / 4; + for (i = 0; i < num; i++) + { + while (!aes_get_data_in_flag()) + ; + aes_write_text(0); + } + /* get data */ + num = padding_size / 4; + } + /* get data */ + for (i = 0; i < num; i++) + { + while (!aes_get_data_out_flag()) + ; + *((uint32_t*)(&aes_out_data[i * 4])) = aes_read_out_data(); + } + if ((cipher_mod == AES_GCM) && (remainder)) + { + while (!aes_get_data_out_flag()) + ; + + *((uint32_t*)(&u8data[0])) = aes_read_out_data(); + switch (remainder) + { + case 1: + aes_out_data[num * 4] = u8data[0]; + break; + case 2: + aes_out_data[num * 4] = u8data[0]; + aes_out_data[(i * 4) + 1] = u8data[1]; + break; + case 3: + aes_out_data[num * 4] = u8data[0]; + aes_out_data[(i * 4) + 1] = u8data[1]; + aes_out_data[(i * 4) + 2] = u8data[2]; + break; + default: + return 0; + } + } + return 1; +} + +int aes_process(uint8_t* aes_in_data, + uint8_t* aes_out_data, + uint32_t data_size, + enum aes_cipher_mod cipher_mod) +{ + uint32_t i, temp_size; + + i = 0; + if (data_size >= 80) + { + for (i = 0; i < (data_size / 80); i++) + aes_process_less_80_bytes(&aes_in_data[i * 80], &aes_out_data[i * 80], 80, cipher_mod); + } + temp_size = data_size % 80; + if (temp_size) + aes_process_less_80_bytes(&aes_in_data[i * 80], &aes_out_data[i * 80], temp_size, cipher_mod); + return 1; +} + +int aes_check_gcm_tag(uint32_t* aes_gcm_tag) +{ + /* check tag */ + while (!aes_get_tag_in_flag()) + ; + aes_write_tag(aes_gcm_tag); + while (!aes_check_tag()) + ; + if (aes_check_tag() == 2) + { + aes_clear_chk_tag(); + return 1; + } + else + { + aes_clear_chk_tag(); + return 0; + } +} diff --git a/lib/drivers/audio_bf.c b/lib/drivers/audio_bf.c new file mode 100644 index 0000000..8add54e --- /dev/null +++ b/lib/drivers/audio_bf.c @@ -0,0 +1,441 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include "env/encoding.h" +#include "audio_bf.h" +#include "syscalls.h" +#include "sysctl.h" + +#define BEAFORMING_BASE_ADDR (0x50250200U) + +volatile struct audio_bf_reg_t* const audio_bf = (volatile struct audio_bf_reg_t*)BEAFORMING_BASE_ADDR; + +/** + * Voice strength average value right shift factor. When performing sound direction detect, + * the average value of samples from different channels is required, this right shift factor + * is used to perform division. + * 0x0: no right shift; + * 0x1: right shift by 1-bit; + * . . . . . . + * 0xF: right shift by 14-bit. +*/ +void audio_bf_set_audio_gain(uint16_t gain) +{ + struct audio_bf_ch_cfg_t ch_cfg = audio_bf->bf_ch_cfg_reg; + + ch_cfg.we_bf_target_dir = 0; + ch_cfg.we_bf_sound_ch_en = 0; + ch_cfg.we_data_src_mode = 0; + ch_cfg.we_audio_gain = 1; + ch_cfg.audio_gain = gain; + audio_bf->bf_ch_cfg_reg = ch_cfg; +} + +void audio_bf_set_smpl_shift(uint8_t smpl_shift) +{ + struct audio_bf_dwsz_cfg_t tmp = audio_bf->bf_dwsz_cfg_reg; + + tmp.smpl_shift_bits = smpl_shift; + audio_bf->bf_dwsz_cfg_reg = tmp; +} + +uint8_t audio_bf_get_smpl_shift(void) +{ + struct audio_bf_dwsz_cfg_t tmp = audio_bf->bf_dwsz_cfg_reg; + + return tmp.smpl_shift_bits; +} + +/** + * BF unit sound channel enable control bits. Bit 'x' corresponds to enable bit for sound + * channel 'x' (x = 0, 1, 2, . . ., 7). BF sound channels are related with I2S host RX channels. + * BF sound channel 0/1 correspond to the left/right channel of I2S RX0; BF channel 2/3 correspond + * to left/right channels of I2S RX1; and things like that. Software write '1' to enable a sound + * channel and hardware automatically clear the bit after the sample buffers used for direction + * searching is filled full. + * 0x1: writing '1' to enable the corresponding BF sound channel. + */ +void audio_bf_set_channel_enabled(uint8_t channel_bit) +{ + struct audio_bf_ch_cfg_t ch_cfg; + + ch_cfg.we_audio_gain = 0; + ch_cfg.we_bf_target_dir = 0; + ch_cfg.we_bf_sound_ch_en = 1; + ch_cfg.bf_sound_ch_en = channel_bit; + audio_bf->bf_ch_cfg_reg = ch_cfg; +} + +/** + * BF unit sound channel enable control bits. Bit 'x' corresponds to enable bit for sound + * channel 'x' (x = 0, 1, 2, . . ., 7). BF sound channels are related with I2S host RX channels. + * BF sound channel 0/1 correspond to the left/right channel of I2S RX0; BF channel 2/3 correspond + * to left/right channels of I2S RX1; and things like that. Software write '1' to enable a sound + * channel and hardware automatically clear the bit after the sample buffers used for direction + * searching is filled full. + * 0x1: writing '1' to enable the corresponding BF sound channel. + */ +void audio_bf_channel_enable(uint8_t channel_bit) +{ + struct audio_bf_ch_cfg_t ch_cfg = audio_bf->bf_ch_cfg_reg; + + ch_cfg.we_audio_gain = 0; + ch_cfg.we_bf_target_dir = 0; + ch_cfg.we_data_src_mode = 0; + ch_cfg.we_bf_sound_ch_en = 1; + ch_cfg.bf_sound_ch_en = channel_bit; + audio_bf->bf_ch_cfg_reg = ch_cfg; +} + +/** + * audio data source configure parameter. This parameter controls where the audio data source comes from. + * 0x0: audio data directly sourcing from audio_bf internal buffer; + * 0x1: audio data sourcing from FFT result buffer. + */ +void audio_bf_set_src_mode(uint8_t src_mode) +{ + struct audio_bf_ch_cfg_t ch_cfg = audio_bf->bf_ch_cfg_reg; + + ch_cfg.we_audio_gain = 0; + ch_cfg.we_bf_target_dir = 0; + ch_cfg.we_bf_sound_ch_en = 0; + ch_cfg.we_data_src_mode = 1; + ch_cfg.data_src_mode = src_mode; + audio_bf->bf_ch_cfg_reg = ch_cfg; +} + +/** + * I2S host beam-forming direction sample ibuffer read index configure register + */ +void audio_bf_set_direction_delay(uint8_t dir_num, uint8_t* dir_bidx) +{ + audio_bf->bf_dir_bidx[dir_num][0] = (struct audio_bf_dir_bidx_t){ + .dir_rd_idx0 = dir_bidx[0], + .dir_rd_idx1 = dir_bidx[1], + .dir_rd_idx2 = dir_bidx[2], + .dir_rd_idx3 = dir_bidx[3]}; + audio_bf->bf_dir_bidx[dir_num][1] = (struct audio_bf_dir_bidx_t){ + .dir_rd_idx0 = dir_bidx[4], + .dir_rd_idx1 = dir_bidx[5], + .dir_rd_idx2 = dir_bidx[6], + .dir_rd_idx3 = dir_bidx[7]}; +} + +/** + * Sound direction searching enable bit. Software writes '1' to start sound direction searching function. + * When all the sound sample buffers are filled full, this bit is cleared by hardware (this sample buffers + * are used for direction detect only). + * 0x1: enable direction searching. + */ +void audio_bf_dir_enable(void) +{ + struct audio_bf_ctl_t bf_en_tmp = audio_bf->bf_ctl_reg; + + bf_en_tmp.we_bf_dir_search_en = 1; + bf_en_tmp.bf_dir_search_en = 1; + audio_bf->bf_ctl_reg = bf_en_tmp; +} + +void audio_bf_dir_reset(void) +{ + struct audio_bf_ctl_t bf_en_tmp = audio_bf->bf_ctl_reg; + + bf_en_tmp.we_search_path_rst = 1; + bf_en_tmp.search_path_reset = 1; + audio_bf->bf_ctl_reg = bf_en_tmp; +} + +/** + * Valid voice sample stream generation enable bit. After sound direction searching is done, software can + * configure this bit to generate a stream of voice samples for voice recognition. + * 0x1: enable output of voice sample stream. + * 0x0: stop the voice samlpe stream output. + */ +void audio_bf_voc_enable(uint8_t enable_flag) +{ + struct audio_bf_ctl_t bf_en_tmp = audio_bf->bf_ctl_reg; + + bf_en_tmp.we_bf_stream_gen = 1; + bf_en_tmp.bf_stream_gen_en = enable_flag; + audio_bf->bf_ctl_reg = bf_en_tmp; +} + +void audio_bf_voc_reset(void) +{ + struct audio_bf_ctl_t bf_en_tmp = audio_bf->bf_ctl_reg; + + bf_en_tmp.we_voice_gen_path_rst = 1; + bf_en_tmp.voice_gen_path_reset = 1; + audio_bf->bf_ctl_reg = bf_en_tmp; +} + +/** + * Target direction select for valid voice output. When the source voice direaction searching + * is done, software can use this field to select one from 16 sound directions for the following + * voice recognition + * 0x0: select sound direction 0; 0x1: select sound direction 1; + * . . . . . . + * 0xF: select sound direction 15. +*/ +void audio_bf_voc_set_direction(enum en_bf_dir direction) +{ + struct audio_bf_ch_cfg_t ch_cfg = audio_bf->bf_ch_cfg_reg; + + ch_cfg.we_bf_sound_ch_en = 0; + ch_cfg.we_audio_gain = 0; + ch_cfg.we_data_src_mode = 0; + ch_cfg.we_bf_target_dir = 1; + ch_cfg.bf_target_dir = direction; + audio_bf->bf_ch_cfg_reg = ch_cfg; + + struct audio_bf_ctl_t bf_en_tmp = audio_bf->bf_ctl_reg; + + bf_en_tmp.we_update_voice_dir = 1; + bf_en_tmp.update_voice_dir = 1; + audio_bf->bf_ctl_reg = bf_en_tmp; +} + +/** + * I2S host beam-forming Filter FIR16 Coefficient Register + */ +void audio_bf_dir_set_prev_fir(uint16_t* fir_coef) +{ + uint8_t i = 0; + + for (i = 0; i < 9; i++) + { + audio_bf->bf_pre_fir0_coef[i] = (struct audio_bf_fir_coef_t){ + .fir_tap0 = fir_coef[i * 2], + .fir_tap1 = i == 8 ? 0 : fir_coef[i * 2 + 1]}; + } +} + +void audio_bf_dir_set_post_fir(uint16_t* fir_coef) +{ + uint8_t i = 0; + + for (i = 0; i < 9; i++) + { + audio_bf->bf_post_fir0_coef[i] = (struct audio_bf_fir_coef_t){ + .fir_tap0 = fir_coef[i * 2], + .fir_tap1 = i == 8 ? 0 : fir_coef[i * 2 + 1]}; + } +} + +void audio_bf_voc_set_prev_fir(uint16_t* fir_coef) +{ + uint8_t i = 0; + + for (i = 0; i < 9; i++) + { + audio_bf->bf_pre_fir1_coef[i] = (struct audio_bf_fir_coef_t){ + .fir_tap0 = fir_coef[i * 2], + .fir_tap1 = i == 8 ? 0 : fir_coef[i * 2 + 1]}; + } +} + +void audio_bf_voc_set_post_fir(uint16_t* fir_coef) +{ + uint8_t i = 0; + + for (i = 0; i < 9; i++) + { + audio_bf->bf_post_fir1_coef[i] = (struct audio_bf_fir_coef_t){ + .fir_tap0 = fir_coef[i * 2], + .fir_tap1 = i == 8 ? 0 : fir_coef[i * 2 + 1]}; + } +} + +void audio_bf_set_fft_shift_factor(uint8_t enable_flag, uint16_t shift_factor) +{ + audio_bf->bf_fft_cfg_reg = (struct audio_bf_fft_cfg_t){ + .fft_enable = enable_flag, + .fft_shift_factor = shift_factor}; + + struct audio_bf_ch_cfg_t ch_cfg = audio_bf->bf_ch_cfg_reg; + + ch_cfg.we_data_src_mode = 1; + ch_cfg.data_src_mode = enable_flag; + audio_bf->bf_ch_cfg_reg = ch_cfg; +} + +void audio_bf_dir_set_down_size(uint8_t dir_dwn_size) +{ + struct audio_bf_dwsz_cfg_t tmp = audio_bf->bf_dwsz_cfg_reg; + + tmp.dir_dwn_siz_rate = dir_dwn_size; + audio_bf->bf_dwsz_cfg_reg = tmp; +} + +void audio_bf_dir_set_interrupt_mask(uint8_t dir_int_mask) +{ + struct audio_bf_int_mask_t tmp = audio_bf->bf_int_mask_reg; + + tmp.dir_data_rdy_msk = dir_int_mask; + audio_bf->bf_int_mask_reg = tmp; +} + +void audio_bf_voc_set_down_size(uint8_t voc_dwn_size) +{ + struct audio_bf_dwsz_cfg_t tmp = audio_bf->bf_dwsz_cfg_reg; + + tmp.voc_dwn_siz_rate = voc_dwn_size; + audio_bf->bf_dwsz_cfg_reg = tmp; +} + +void audio_bf_voc_set_interrupt_mask(uint8_t voc_int_mask) +{ + struct audio_bf_int_mask_t tmp = audio_bf->bf_int_mask_reg; + + tmp.voc_buf_rdy_msk = voc_int_mask; + audio_bf->bf_int_mask_reg = tmp; +} + +void audio_bf_set_down_size(uint8_t dir_dwn_size, uint8_t voc_dwn_size) +{ + struct audio_bf_dwsz_cfg_t tmp = audio_bf->bf_dwsz_cfg_reg; + + tmp.dir_dwn_siz_rate = dir_dwn_size; + tmp.voc_dwn_siz_rate = voc_dwn_size; + audio_bf->bf_dwsz_cfg_reg = tmp; +} + +void audio_bf_set_interrupt_mask(uint8_t dir_int_mask, uint8_t voc_int_mask) +{ + audio_bf->bf_int_mask_reg = (struct audio_bf_int_mask_t){ + .dir_data_rdy_msk = dir_int_mask, + .voc_buf_rdy_msk = voc_int_mask}; +} + +void audio_bf_dir_clear_int_state(void) +{ + audio_bf->bf_int_stat_reg = (struct audio_bf_int_stat_t){ + .dir_search_data_rdy = 1}; +} + +void audio_bf_voc_clear_int_state(void) +{ + audio_bf->bf_int_stat_reg = (struct audio_bf_int_stat_t){ + .voc_buf_data_rdy = 1}; +} + +void audio_bf_voc_reset_saturation_counter(void) +{ + audio_bf->saturation_counter = 1 << 31; +} + +/* heigh 16 bit is counter, low 16 bit is total.*/ +uint32_t audio_bf_voc_get_saturation_counter(void) +{ + return audio_bf->saturation_counter; +} + +void audio_bf_voc_set_saturation_limit(uint16_t upper, uint16_t bottom) +{ + audio_bf->saturation_limits = (uint32_t)bottom << 16 | upper; +} + +/* heigh 16 bit is counter, low 16 bit is total.*/ +uint32_t audio_bf_voc_get_saturation_limit(void) +{ + return audio_bf->saturation_limits; +} + +static void print_fir(const char* member_name, volatile struct audio_bf_fir_coef_t* pfir) +{ + int i; + printf(" for(int i = 0; i < 9; i++){\n"); + for (i = 0; i < 9; i++) + { + struct audio_bf_fir_coef_t fir = pfir[i]; + + printf(" audio_bf->%s[%d] = (struct audio_bf_fir_coef_t){\n", member_name, i); + printf(" .fir_tap0 = 0x%x,\n", fir.fir_tap0); + printf(" .fir_tap1 = 0x%x\n", fir.fir_tap1); + printf(" };\n"); + } + printf(" }\n"); +} + +void audio_bf_print_setting(void) +{ + int i; + printf("void audio_bf_setting(void) {\n"); + struct audio_bf_ch_cfg_t bf_ch_cfg_reg = audio_bf->bf_ch_cfg_reg; + + printf(" audio_bf->bf_ch_cfg_reg = (struct audio_bf_ch_cfg_t){\n"); + printf(" .we_audio_gain = 1, .we_bf_target_dir = 1, .we_bf_sound_ch_en = 1,\n"); + printf(" .audio_gain = 0x%x, .bf_target_dir = %d, .bf_sound_ch_en = %d, .data_src_mode = %d\n", + bf_ch_cfg_reg.audio_gain, bf_ch_cfg_reg.bf_target_dir, bf_ch_cfg_reg.bf_sound_ch_en, bf_ch_cfg_reg.data_src_mode); + printf(" };\n"); + + struct audio_bf_ctl_t bf_ctl_reg = audio_bf->bf_ctl_reg; + + printf(" audio_bf->bf_ctl_reg = (struct audio_bf_ctl_t){\n"); + printf(" .we_bf_stream_gen = 1, .we_bf_dir_search_en = 1,\n"); + printf(" .bf_stream_gen_en = %d, .bf_dir_search_en = %d\n", + bf_ctl_reg.bf_stream_gen_en, bf_ctl_reg.bf_dir_search_en); + printf(" };\n"); + + printf(" for(int i = 0; i < 16; i++){\n"); + for (i = 0; i < 16; i++) + { + struct audio_bf_dir_bidx_t bidx0 = audio_bf->bf_dir_bidx[i][0]; + struct audio_bf_dir_bidx_t bidx1 = audio_bf->bf_dir_bidx[i][1]; + + printf(" audio_bf->bf_dir_bidx[%d][0] = (struct audio_bf_dir_bidx_t){\n", i); + printf(" .dir_rd_idx0 = 0x%x,\n", bidx0.dir_rd_idx0); + printf(" .dir_rd_idx1 = 0x%x,\n", bidx0.dir_rd_idx1); + printf(" .dir_rd_idx2 = 0x%x,\n", bidx0.dir_rd_idx2); + printf(" .dir_rd_idx3 = 0x%x\n", bidx0.dir_rd_idx3); + printf(" };\n"); + printf(" audio_bf->bf_dir_bidx[%d][1] = (struct audio_bf_dir_bidx_t){\n", i); + printf(" .dir_rd_idx0 = 0x%x,\n", bidx1.dir_rd_idx0); + printf(" .dir_rd_idx1 = 0x%x,\n", bidx1.dir_rd_idx1); + printf(" .dir_rd_idx2 = 0x%x,\n", bidx1.dir_rd_idx2); + printf(" .dir_rd_idx3 = 0x%x\n", bidx1.dir_rd_idx3); + printf(" };\n"); + } + printf(" }\n"); + + print_fir("bf_pre_fir0_coef", audio_bf->bf_pre_fir0_coef); + print_fir("bf_post_fir0_coef", audio_bf->bf_post_fir0_coef); + print_fir("bf_pre_fir1_coef", audio_bf->bf_pre_fir1_coef); + print_fir("bf_post_fir1_coef", audio_bf->bf_post_fir1_coef); + + struct audio_bf_dwsz_cfg_t bf_dwsz_cfg_reg = audio_bf->bf_dwsz_cfg_reg; + + printf(" audio_bf->bf_dwsz_cfg_reg = (struct audio_bf_dwsz_cfg_t){\n"); + printf(" .dir_dwn_siz_rate = %d, .voc_dwn_siz_rate = %d\n", + bf_dwsz_cfg_reg.dir_dwn_siz_rate, bf_dwsz_cfg_reg.voc_dwn_siz_rate); + printf(" };\n"); + + struct audio_bf_fft_cfg_t bf_fft_cfg_reg = audio_bf->bf_fft_cfg_reg; + + printf(" audio_bf->bf_fft_cfg_reg = (struct audio_bf_fft_cfg_t){\n"); + printf(" .fft_enable = %d, .fft_shift_factor = 0x%x\n", + bf_fft_cfg_reg.fft_enable, bf_fft_cfg_reg.fft_shift_factor); + printf(" };\n"); + + struct audio_bf_int_mask_t bf_int_mask_reg = audio_bf->bf_int_mask_reg; + + printf(" audio_bf->bf_int_mask_reg = (struct audio_bf_int_mask_t){\n"); + printf(" .dir_data_rdy_msk = %d, .voc_buf_rdy_msk = %d\n", + bf_int_mask_reg.dir_data_rdy_msk, bf_int_mask_reg.voc_buf_rdy_msk); + printf(" };\n"); + + printf("}\n"); +} diff --git a/lib/drivers/clint.c b/lib/drivers/clint.c new file mode 100644 index 0000000..9e4db0a --- /dev/null +++ b/lib/drivers/clint.c @@ -0,0 +1,276 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include "env/encoding.h" +#include "clint.h" +#include "sysctl.h" + +struct clint_timer_instance_t +{ + uint64_t interval; + uint64_t cycles; + uint64_t single_shot; + clint_timer_callback_t callback; + void* ctx; +}; + +struct clint_ipi_instance_t +{ + clint_ipi_callback_t callback; + void* ctx; +}; + +volatile struct clint_t* const clint = (volatile struct clint_t*)CLINT_BASE_ADDR; +static struct clint_timer_instance_t clint_timer_instance[CLINT_NUM_HARTS]; +static struct clint_ipi_instance_t clint_ipi_instance[CLINT_NUM_HARTS]; + +uint64_t clint_get_time(void) +{ + /* No difference on harts */ + return clint->mtime; +} + +int clint_timer_init(void) +{ + /* Read hart id */ + unsigned long hart_id = read_csr(mhartid); + /* Clear the Machine-Timer bit in MIE */ + clear_csr(mie, MIP_MTIP); + /* Fill hart's instance with original data */ + + /* clang-format off */ + clint_timer_instance[hart_id] = (const struct clint_timer_instance_t) + { + .interval = 0, + .cycles = 0, + .single_shot = 0, + .callback = NULL, + .ctx = NULL, + }; + /* clang-format on */ + + return 0; +} + +int clint_timer_stop(void) +{ + /* Clear the Machine-Timer bit in MIE */ + clear_csr(mie, MIP_MTIP); + return 0; +} + +uint64_t clint_timer_get_freq(void) +{ + /* The clock is divided by CLINT_CLOCK_DIV */ + return sysctl_get_freq() / CLINT_CLOCK_DIV; +} + +int clint_timer_start(uint64_t interval, int single_shot) +{ + /* Read hart id */ + unsigned long hart_id = read_csr(mhartid); + /* Set timer interval */ + if (clint_timer_set_interval(interval) != 0) + return -1; + /* Set timer single shot */ + if (clint_timer_set_single_shot(single_shot) != 0) + return -1; + /* Check settings to prevent interval is 0 */ + if (clint_timer_instance[hart_id].interval == 0) + return -1; + /* Check settings to prevent cycles is 0 */ + if (clint_timer_instance[hart_id].cycles == 0) + return -1; + /* Add cycle interval to mtimecmp */ + uint64_t now = clint->mtime; + uint64_t then = now + clint_timer_instance[hart_id].cycles; + /* Set mtimecmp by hart id */ + clint->mtimecmp[hart_id] = then; + /* Enable interrupts in general */ + set_csr(mstatus, MSTATUS_MIE); + /* Enable the Machine-Timer bit in MIE */ + set_csr(mie, MIP_MTIP); + return 0; +} + +uint64_t clint_timer_get_interval(void) +{ + /* Read hart id */ + unsigned long hart_id = read_csr(mhartid); + return clint_timer_instance[hart_id].interval; +} + +int clint_timer_set_interval(uint64_t interval) +{ + /* Read hart id */ + unsigned long hart_id = read_csr(mhartid); + /* Check parameter */ + if (interval == 0) + return -1; + + /* Assign user interval with Millisecond(ms) */ + clint_timer_instance[hart_id].interval = interval; + /* Convert interval to cycles */ + clint_timer_instance[hart_id].cycles = interval * clint_timer_get_freq() / 1000ULL; + return 0; +} + +int clint_timer_get_single_shot(void) +{ + /* Read hart id */ + unsigned long hart_id = read_csr(mhartid); + /* Get single shot mode by hart id */ + return clint_timer_instance[hart_id].single_shot; +} + +int clint_timer_set_single_shot(int single_shot) +{ + /* Read hart id */ + unsigned long hart_id = read_csr(mhartid); + /* Set single shot mode by hart id */ + clint_timer_instance[hart_id].single_shot = single_shot; + return 0; +} + +int clint_timer_register(clint_timer_callback_t callback, void* ctx) +{ + /* Read hart id */ + unsigned long hart_id = read_csr(mhartid); + /* Set user callback function */ + clint_timer_instance[hart_id].callback = callback; + /* Assign user context */ + clint_timer_instance[hart_id].ctx = ctx; + return 0; +} + +int clint_timer_deregister(void) +{ + /* Just assign NULL to user callback function and context */ + return clint_timer_register(NULL, NULL); +} + +int clint_ipi_init(void) +{ + /* Read hart id */ + unsigned long hart_id = read_csr(mhartid); + /* Clear the Machine-Software bit in MIE */ + clear_csr(mie, MIP_MSIP); + /* Fill hart's instance with original data */ + /* clang-format off */ + clint_ipi_instance[hart_id] = (const struct clint_ipi_instance_t){ + .callback = NULL, + .ctx = NULL, + }; + /* clang-format on */ + + return 0; +} + +int clint_ipi_enable(void) +{ + /* Enable interrupts in general */ + set_csr(mstatus, MSTATUS_MIE); + /* Set the Machine-Software bit in MIE */ + set_csr(mie, MIP_MSIP); + return 0; +} + +int clint_ipi_disable(void) +{ + /* Clear the Machine-Software bit in MIE */ + clear_csr(mie, MIP_MSIP); + return 0; +} + +int clint_ipi_send(size_t hart_id) +{ + if (hart_id >= CLINT_NUM_HARTS) + return -1; + clint->msip[hart_id].msip = 1; + return 0; +} + +int clint_ipi_clear(size_t hart_id) +{ + if (hart_id >= CLINT_NUM_HARTS) + return -1; + if (clint->msip[hart_id].msip) + { + clint->msip[hart_id].msip = 0; + return 1; + } + return 0; +} + +int clint_ipi_register(clint_ipi_callback_t callback, void* ctx) +{ + /* Read hart id */ + unsigned long hart_id = read_csr(mhartid); + /* Set user callback function */ + clint_ipi_instance[hart_id].callback = callback; + /* Assign user context */ + clint_ipi_instance[hart_id].ctx = ctx; + return 0; +} + +int clint_ipi_deregister(void) +{ + /* Just assign NULL to user callback function and context */ + return clint_ipi_register(NULL, NULL); +} + +uintptr_t handle_irq_m_timer(uintptr_t cause, uintptr_t epc, uintptr_t regs[32]) +{ + /* Read hart id */ + uint64_t hart_id = read_csr(mhartid); + uint64_t ie_flag = read_csr(mie); + + clear_csr(mie, MIP_MTIP | MIP_MSIP); + set_csr(mstatus, MSTATUS_MIE); + if (clint_timer_instance[hart_id].callback != NULL) + clint_timer_instance[hart_id].callback( + clint_timer_instance[hart_id].ctx); + clear_csr(mstatus, MSTATUS_MIE); + set_csr(mstatus, MSTATUS_MPIE | MSTATUS_MPP); + write_csr(mie, ie_flag); + /* If not single shot and cycle interval is not 0, repeat this timer */ + if (!clint_timer_instance[hart_id].single_shot && clint_timer_instance[hart_id].cycles != 0) + { + /* Set mtimecmp by hart id */ + clint->mtimecmp[hart_id] += clint_timer_instance[hart_id].cycles; + } + else + clear_csr(mie, MIP_MTIP); + return epc; +} + +uintptr_t handle_irq_m_soft(uintptr_t cause, uintptr_t epc, uintptr_t regs[32]) +{ + /* Read hart id */ + uint64_t hart_id = read_csr(mhartid); + /* Clear the Machine-Software bit in MIE to prevent call again */ + clear_csr(mie, MIP_MSIP); + set_csr(mstatus, MSTATUS_MIE); + /* Clear ipi flag */ + clint_ipi_clear(hart_id); + if (clint_ipi_instance[hart_id].callback != NULL) + clint_ipi_instance[hart_id].callback(clint_ipi_instance[hart_id].ctx); + clear_csr(mstatus, MSTATUS_MIE); + set_csr(mstatus, MSTATUS_MPIE | MSTATUS_MPP); + set_csr(mie, MIP_MSIP); + return epc; +} + diff --git a/lib/drivers/common.c b/lib/drivers/common.c new file mode 100644 index 0000000..bc7bce7 --- /dev/null +++ b/lib/drivers/common.c @@ -0,0 +1,55 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include "env/encoding.h" +#include "common.h" + +void set_bit(volatile uint32_t* bits, uint32_t mask, uint32_t value) +{ + uint32_t org = (*bits) & ~mask; + *bits = org | (value & mask); +} + +void set_bit_offset(volatile uint32_t* bits, uint32_t mask, size_t offset, uint32_t value) +{ + set_bit(bits, mask << offset, value << offset); +} + +void set_gpio_bit(volatile uint32_t* bits, size_t offset, uint32_t value) +{ + set_bit_offset(bits, 1, offset, value); +} + +uint32_t get_bit(volatile uint32_t* bits, uint32_t mask, size_t offset) +{ + return ((*bits) & (mask << offset)) >> offset; +} + +uint32_t get_gpio_bit(volatile uint32_t* bits, size_t offset) +{ + return get_bit(bits, 1, offset); +} + +void machine_irq_enable(void) +{ + set_csr(mie, MIP_MEIP); + set_csr(mstatus, MSTATUS_MIE); +} + +void machine_irq_disable(void) +{ + clear_csr(mie, MIP_MEIP); + clear_csr(mstatus, MSTATUS_MIE); +} diff --git a/lib/drivers/dmac.c b/lib/drivers/dmac.c new file mode 100644 index 0000000..e454205 --- /dev/null +++ b/lib/drivers/dmac.c @@ -0,0 +1,716 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include "dmac.h" +#include "sysctl.h" +#include "fpioa.h" +#include "common.h" +#include "plic.h" +#include "stdlib.h" + +volatile struct dmac_t *const dmac = (struct dmac_t *)DMAC_BASE_ADDR; + +static int is_memory(uintptr_t address) +{ + enum { mem_len = 6 * 1024 * 1024 }; + return ((address >= 0x80000000) && (address < 0x80000000 + mem_len)) || ((address >= 0x40000000) && (address < 0x40000000 + mem_len)) || (address == 0x50450040); +} + +uint64_t dmac_read_id(void) +{ + return dmac->id; +} + +uint64_t dmac_read_version(void) +{ + return dmac->compver; +} + +uint64_t dmac_read_channel_id(dmac_channel_number channel_num) +{ + return dmac->channel[channel_num].axi_id; +} + +void dmac_enable(void) +{ + union dmac_cfg_u dmac_cfg; + + dmac_cfg.data = readq(&dmac->cfg); + dmac_cfg.cfg.dmac_en = 1; + dmac_cfg.cfg.int_en = 1; + writeq(dmac_cfg.data, &dmac->cfg); +} + +void dmac_disable(void) +{ + union dmac_cfg_u dmac_cfg; + + dmac_cfg.data = readq(&dmac->cfg); + dmac_cfg.cfg.dmac_en = 0; + dmac_cfg.cfg.int_en = 0; + writeq(dmac_cfg.data, &dmac->cfg); +} + +void src_transaction_complete_int_enable(dmac_channel_number channel_num) +{ + union dmac_ch_intstatus_enable_u ch_intstat; + + ch_intstat.data = readq(&dmac->channel[channel_num].intstatus_en); + ch_intstat.ch_intstatus_enable.enable_src_transcomp_intstat = 1; + + writeq(ch_intstat.data, &dmac->channel[channel_num].intstatus_en); +} + +void dmac_channel_enable(dmac_channel_number channel_num) +{ + union dmac_chen_u chen; + + chen.data = readq(&dmac->chen); + + switch (channel_num) { + case DMAC_CHANNEL0: + chen.dmac_chen.ch1_en = 1; + chen.dmac_chen.ch1_en_we = 1; + break; + case DMAC_CHANNEL1: + chen.dmac_chen.ch2_en = 1; + chen.dmac_chen.ch2_en_we = 1; + break; + case DMAC_CHANNEL2: + chen.dmac_chen.ch3_en = 1; + chen.dmac_chen.ch3_en_we = 1; + break; + case DMAC_CHANNEL3: + chen.dmac_chen.ch4_en = 1; + chen.dmac_chen.ch4_en_we = 1; + break; + case DMAC_CHANNEL4: + chen.dmac_chen.ch5_en = 1; + chen.dmac_chen.ch5_en_we = 1; + break; + case DMAC_CHANNEL5: + chen.dmac_chen.ch6_en = 1; + chen.dmac_chen.ch6_en_we = 1; + break; + default: + break; + } + + writeq(chen.data, &dmac->chen); +} + +void dmac_channel_disable(dmac_channel_number channel_num) +{ + union dmac_chen_u chen; + + chen.data = readq(&dmac->chen); + + switch (channel_num) { + case DMAC_CHANNEL0: + chen.dmac_chen.ch1_en = 0; + chen.dmac_chen.ch1_en_we = 0; + break; + case DMAC_CHANNEL1: + chen.dmac_chen.ch2_en = 0; + chen.dmac_chen.ch2_en_we = 0; + break; + case DMAC_CHANNEL2: + chen.dmac_chen.ch3_en = 0; + chen.dmac_chen.ch3_en_we = 0; + break; + case DMAC_CHANNEL3: + chen.dmac_chen.ch4_en = 0; + chen.dmac_chen.ch4_en_we = 0; + break; + case DMAC_CHANNEL4: + chen.dmac_chen.ch5_en = 0; + chen.dmac_chen.ch5_en_we = 0; + break; + case DMAC_CHANNEL5: + chen.dmac_chen.ch6_en = 0; + chen.dmac_chen.ch6_en_we = 0; + break; + default: + break; + } + + writeq(chen.data, &dmac->chen); +} + +int32_t dmac_check_channel_busy(dmac_channel_number channel_num) +{ + int32_t ret = 0; + union dmac_chen_u chen_u; + + chen_u.data = readq(&dmac->chen); + switch (channel_num) { + case DMAC_CHANNEL0: + if (chen_u.dmac_chen.ch1_en == 1) + ret = 1; + break; + case DMAC_CHANNEL1: + if (chen_u.dmac_chen.ch2_en == 1) + ret = 1; + break; + case DMAC_CHANNEL2: + if (chen_u.dmac_chen.ch3_en == 1) + ret = 1; + break; + case DMAC_CHANNEL3: + if (chen_u.dmac_chen.ch4_en == 1) + ret = 1; + break; + case DMAC_CHANNEL4: + if (chen_u.dmac_chen.ch5_en == 1) + ret = 1; + break; + case DMAC_CHANNEL5: + if (chen_u.dmac_chen.ch6_en == 1) + ret = 1; + break; + default: + break; + } + + writeq(chen_u.data, &dmac->chen); + + return ret; +} + +int32_t dmac_set_list_master_select(dmac_channel_number channel_num, + dmac_src_dst_select sd_sel, enum dmac_master_number mst_num) +{ + int32_t ret = 0; + uint64_t tmp = 0; + union dmac_ch_ctl_u ctl; + + ctl.data = readq(&dmac->channel[channel_num].ctl); + ret = dmac_check_channel_busy(channel_num); + if (ret == 0) { + if (sd_sel == DMAC_SRC || sd_sel == DMAC_SRC_DST) + ctl.ch_ctl.sms = mst_num; + + if (sd_sel == DMAC_DST || sd_sel == DMAC_SRC_DST) + ctl.ch_ctl.dms = mst_num; + tmp |= *(uint64_t *)&dmac->channel[channel_num].ctl; + writeq(ctl.data, &dmac->channel[channel_num].ctl); + } + + return ret; +} + +void dmac_enable_common_interrupt_status(void) +{ + union dmac_commonreg_intstatus_enable_u intstatus; + + intstatus.data = readq(&dmac->com_intstatus_en); + intstatus.intstatus_enable.enable_slvif_dec_err_intstat = 1; + intstatus.intstatus_enable.enable_slvif_wr2ro_err_intstat = 1; + intstatus.intstatus_enable.enable_slvif_rd2wo_err_intstat = 1; + intstatus.intstatus_enable.enable_slvif_wronhold_err_intstat = 1; + intstatus.intstatus_enable.enable_slvif_undefinedreg_dec_err_intstat = 1; + + writeq(intstatus.data, &dmac->com_intstatus_en); +} + +void dmac_enable_common_interrupt_signal(void) +{ + union dmac_commonreg_intsignal_enable_u intsignal; + + intsignal.data = readq(&dmac->com_intsignal_en); + intsignal.intsignal_enable.enable_slvif_dec_err_intsignal = 1; + intsignal.intsignal_enable.enable_slvif_wr2ro_err_intsignal = 1; + intsignal.intsignal_enable.enable_slvif_rd2wo_err_intsignal = 1; + intsignal.intsignal_enable.enable_slvif_wronhold_err_intsignal = 1; + intsignal.intsignal_enable.enable_slvif_undefinedreg_dec_err_intsignal = 1; + + writeq(intsignal.data, &dmac->com_intsignal_en); +} + +void dmac_enable_channel_interrupt_status(dmac_channel_number channel_num) +{ + writeq(0xffffffff, &dmac->channel[channel_num].intclear); + writeq(0xffffffff, &dmac->channel[channel_num].intstatus_en); +} + +void dmac_disable_channel_interrupt_status(dmac_channel_number channel_num) +{ + writeq(0, &dmac->channel[channel_num].intstatus_en); +} + +void dmac_enable_channel_interrupt_signal(dmac_channel_number channel_num, + enum dmca_common_int which_interrupt) +{ + +} + +void dmac_chanel_interrupt_clear(dmac_channel_number channel_num) +{ + writeq(0xffffffff, &dmac->channel[channel_num].intclear); +} + +int dmac_set_channel_config(dmac_channel_number channel_num, + struct dmac_channel_config_t *cfg_param) +{ + union dmac_ch_ctl_u ctl; + union dmac_ch_cfg_u cfg; + union dmac_ch_llp_u ch_llp; + + if (cfg_param->ctl_sms > DMAC_MASTER2) + return -1; + if (cfg_param->ctl_dms > DMAC_MASTER2) + return -1; + if (cfg_param->ctl_src_msize > DMAC_MSIZE_256) + return -1; + if (cfg_param->ctl_drc_msize > DMAC_MSIZE_256) + return -1; + + /** + * cfg register must configure before ts_block and + * sar dar register + */ + cfg.data = readq(&dmac->channel[channel_num].cfg); + + cfg.ch_cfg.hs_sel_src = cfg_param->cfg_hs_sel_src; + cfg.ch_cfg.hs_sel_dst = cfg_param->cfg_hs_sel_dst; + cfg.ch_cfg.src_hwhs_pol = cfg_param->cfg_src_hs_pol; + cfg.ch_cfg.dst_hwhs_pol = cfg_param->cfg_dst_hs_pol; + cfg.ch_cfg.src_per = cfg_param->cfg_src_per; + cfg.ch_cfg.dst_per = cfg_param->cfg_dst_per; + cfg.ch_cfg.ch_prior = cfg_param->cfg_ch_prior; + cfg.ch_cfg.tt_fc = cfg_param->ctl_tt_fc; + + cfg.ch_cfg.src_multblk_type = cfg_param->cfg_src_multblk_type; + cfg.ch_cfg.dst_multblk_type = cfg_param->cfg_dst_multblk_type; + + writeq(cfg.data, &dmac->channel[channel_num].cfg); + + ctl.data = readq(&dmac->channel[channel_num].ctl); + ctl.ch_ctl.sms = cfg_param->ctl_sms; + ctl.ch_ctl.dms = cfg_param->ctl_dms; + /* master select */ + ctl.ch_ctl.sinc = cfg_param->ctl_sinc; + ctl.ch_ctl.dinc = cfg_param->ctl_dinc; + /* address incrememt */ + ctl.ch_ctl.src_tr_width = cfg_param->ctl_src_tr_width; + ctl.ch_ctl.dst_tr_width = cfg_param->ctl_dst_tr_width; + /* transfer width */ + ctl.ch_ctl.src_msize = cfg_param->ctl_src_msize; + ctl.ch_ctl.dst_msize = cfg_param->ctl_drc_msize; + /* Burst transaction length */ + ctl.ch_ctl.ioc_blktfr = cfg_param->ctl_ioc_blktfr; + /* interrupt on completion of block transfer */ + /* 0x1 enable BLOCK_TFR_DONE_IntStat field */ + + writeq(cfg_param->ctl_block_ts, &dmac->channel[channel_num].block_ts); + /* the number of (blcok_ts +1) data of width SRC_TR_WIDTF to be */ + /* transferred in a dma block transfer */ + + dmac->channel[channel_num].sar = cfg_param->sar; + dmac->channel[channel_num].dar = cfg_param->dar; + + ch_llp.data = readq(&dmac->channel[channel_num].llp); + ch_llp.llp.loc = cfg_param->llp_loc; + ch_llp.llp.lms = cfg_param->llp_lms; + writeq(ch_llp.data, &dmac->channel[channel_num].llp); + writeq(ctl.data, &dmac->channel[channel_num].ctl); + readq(&dmac->channel[channel_num].swhssrc); + + return 0; +} + +int dmac_set_channel_param(dmac_channel_number channel_num, + void *src, void *dest, enum dmac_address_increment src_inc, enum dmac_address_increment dest_inc, + enum dmac_burst_trans_length dmac_msize, + enum dmac_transfer_width dmac_trans_width, + uint32_t blockSize) +{ + union dmac_ch_ctl_u ctl; + union dmac_ch_cfg_u cfg_u; + + int mem_type_src = is_memory((uintptr_t)src), mem_type_dest = is_memory((uintptr_t)dest); + enum dmac_transfer_flow flow_control; + if (mem_type_src == 0 && mem_type_dest == 0) + { + flow_control = DMAC_PRF2PRF_DMA; + }else if (mem_type_src == 1 && mem_type_dest == 0) + flow_control = DMAC_MEM2PRF_DMA; + else if (mem_type_src == 0 && mem_type_dest == 1) + flow_control = DMAC_PRF2MEM_DMA; + else if (mem_type_src == 1 && mem_type_dest == 1) + flow_control = DMAC_MEM2MEM_DMA; + + /** + * cfg register must configure before ts_block and + * sar dar register + */ + cfg_u.data = readq(&dmac->channel[channel_num].cfg); + + cfg_u.ch_cfg.tt_fc = flow_control; + cfg_u.ch_cfg.hs_sel_src = mem_type_src ? DMAC_HS_SOFTWARE : DMAC_HS_HARDWARE; + cfg_u.ch_cfg.hs_sel_dst = mem_type_dest ? DMAC_HS_SOFTWARE : DMAC_HS_HARDWARE; + cfg_u.ch_cfg.src_per = channel_num; + cfg_u.ch_cfg.dst_per = channel_num; + cfg_u.ch_cfg.src_multblk_type = 0; + cfg_u.ch_cfg.dst_multblk_type = 0; + + writeq(cfg_u.data, &dmac->channel[channel_num].cfg); + + dmac->channel[channel_num].sar = (uint64_t)src; + dmac->channel[channel_num].dar = (uint64_t)dest; + + ctl.data = readq(&dmac->channel[channel_num].ctl); + ctl.ch_ctl.sms = DMAC_MASTER1; + ctl.ch_ctl.dms = DMAC_MASTER2; + /* master select */ + ctl.ch_ctl.sinc = src_inc; + ctl.ch_ctl.dinc = dest_inc; + /* address incrememt */ + ctl.ch_ctl.src_tr_width = dmac_trans_width; + ctl.ch_ctl.dst_tr_width = dmac_trans_width; + /* transfer width */ + ctl.ch_ctl.src_msize = dmac_msize; + ctl.ch_ctl.dst_msize = dmac_msize; + + writeq(ctl.data, &dmac->channel[channel_num].ctl); + + writeq(blockSize - 1, &dmac->channel[channel_num].block_ts); + /*the number of (blcok_ts +1) data of width SRC_TR_WIDTF to be */ + /* transferred in a dma block transfer */ + return 0; +} + +int dmac_get_channel_config(dmac_channel_number channel_num, + struct dmac_channel_config_t *cfg_param) +{ + union dmac_ch_ctl_u ctl; + union dmac_ch_cfg_u cfg; + union dmac_ch_llp_u ch_llp; + + if (cfg_param == 0) + return -1; + if (channel_num < DMAC_CHANNEL0 || + channel_num > DMAC_CHANNEL3) + return -1; + + ctl.data = readq(&dmac->channel[channel_num].ctl); + + cfg_param->ctl_sms = ctl.ch_ctl.sms; + cfg_param->ctl_dms = ctl.ch_ctl.dms; + cfg_param->ctl_sinc = ctl.ch_ctl.sinc; + cfg_param->ctl_dinc = ctl.ch_ctl.dinc; + cfg_param->ctl_src_tr_width = ctl.ch_ctl.src_tr_width; + cfg_param->ctl_dst_tr_width = ctl.ch_ctl.dst_tr_width; + cfg_param->ctl_src_msize = ctl.ch_ctl.src_msize; + cfg_param->ctl_drc_msize = ctl.ch_ctl.dst_msize; + cfg_param->ctl_ioc_blktfr = ctl.ch_ctl.ioc_blktfr; + + cfg.data = readq(&dmac->channel[channel_num].cfg); + cfg_param->cfg_hs_sel_src = cfg.ch_cfg.hs_sel_src; + cfg_param->cfg_hs_sel_dst = cfg.ch_cfg.hs_sel_dst; + cfg_param->cfg_src_hs_pol = cfg.ch_cfg.src_hwhs_pol; + cfg_param->cfg_dst_hs_pol = cfg.ch_cfg.dst_hwhs_pol; + cfg_param->cfg_src_per = cfg.ch_cfg.src_per; + cfg_param->cfg_dst_per = cfg.ch_cfg.dst_per; + cfg_param->cfg_ch_prior = cfg.ch_cfg.ch_prior; + cfg_param->cfg_src_multblk_type = cfg.ch_cfg.src_multblk_type; + cfg_param->cfg_dst_multblk_type = cfg.ch_cfg.dst_multblk_type; + + cfg_param->sar = dmac->channel[channel_num].sar; + cfg_param->dar = dmac->channel[channel_num].dar; + + ch_llp.data = readq(&dmac->channel[channel_num].llp); + cfg_param->llp_loc = ch_llp.llp.loc; + cfg_param->llp_lms = ch_llp.llp.lms; + + cfg_param->ctl_block_ts = readq(&dmac->channel[channel_num].block_ts); + + return 0; +} + +void dmac_set_address(dmac_channel_number channel_num, uint64_t src_addr, + uint64_t dst_addr) +{ + writeq(src_addr, &dmac->channel[channel_num].sar); + writeq(dst_addr, &dmac->channel[channel_num].dar); +} + +void dmac_set_block_ts(dmac_channel_number channel_num, + uint32_t block_size) +{ + uint32_t block_ts; + + block_ts = block_size & 0x3fffff; + writeq(block_ts, &dmac->channel[channel_num].block_ts); +} + +void dmac_source_control(dmac_channel_number channel_num, + enum dmac_master_number master_select, + enum dmac_address_increment address_mode, + enum dmac_transfer_width tr_width, + enum dmac_burst_trans_length burst_length) +{ + union dmac_ch_ctl_u ctl_u; + + ctl_u.data = readq(&dmac->channel[channel_num].ctl); + ctl_u.ch_ctl.sms = master_select; + ctl_u.ch_ctl.sinc = address_mode; + ctl_u.ch_ctl.src_tr_width = tr_width; + ctl_u.ch_ctl.src_msize = burst_length; + + writeq(ctl_u.data, &dmac->channel[channel_num].ctl); +} + +void dmac_master_control(dmac_channel_number channel_num, + enum dmac_master_number master_select, + enum dmac_address_increment address_mode, + enum dmac_transfer_width tr_width, + enum dmac_burst_trans_length burst_length) +{ + union dmac_ch_ctl_u ctl_u; + + ctl_u.data = readq(&dmac->channel[channel_num].ctl); + ctl_u.ch_ctl.dms = master_select; + ctl_u.ch_ctl.dinc = address_mode; + ctl_u.ch_ctl.dst_tr_width = tr_width; + ctl_u.ch_ctl.dst_msize = burst_length; + + writeq(ctl_u.data, &dmac->channel[channel_num].ctl); +} + +void dmac_set_source_transfer_control(dmac_channel_number channel_num, + enum dmac_multiblk_transfer_type transfer_type, + enum dmac_sw_hw_hs_select handshak_select) +{ + union dmac_ch_cfg_u cfg_u; + + cfg_u.data = readq(&dmac->channel[channel_num].cfg); + cfg_u.ch_cfg.src_multblk_type = transfer_type; + cfg_u.ch_cfg.hs_sel_src = handshak_select; + + writeq(cfg_u.data, &dmac->channel[channel_num].cfg); +} + +void dmac_set_destination_transfer_control(dmac_channel_number channel_num, + enum dmac_multiblk_transfer_type transfer_type, + enum dmac_sw_hw_hs_select handshak_select) +{ + union dmac_ch_cfg_u cfg_u; + + cfg_u.data = readq(&dmac->channel[channel_num].cfg); + cfg_u.ch_cfg.dst_multblk_type = transfer_type; + cfg_u.ch_cfg.hs_sel_dst = handshak_select; + + writeq(cfg_u.data, &dmac->channel[channel_num].cfg); +} + +void dmac_set_flow_control(dmac_channel_number channel_num, + enum dmac_transfer_flow flow_control) +{ + union dmac_ch_cfg_u cfg_u; + + cfg_u.data = readq(&dmac->channel[channel_num].cfg); + cfg_u.ch_cfg.tt_fc = flow_control; + + writeq(cfg_u.data, &dmac->channel[channel_num].cfg); +} + +void dmac_set_linked_list_addr_point(dmac_channel_number channel_num, + uint64_t *addr) +{ + union dmac_ch_llp_u llp_u; + + llp_u.data = readq(&dmac->channel[channel_num].llp); + /* Cast pointer to uint64_t */ + llp_u.llp.loc = (uint64_t)addr; + writeq(llp_u.data, &dmac->channel[channel_num].llp); +} + +void dmac_init(void) +{ + uint64_t tmp; + union dmac_commonreg_intclear_u intclear; + union dmac_cfg_u dmac_cfg; + union dmac_reset_u dmac_reset; + + sysctl_clock_enable(SYSCTL_CLOCK_DMA); + + dmac_reset.data = readq(&dmac->reset); + dmac_reset.reset.rst = 1; + writeq(dmac_reset.data, &dmac->reset); + while (dmac_reset.reset.rst) + dmac_reset.data = readq(&dmac->reset); + + /*reset dmac */ + + intclear.data = readq(&dmac->com_intclear); + intclear.com_intclear.cear_slvif_dec_err_intstat = 1; + intclear.com_intclear.clear_slvif_wr2ro_err_intstat = 1; + intclear.com_intclear.clear_slvif_rd2wo_err_intstat = 1; + intclear.com_intclear.clear_slvif_wronhold_err_intstat = 1; + intclear.com_intclear.clear_slvif_undefinedreg_dec_err_intstat = 1; + writeq(intclear.data, &dmac->com_intclear); + /* clear common register interrupt */ + + dmac_cfg.data = readq(&dmac->cfg); + dmac_cfg.cfg.dmac_en = 0; + dmac_cfg.cfg.int_en = 0; + writeq(dmac_cfg.data, &dmac->cfg); + /* disable dmac and disable interrupt */ + + while (readq(&dmac->cfg)) + ; + tmp = readq(&dmac->chen); + tmp &= ~0xf; + writeq(tmp, &dmac->chen); + /* disable all channel before configure */ +} + +void list_add(struct list_head_t *new, struct list_head_t *prev, + struct list_head_t *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +void list_add_tail(struct list_head_t *new, struct list_head_t *head) +{ + list_add(new, head->prev, head); +} + +void INIT_LIST_HEAD(struct list_head_t *list) +{ + list->next = list; + list->prev = list; +} + +void dmac_link_list_item(dmac_channel_number channel_num, + uint8_t LLI_row_num, int8_t LLI_last_row, + struct dmac_lli_item_t *lli_item, + struct dmac_channel_config_t *cfg_param) +{ + union dmac_ch_ctl_u ctl; + union dmac_ch_llp_u llp_u; + + lli_item[LLI_row_num].sar = cfg_param->sar; + lli_item[LLI_row_num].dar = cfg_param->dar; + + ctl.data = readq(&dmac->channel[channel_num].ctl); + ctl.ch_ctl.sms = cfg_param->ctl_sms; + ctl.ch_ctl.dms = cfg_param->ctl_dms; + ctl.ch_ctl.sinc = cfg_param->ctl_sinc; + ctl.ch_ctl.dinc = cfg_param->ctl_dinc; + ctl.ch_ctl.src_tr_width = cfg_param->ctl_src_tr_width; + ctl.ch_ctl.dst_tr_width = cfg_param->ctl_dst_tr_width; + ctl.ch_ctl.src_msize = cfg_param->ctl_src_msize; + ctl.ch_ctl.dst_msize = cfg_param->ctl_drc_msize; + ctl.ch_ctl.src_stat_en = cfg_param->ctl_src_stat_en; + ctl.ch_ctl.dst_stat_en = cfg_param->ctl_dst_stat_en; + + if (LLI_last_row != LAST_ROW) { + ctl.ch_ctl.shadowreg_or_lli_valid = 1; + ctl.ch_ctl.shadowreg_or_lli_last = 0; + } else { + ctl.ch_ctl.shadowreg_or_lli_valid = 1; + ctl.ch_ctl.shadowreg_or_lli_last = 1; + } + + lli_item[LLI_row_num].ctl = ctl.data; + + lli_item[LLI_row_num].ch_block_ts = cfg_param->ctl_block_ts; + lli_item[LLI_row_num].sstat = 0; + lli_item[LLI_row_num].dstat = 0; + + llp_u.data = readq(&dmac->channel[channel_num].llp); + + if (LLI_last_row != LAST_ROW) + llp_u.llp.loc = ((uint64_t)&lli_item[LLI_row_num + 1]) >> 6; + else + llp_u.llp.loc = 0; + + lli_item[LLI_row_num].llp = llp_u.data; +} + +void dmac_update_shandow_register(dmac_channel_number channel_num, + int8_t last_block, struct dmac_channel_config_t *cfg_param) +{ + union dmac_ch_ctl_u ctl_u; + + do { + ctl_u.data = readq(&dmac->channel[channel_num].ctl); + } while (ctl_u.ch_ctl.shadowreg_or_lli_valid); + + writeq(cfg_param->sar, &dmac->channel[channel_num].sar); + writeq(cfg_param->dar, &dmac->channel[channel_num].dar); + writeq(cfg_param->ctl_block_ts, &dmac->channel[channel_num].block_ts); + + ctl_u.ch_ctl.sms = cfg_param->ctl_sms; + ctl_u.ch_ctl.dms = cfg_param->ctl_dms; + ctl_u.ch_ctl.sinc = cfg_param->ctl_sinc; + ctl_u.ch_ctl.dinc = cfg_param->ctl_dinc; + ctl_u.ch_ctl.src_tr_width = cfg_param->ctl_src_tr_width; + ctl_u.ch_ctl.dst_tr_width = cfg_param->ctl_dst_tr_width; + ctl_u.ch_ctl.src_msize = cfg_param->ctl_src_msize; + ctl_u.ch_ctl.dst_msize = cfg_param->ctl_drc_msize; + ctl_u.ch_ctl.src_stat_en = cfg_param->ctl_src_stat_en; + ctl_u.ch_ctl.dst_stat_en = cfg_param->ctl_dst_stat_en; + if (last_block != LAST_ROW) + { + ctl_u.ch_ctl.shadowreg_or_lli_valid = 1; + ctl_u.ch_ctl.shadowreg_or_lli_last = 0; + } else { + ctl_u.ch_ctl.shadowreg_or_lli_valid = 1; + ctl_u.ch_ctl.shadowreg_or_lli_last = 1; + } + + writeq(ctl_u.data, &dmac->channel[channel_num].ctl); + writeq(0, &dmac->channel[channel_num].blk_tfr); +} + +void dmac_set_shadow_invalid_flag(dmac_channel_number channel_num) +{ + union dmac_ch_ctl_u ctl_u; + + ctl_u.data = readq(&dmac->channel[channel_num].ctl); + ctl_u.ch_ctl.shadowreg_or_lli_valid = 1; + ctl_u.ch_ctl.shadowreg_or_lli_last = 0; + writeq(ctl_u.data, &dmac->channel[channel_num].ctl); +} + +void dmac_set_single_mode(dmac_channel_number channel_num, + void *src, void *dest, enum dmac_address_increment src_inc, enum dmac_address_increment dest_inc, + enum dmac_burst_trans_length dmac_msize, + enum dmac_transfer_width dmac_trans_width, + uint32_t blockSize) +{ + dmac_channel_disable(channel_num); + dmac_set_channel_param(channel_num, src, dest, src_inc,dest_inc, + dmac_msize,dmac_trans_width,blockSize); + dmac_enable(); + dmac_chanel_interrupt_clear(channel_num); /* clear interrupt */ + dmac_enable_channel_interrupt_status(channel_num); + dmac_channel_enable(channel_num); +} + +void dmac_wait_done(dmac_channel_number channel_num) +{ + while (!(readq(&dmac->channel[channel_num].intstatus) & 0x2)) + ; + dmac_chanel_interrupt_clear(channel_num); /* clear interrupt */ +} diff --git a/lib/drivers/dvp.c b/lib/drivers/dvp.c new file mode 100644 index 0000000..ebc6386 --- /dev/null +++ b/lib/drivers/dvp.c @@ -0,0 +1,293 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include "dvp.h" +#include "common.h" +#include "fpioa.h" +#include "sysctl.h" + +volatile struct dvp_t* const dvp = (volatile struct dvp_t*)DVP_BASE_ADDR; +static uint8_t reg_len = 8; + +void mdelay(uint32_t ms) +{ + uint32_t i; + + while (ms && ms--) + { + for (i = 0; i < 25000; i++) + __asm__ __volatile__("nop"); + } +} + +static void dvp_sccb_clk_init(void) +{ + uint32_t tmp; + + tmp = dvp->sccb_cfg & (~(DVP_SCCB_SCL_LCNT_MASK | DVP_SCCB_SCL_HCNT_MASK)); + tmp |= DVP_SCCB_SCL_LCNT(500) | DVP_SCCB_SCL_HCNT(500); + + dvp->sccb_cfg = tmp; +} + +static void dvp_sccb_start_transfer(void) +{ + while (dvp->sts & DVP_STS_SCCB_EN) + ; + dvp->sts = DVP_STS_SCCB_EN | DVP_STS_SCCB_EN_WE; + while (dvp->sts & DVP_STS_SCCB_EN) + ; +} + +int dvp_sccb_write(uint8_t dev_addr, uint16_t reg_addr, uint8_t reg_data) +{ + uint32_t tmp; + + tmp = dvp->sccb_cfg & (~DVP_SCCB_BYTE_NUM_MASK); + + (reg_len == 8) ? (tmp |= DVP_SCCB_BYTE_NUM_3) : (tmp |= DVP_SCCB_BYTE_NUM_4); + + dvp->sccb_cfg = tmp; + + if (reg_len == 8) + { + dvp->sccb_ctl = DVP_SCCB_WRITE_ENABLE | DVP_SCCB_DEVICE_ADDRESS(dev_addr) | DVP_SCCB_REG_ADDRESS(reg_addr) | DVP_SCCB_WDATA_BYTE0(reg_data); + } + else + { + dvp->sccb_ctl = DVP_SCCB_WRITE_ENABLE | DVP_SCCB_DEVICE_ADDRESS(dev_addr) | DVP_SCCB_REG_ADDRESS(reg_addr >> 8) | DVP_SCCB_WDATA_BYTE0(reg_addr & 0xff) | DVP_SCCB_WDATA_BYTE1(reg_data); + } + dvp_sccb_start_transfer(); + + return 0; +} + +uint8_t dvp_sccb_read(uint8_t dev_addr, uint16_t reg_addr) +{ + uint32_t tmp; + + tmp = dvp->sccb_cfg & (~DVP_SCCB_BYTE_NUM_MASK); + (reg_len == 8) ? (tmp |= DVP_SCCB_BYTE_NUM_2) : (tmp |= DVP_SCCB_BYTE_NUM_3); + + dvp->sccb_cfg = tmp; + + if (reg_len == 8) + { + dvp->sccb_ctl = DVP_SCCB_WRITE_ENABLE | DVP_SCCB_DEVICE_ADDRESS(dev_addr) | DVP_SCCB_REG_ADDRESS(reg_addr); + } + else + { + dvp->sccb_ctl = DVP_SCCB_WRITE_ENABLE | DVP_SCCB_DEVICE_ADDRESS(dev_addr) | DVP_SCCB_REG_ADDRESS(reg_addr >> 8) | DVP_SCCB_WDATA_BYTE0(reg_addr & 0xff); + } + dvp_sccb_start_transfer(); + + dvp->sccb_ctl = DVP_SCCB_DEVICE_ADDRESS(dev_addr) | DVP_SCCB_REG_ADDRESS(reg_addr); + + dvp_sccb_start_transfer(); + + return DVP_SCCB_RDATA_BYTE(dvp->sccb_cfg); +} + +static void dvp_io_init(void) +{ + /* Init DVP IO map and function settings */ + fpioa_set_function(15, FUNC_CMOS_RST); + fpioa_set_function(17, FUNC_CMOS_PWND); + fpioa_set_function(20, FUNC_CMOS_XCLK); + fpioa_set_function(18, FUNC_CMOS_VSYNC); + fpioa_set_function(19, FUNC_CMOS_HREF); + fpioa_set_function(21, FUNC_CMOS_PCLK); + fpioa_set_function(22, FUNC_SCCB_SCLK); + fpioa_set_function(23, FUNC_SCCB_SDA); + sysctl->misc.reserved0 = 1; +} + +static void dvp_reset(void) +{ + /* First power down */ + dvp->cmos_cfg |= DVP_CMOS_POWER_DOWN; + mdelay(200); + dvp->cmos_cfg &= ~DVP_CMOS_POWER_DOWN; + mdelay(200); + + /* Second reset */ + dvp->cmos_cfg &= ~DVP_CMOS_RESET; + mdelay(200); + dvp->cmos_cfg |= DVP_CMOS_RESET; + mdelay(200); +} + +int dvp_init(uint8_t reglen) +{ + reg_len = reglen; + sysctl_clock_enable(SYSCTL_CLOCK_DVP); + sysctl_reset(SYSCTL_RESET_DVP); + dvp->cmos_cfg &= (~DVP_CMOS_CLK_DIV_MASK); + dvp->cmos_cfg |= DVP_CMOS_CLK_DIV(0) | DVP_CMOS_CLK_ENABLE; + dvp_io_init(); + dvp_sccb_clk_init(); + dvp_reset(); + + return 0; +} + +int dvp_set_image_format(uint32_t format) +{ + uint32_t tmp; + + tmp = dvp->dvp_cfg & (~DVP_CFG_FORMAT_MASK); + dvp->dvp_cfg = tmp | format; + + return 0; +} + +void dvp_burst_enable(void) +{ + dvp->dvp_cfg |= DVP_CFG_BURST_SIZE_4BEATS; + + dvp->axi &= (~DVP_AXI_GM_MLEN_MASK); + dvp->axi |= DVP_AXI_GM_MLEN_4BYTE; +} + +void dvp_burst_disable(void) +{ + dvp->dvp_cfg &= (~DVP_CFG_BURST_SIZE_4BEATS); + + dvp->axi &= (~DVP_AXI_GM_MLEN_MASK); + dvp->axi |= DVP_AXI_GM_MLEN_1BYTE; +} + +int dvp_set_image_size(uint32_t width, uint32_t height) +{ + uint32_t tmp; + + tmp = dvp->dvp_cfg & (~(DVP_CFG_HREF_BURST_NUM_MASK | DVP_CFG_LINE_NUM_MASK)); + + tmp |= DVP_CFG_LINE_NUM(height); + + if (dvp->dvp_cfg & DVP_CFG_BURST_SIZE_4BEATS) + tmp |= DVP_CFG_HREF_BURST_NUM(width / 8 / 4); + else + tmp |= DVP_CFG_HREF_BURST_NUM(width / 8 / 1); + + dvp->dvp_cfg = tmp; + + return 0; +} + +int dvp_set_ai_addr(uint32_t r_addr, uint32_t g_addr, uint32_t b_addr) +{ + dvp->r_addr = r_addr; + dvp->g_addr = g_addr; + dvp->b_addr = b_addr; + + return 0; +} + +int dvp_set_display_addr(uint32_t addr) +{ + dvp->rgb_addr = addr; + + return 0; +} + +int dvp_frame_start(void) +{ + while (!(dvp->sts & DVP_STS_FRAME_START)) + ; + dvp->sts = (DVP_STS_FRAME_START | DVP_STS_FRAME_START_WE); + + return 0; +} + +void dvp_convert_start(void) +{ + dvp->sts = DVP_STS_DVP_EN | DVP_STS_DVP_EN_WE; +} + +int dvp_convert_finish(void) +{ + while (!(dvp->sts & DVP_STS_FRAME_FINISH)) + ; + dvp->sts = DVP_STS_FRAME_FINISH | DVP_STS_FRAME_FINISH_WE; + + return 0; +} + +int dvp_get_image(void) +{ + while (!(dvp->sts & DVP_STS_FRAME_START)) + ; + dvp->sts = DVP_STS_FRAME_START | DVP_STS_FRAME_START_WE; + while (!(dvp->sts & DVP_STS_FRAME_START)) + ; + dvp->sts = DVP_STS_FRAME_FINISH | DVP_STS_FRAME_FINISH_WE | DVP_STS_FRAME_START | DVP_STS_FRAME_START_WE | DVP_STS_DVP_EN | DVP_STS_DVP_EN_WE; + while (!(dvp->sts & DVP_STS_FRAME_FINISH)) + ; + + return 0; +} + +void dvp_interrupt_config(uint32_t interrupt, uint8_t status) +{ + if (status) + dvp->dvp_cfg |= interrupt; + else + dvp->dvp_cfg &= (~interrupt); +} + +int dvp_interrupt_get(uint32_t interrupt) +{ + if (dvp->sts & interrupt) + return 1; + return 0; +} + +void dvp_interrupt_clear(uint32_t interrupt) +{ + interrupt |= (interrupt << 1); + dvp->sts |= interrupt; +} + +void dvp_enable_auto(void) +{ + dvp->dvp_cfg |= DVP_CFG_AUTO_ENABLE; +} + +void dvp_disable_auto(void) +{ + dvp->dvp_cfg &= (~DVP_CFG_AUTO_ENABLE); +} + +void dvp_set_output_enable(size_t index, int enable) +{ + configASSERT(index < 2); + + if (index == 0) + { + if (enable) + dvp->dvp_cfg |= DVP_CFG_AI_OUTPUT_ENABLE; + else + dvp->dvp_cfg &= ~DVP_CFG_AI_OUTPUT_ENABLE; + } + else + { + if (enable) + dvp->dvp_cfg |= DVP_CFG_DISPLAY_OUTPUT_ENABLE; + else + dvp->dvp_cfg &= ~DVP_CFG_DISPLAY_OUTPUT_ENABLE; + } +} diff --git a/lib/drivers/fpioa.c b/lib/drivers/fpioa.c new file mode 100644 index 0000000..8f7ad7e --- /dev/null +++ b/lib/drivers/fpioa.c @@ -0,0 +1,5398 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include "sysctl.h" +#include "fpioa.h" + +volatile struct fpioa_t *const fpioa = (volatile struct fpioa_t *)FPIOA_BASE_ADDR; + +/** + * @brief Internal used FPIOA function initialize cell + * + * This is NOT fpioa_io_config_t, can't assign directly + * + */ +struct fpioa_assign_t +{ + uint32_t ch_sel : 8; + /* Channel select from 256 input. */ + uint32_t ds : 4; + /* Driving selector. */ + uint32_t oe_en : 1; + /* Static output enable, will AND with OE_INV. */ + uint32_t oe_inv : 1; + /* Invert output enable. */ + uint32_t do_sel : 1; + /* Data output select: 0 for DO, 1 for OE. */ + uint32_t do_inv : 1; + /* Invert the result of data output select (DO_SEL). */ + uint32_t pu : 1; + /* Pull up enable. 0 for nothing, 1 for pull up. */ + uint32_t pd : 1; + /* Pull down enable. 0 for nothing, 1 for pull down. */ + uint32_t resv0 : 1; + /* Reserved bits. */ + uint32_t sl : 1; + /* Slew rate control enable. */ + uint32_t ie_en : 1; + /* Static input enable, will AND with IE_INV. */ + uint32_t ie_inv : 1; + /* Invert input enable. */ + uint32_t di_inv : 1; + /* Invert Data input. */ + uint32_t st : 1; + /* Schmitt trigger. */ + uint32_t tie_en : 1; + /* Input tie enable, 1 for enable, 0 for disable. */ + uint32_t tie_val : 1; + /* Input tie value, 1 for high, 0 for low. */ + uint32_t resv1 : 5; + /* Reserved bits. */ + uint32_t pad_di : 1; + /* Read current PAD's data input. */ +} __attribute__((packed, aligned(4))); + +/* Function list */ +static const struct fpioa_assign_t function_config[FUNC_MAX] = +{ + { + .ch_sel = FUNC_JTAG_TCLK, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_JTAG_TDI, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_JTAG_TMS, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_JTAG_TDO, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_D0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_D1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_D2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_D3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_D4, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_D5, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_D6, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_D7, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_SS0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_SS1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_SS2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_SS3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_ARB, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 1, + .tie_val = 1, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_SCLK, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UARTHS_RX, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UARTHS_TX, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CLK_IN1, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CLK_IN2, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CLK_SPI1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CLK_I2C1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS4, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS5, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS6, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS7, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS8, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS9, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS10, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS11, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS12, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS13, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS14, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS15, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS16, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS17, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS18, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS19, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS20, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS21, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS22, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS23, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS24, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS25, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS26, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS27, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS28, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS29, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS30, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS31, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIO0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIO1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIO2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIO3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIO4, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIO5, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIO6, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIO7, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_RX, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_TX, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_RX, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_TX, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_RX, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_TX, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_D0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_D1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_D2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_D3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_D4, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_D5, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_D6, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_D7, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_SS0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_SS1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_SS2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_SS3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_ARB, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 1, + .tie_val = 1, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_SCLK, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI_SLAVE_D0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI_SLAVE_SS, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI_SLAVE_SCLK, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S0_MCLK, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S0_SCLK, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S0_WS, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S0_IN_D0, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S0_IN_D1, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S0_IN_D2, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S0_IN_D3, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S0_OUT_D0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S0_OUT_D1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S0_OUT_D2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S0_OUT_D3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S1_MCLK, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S1_SCLK, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S1_WS, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S1_IN_D0, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S1_IN_D1, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S1_IN_D2, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S1_IN_D3, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S1_OUT_D0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S1_OUT_D1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S1_OUT_D2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S1_OUT_D3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S2_MCLK, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S2_SCLK, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S2_WS, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S2_IN_D0, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S2_IN_D1, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S2_IN_D2, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S2_IN_D3, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S2_OUT_D0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S2_OUT_D1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S2_OUT_D2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S2_OUT_D3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_RESV0, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_RESV1, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_RESV2, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_RESV3, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_RESV4, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_RESV5, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2C0_SCLK, + .ds = 0x0, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 1, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2C0_SDA, + .ds = 0x0, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 1, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2C1_SCLK, + .ds = 0x0, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 1, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2C1_SDA, + .ds = 0x0, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 1, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2C2_SCLK, + .ds = 0x0, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 1, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2C2_SDA, + .ds = 0x0, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 1, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_XCLK, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_RST, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_PWND, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_VSYNC, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_HREF, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_PCLK, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_D0, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_D1, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_D2, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_D3, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_D4, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_D5, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_D6, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_D7, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SCCB_SCLK, + .ds = 0x0, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 1, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SCCB_SDA, + .ds = 0x0, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 1, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_CTS, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_DSR, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_DCD, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_RI, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_SIR_IN, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_DTR, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_RTS, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_OUT2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_OUT1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_SIR_OUT, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_BAUD, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_RE, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_DE, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_RS485_EN, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_CTS, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_DSR, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_DCD, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_RI, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_SIR_IN, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_DTR, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_RTS, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_OUT2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_OUT1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_SIR_OUT, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_BAUD, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_RE, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_DE, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_RS485_EN, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_CTS, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_DSR, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_DCD, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_RI, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_SIR_IN, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_DTR, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_RTS, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_OUT2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_OUT1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_SIR_OUT, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_BAUD, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_RE, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_DE, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_RS485_EN, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_TIMER0_TOGGLE1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_TIMER0_TOGGLE2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_TIMER0_TOGGLE3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_TIMER0_TOGGLE4, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_TIMER1_TOGGLE1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_TIMER1_TOGGLE2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_TIMER1_TOGGLE3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_TIMER1_TOGGLE4, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_TIMER2_TOGGLE1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_TIMER2_TOGGLE2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_TIMER2_TOGGLE3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_TIMER2_TOGGLE4, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CLK_SPI2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CLK_I2C2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL4, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL5, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL6, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL7, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL8, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL9, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL10, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL11, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL12, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = 217, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = 218, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 1, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL13, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL14, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL15, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CONSTANT, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL16, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG4, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG5, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG6, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG7, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG8, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG9, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG10, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG11, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG12, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG13, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG14, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG15, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG16, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG17, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG18, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG19, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG20, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG21, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG22, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG23, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG24, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG25, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG26, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG27, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG28, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG29, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG30, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG31, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, +}; + +int fpioa_init(void) +{ + int i = 0; + + /* Enable fpioa clock in system controller */ + sysctl_clock_enable(SYSCTL_CLOCK_FPIOA); + + /* Initialize tie */ + struct fpioa_tie_t tie = { 0 }; + + /* Set tie enable and tie value */ + for (i = 0; i < FUNC_MAX; i++) + { + tie.en[i / 32] |= (function_config[i].tie_en << (i % 32)); + tie.val[i / 32] |= (function_config[i].tie_val << (i % 32)); + } + + /* Atomic write every 32bit register to fpioa function */ + for (i = 0; i < FUNC_MAX / 32; i++) + { + /* Set value before enable */ + fpioa->tie.val[i] = tie.val[i]; + fpioa->tie.en[i] = tie.en[i]; + } + + return 0; +} + +int fpioa_get_io(int number, struct fpioa_io_config_t *cfg) +{ + /* Check parameters */ + if (number < 0 || number >= FPIOA_NUM_IO || cfg == NULL) + return -1; + /* Atomic read register */ + *cfg = fpioa->io[number]; + return 0; +} + +int fpioa_set_io(int number, struct fpioa_io_config_t *cfg) +{ + /* Check parameters */ + if (number < 0 || number >= FPIOA_NUM_IO || cfg == NULL) + return -1; + /* Atomic write register */ + fpioa->io[number] = *cfg; + return 0; +} + +int fpioa_set_io_pull(int number, enum fpioa_pull_e pull) +{ + /* Check parameters */ + if (number < 0 || number >= FPIOA_NUM_IO || pull >= FPIOA_PULL_MAX) + return -1; + + /* Atomic read register */ + struct fpioa_io_config_t cfg = fpioa->io[number]; + + switch (pull) + { + case FPIOA_PULL_NONE: + cfg.pu = 0; + cfg.pd = 0; + break; + case FPIOA_PULL_DOWN: + cfg.pu = 0; + cfg.pd = 1; + break; + case FPIOA_PULL_UP: + cfg.pu = 1; + cfg.pd = 0; + break; + default: + break; + } + /* Atomic write register */ + fpioa->io[number] = cfg; + return 0; +} + +int fpioa_get_io_pull(int number) +{ + /* Check parameters */ + if (number < 0 || number >= FPIOA_NUM_IO) + return -1; + + enum fpioa_pull_e pull; + /* Atomic read register */ + struct fpioa_io_config_t cfg = fpioa->io[number]; + + if (cfg.pu == 0 && cfg.pd == 1) + pull = FPIOA_PULL_DOWN; + else if (cfg.pu == 1 && cfg.pd == 0) + pull = FPIOA_PULL_UP; + else + pull = FPIOA_PULL_NONE; + return pull; +} + +int fpioa_set_io_driving(int number, enum fpioa_driving_e driving) +{ + /* Check parameters */ + if (number < 0 || number >= FPIOA_NUM_IO || driving >= FPIOA_DRIVING_MAX) + return -1; + + /* Atomic read register */ + struct fpioa_io_config_t cfg = fpioa->io[number]; + /* Set IO driving */ + cfg.ds = driving; + /* Atomic write register */ + fpioa->io[number] = cfg; + return 0; +} + +int fpioa_get_io_driving(int number) +{ + /* Check parameters */ + if (number < 0 || number >= FPIOA_NUM_IO) + return -1; + + return fpioa->io[number].ds; +} + +int fpioa_set_function_raw(int number, enum fpioa_function_e function) +{ + /* Check parameters */ + if (number < 0 || number >= FPIOA_NUM_IO || function < 0 || function >= FUNC_MAX) + return -1; + /* Atomic write register */ + fpioa->io[number] =(const struct fpioa_io_config_t) + { + .ch_sel = function_config[function].ch_sel, + .ds = function_config[function].ds, + .oe_en = function_config[function].oe_en, + .oe_inv = function_config[function].oe_inv, + .do_sel = function_config[function].do_sel, + .do_inv = function_config[function].do_inv, + .pu = function_config[function].pu, + .pd = function_config[function].pd, + .sl = function_config[function].sl, + .ie_en = function_config[function].ie_en, + .ie_inv = function_config[function].ie_inv, + .di_inv = function_config[function].di_inv, + .st = function_config[function].st, + /* resv and pad_di do not need initialization */ + }; + return 0; +} + +int fpioa_set_function(int number, enum fpioa_function_e function) +{ + uint8_t index = 0; + /* Check parameters */ + if (number < 0 || number >= FPIOA_NUM_IO || function < 0 || function >= FUNC_MAX) + return -1; + if (function == FUNC_RESV0) + { + fpioa_set_function_raw(number, FUNC_RESV0); + return 0; + } + /* Compare all IO */ + for (index = 0; index < FPIOA_NUM_IO; index++) + { + if ((fpioa->io[index].ch_sel == function) && (index != number)) + fpioa_set_function_raw(index, FUNC_RESV0); + } + fpioa_set_function_raw(number, function); + return 0; +} + +int fpioa_set_tie_enable(enum fpioa_function_e function, int enable) +{ + /* Check parameters */ + if (function < 0 || function >= FUNC_MAX) + return -1; + /* Set tie enable */ + if (enable) + fpioa->tie.en[function / 32] |= (1UL << (function % 32)); + else + fpioa->tie.en[function / 32] &= (~(1UL << (function % 32))); + return 0; +} + +int fpioa_set_tie_value(enum fpioa_function_e function, int value) +{ + /* Check parameters */ + if (function < 0 || function >= FUNC_MAX) + return -1; + /* Set tie value */ + if (value) + fpioa->tie.val[function / 32] |= (1UL << (function % 32)); + else + fpioa->tie.val[function / 32] &= (~(1UL << (function % 32))); + return 0; +} + +int fpioa_get_io_by_func(enum fpioa_function_e function) +{ + int index = 0; + for (index = 0; index < FPIOA_NUM_IO; index++) + { + if (fpioa->io[index].ch_sel == function) + return index; + } + + return -1; +} diff --git a/lib/drivers/gpio.c b/lib/drivers/gpio.c new file mode 100644 index 0000000..d920d74 --- /dev/null +++ b/lib/drivers/gpio.c @@ -0,0 +1,86 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "gpio.h" +#include "common.h" +#include "fpioa.h" +#include "sysctl.h" +#define GPIO_MAX_PINNO 8 + +volatile gpio_t* const gpio = (volatile gpio_t*)GPIO_BASE_ADDR; + +int gpio_init(void) +{ + sysctl_clock_enable(SYSCTL_CLOCK_GPIO); + return 0; +} + +void gpio_pin_init(size_t pin_num, size_t gpio_pin) +{ + configASSERT(gpio_pin < GPIO_MAX_PINNO); + fpioa_set_function(pin_num, FUNC_GPIO0 + gpio_pin); +} + +void gpio_set_drive_mode(size_t pin, gpio_drive_mode mode) +{ + configASSERT(pin < GPIO_MAX_PINNO); + int io_number = fpioa_get_io_by_func(FUNC_GPIO0 + pin); + configASSERT(io_number > 0); + + enum fpioa_pull_e pull; + uint32_t dir; + + switch (mode) + { + case GPIO_DM_Input: + pull = FPIOA_PULL_NONE; + dir = 0; + break; + case GPIO_DM_InputPullDown: + pull = FPIOA_PULL_DOWN; + dir = 0; + break; + case GPIO_DM_InputPullUp: + pull = FPIOA_PULL_UP; + dir = 0; + break; + case GPIO_DM_Output: + pull = FPIOA_PULL_DOWN; + dir = 1; + break; + default: + configASSERT(!"GPIO drive mode is not supported.") break; + } + + fpioa_set_io_pull(io_number, pull); + set_gpio_bit(gpio->direction.u32, pin, dir); +} + +gpio_pin_value gpio_get_pin_value(size_t pin) +{ + configASSERT(pin < GPIO_MAX_PINNO); + uint32_t dir = get_gpio_bit(gpio->direction.u32, pin); + volatile uint32_t* reg = dir ? gpio->data_output.u32 : gpio->data_input.u32; + return get_gpio_bit(reg, pin); +} + +void gpio_set_pin_value(size_t pin, gpio_pin_value value) +{ + configASSERT(pin < GPIO_MAX_PINNO); + uint32_t dir = get_gpio_bit(gpio->direction.u32, pin); + volatile uint32_t* reg = dir ? gpio->data_output.u32 : gpio->data_input.u32; + configASSERT(dir == 1); + set_gpio_bit(reg, pin, value); +} + diff --git a/lib/drivers/gpiohs.c b/lib/drivers/gpiohs.c new file mode 100644 index 0000000..582ec0c --- /dev/null +++ b/lib/drivers/gpiohs.c @@ -0,0 +1,184 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "gpiohs.h" +#include "common.h" +#include "fpioa.h" +#include "sysctl.h" +#define GPIOHS_MAX_PINNO 32 + +volatile gpiohs_t* const gpiohs = (volatile gpiohs_t*)GPIOHS_BASE_ADDR; + +struct gpiohs_pin_context +{ + size_t pin; + gpio_pin_edge edge; + void (*callback)(); +} pin_context[32]; + +int gpiohs_init(void) +{ + gpiohs->rise_ie.u32[0] = 0; + gpiohs->rise_ip.u32[0] = 0xFFFFFFFF; + gpiohs->fall_ie.u32[0] = 0; + gpiohs->fall_ip.u32[0] = 0xFFFFFFFF; + return 0; +} + +void gpiohs_pin_init(size_t pin_num, size_t gpio_pin) +{ + configASSERT(gpio_pin < GPIOHS_MAX_PINNO); + fpioa_set_function(pin_num, FUNC_GPIOHS0 + gpio_pin); +} + +void gpiohs_set_drive_mode(size_t pin, gpio_drive_mode mode) +{ + configASSERT(pin < GPIOHS_MAX_PINNO); + int io_number = fpioa_get_io_by_func(FUNC_GPIOHS0 + pin); + configASSERT(io_number > 0); + + enum fpioa_pull_e pull; + uint32_t dir; + + switch (mode) + { + case GPIO_DM_Input: + pull = FPIOA_PULL_NONE; + dir = 0; + break; + case GPIO_DM_InputPullDown: + pull = FPIOA_PULL_DOWN; + dir = 0; + break; + case GPIO_DM_InputPullUp: + pull = FPIOA_PULL_UP; + dir = 0; + break; + case GPIO_DM_Output: + pull = FPIOA_PULL_DOWN; + dir = 1; + break; + default: + configASSERT(!"GPIO drive mode is not supported.") break; + } + + fpioa_set_io_pull(io_number, pull); + volatile uint32_t* reg = dir ? gpiohs->output_en.u32 : gpiohs->input_en.u32; + volatile uint32_t* reg_d = !dir ? gpiohs->output_en.u32 : gpiohs->input_en.u32; + set_gpio_bit(reg_d, pin, 0); + set_gpio_bit(reg, pin, 1); +} + +gpio_pin_value gpiohs_get_pin_value(size_t pin) +{ + configASSERT(pin < GPIOHS_MAX_PINNO); + return get_gpio_bit(gpiohs->input_val.u32, pin); +} + +void gpiohs_set_pin_value(size_t pin, gpio_pin_value value) +{ + configASSERT(pin < GPIOHS_MAX_PINNO); + set_gpio_bit(gpiohs->output_val.u32, pin, value); +} + +void gpiohs_set_pin_edge(size_t pin, gpio_pin_edge edge) +{ + uint32_t rise, fall, irq; + switch (edge) + { + case GPIO_PE_None: + rise = fall = irq = 0; + break; + case GPIO_PE_Falling: + rise = 0; + fall = irq = 1; + break; + case GPIO_PE_Rising: + fall = 0; + rise = irq = 1; + break; + case GPIO_PE_Both: + rise = fall = irq = 1; + break; + default: + configASSERT(!"Invalid gpio edge"); + break; + } + + set_gpio_bit(gpiohs->rise_ie.u32, pin, rise); + set_gpio_bit(gpiohs->fall_ie.u32, pin, fall); + pin_context[pin].edge = edge; +} + +int gpiohs_pin_onchange_isr(void* userdata) +{ + struct gpiohs_pin_context* ctx = (struct gpiohs_pin_context*)userdata; + size_t pin = ctx->pin; + uint32_t rise, fall; + switch (ctx->edge) + { + case GPIO_PE_None: + rise = fall = 0; + break; + case GPIO_PE_Falling: + rise = 0; + fall = 1; + break; + case GPIO_PE_Rising: + fall = 0; + rise = 1; + break; + case GPIO_PE_Both: + rise = fall = 1; + break; + default: + configASSERT(!"Invalid gpio edge"); + break; + } + + if (rise) + { + set_gpio_bit(gpiohs->rise_ie.u32, pin, 0); + set_gpio_bit(gpiohs->rise_ip.u32, pin, 1); + set_gpio_bit(gpiohs->rise_ie.u32, pin, 1); + } + + if (fall) + { + set_gpio_bit(gpiohs->fall_ie.u32, pin, 0); + set_gpio_bit(gpiohs->fall_ip.u32, pin, 1); + set_gpio_bit(gpiohs->fall_ie.u32, pin, 1); + } + + if (ctx->callback) + ctx->callback(); + return 0; +} + +void gpiohs_set_irq(size_t pin, uint32_t priority, void (*func)()) +{ + + pin_context[pin].pin = pin; + pin_context[pin].callback = func; + + plic_set_priority(IRQN_GPIOHS0_INTERRUPT + pin, priority); + plic_irq_register(IRQN_GPIOHS0_INTERRUPT + pin, gpiohs_pin_onchange_isr, &(pin_context[pin])); + plic_irq_enable(IRQN_GPIOHS0_INTERRUPT + pin); +} + +void gpiohs_irq_disable(size_t pin) +{ + plic_irq_disable(IRQN_GPIOHS0_INTERRUPT + pin); +} + diff --git a/lib/drivers/hard_fft.c b/lib/drivers/hard_fft.c new file mode 100644 index 0000000..e6e3e95 --- /dev/null +++ b/lib/drivers/hard_fft.c @@ -0,0 +1,150 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include "env/encoding.h" +#include "hard_fft.h" +#include "platform.h" +#include "syscalls.h" +#include "sysctl.h" + +#define FFT_RESULT_ADDR (0x42100000 + 0x2000) +volatile uint64_t* fft_result = (volatile uint64_t*)FFT_RESULT_ADDR; + +volatile fft_t* const fft = (volatile fft_t*)FFT_BASE_ADDR; + +int fft_init(uint8_t point, uint8_t mode, uint16_t shift, uint8_t is_dma, uint8_t input_mode, uint8_t data_mode) +{ + fft->fft_ctrl.fft_point = point; /* 0:512, 1:256, 2:128, 3:64 */ + fft->fft_ctrl.fft_mode = mode; /* 1: fft, 0: ifft */ + fft->fft_ctrl.fft_shift = shift; + fft->fft_ctrl.dma_send = is_dma; + fft->fft_ctrl.fft_enable = 1; + fft->fft_ctrl.fft_input_mode = input_mode; + fft->fft_ctrl.fft_data_mode = data_mode; + return 0; +} + +void fft_reset(void) +{ + fft->fifo_ctrl.resp_fifo_flush_n = 0; + fft->fifo_ctrl.cmd_fifo_flush_n = 0; + fft->fifo_ctrl.gs_fifo_flush_n = 0; +} + +void fft_enable_int(void) +{ + fft->intr_mask.fft_done_mask = 1; +} + +void fft_input_data(float* x, float* y, uint8_t point) +{ + uint16_t point_num = 0; + uint16_t i; + fft_data input_data; + + if (point == 0) + point_num = 512; + else if (point == 1) + point_num = 256; + else if (point == 2) + point_num = 128; + else if (point == 3) + point_num = 64; + point_num = point_num / 2; /* one time send two data */ + + for (i = 0; i < point_num; i++) + { + input_data.R1 = (int16_t)(x[2 * i] * 32); + input_data.I1 = (int16_t)(y[2 * i] * 32); + input_data.R2 = (int16_t)(x[2 * i + 1] * 32); + input_data.I2 = (int16_t)(y[2 * i + 1] * 32); + + fft->fft_input_fifo.fft_input_fifo = *(uint64_t*)&input_data; + printf("%d, %d\n", input_data.R1, input_data.I1); + printf("%d, %d\n", input_data.R2, input_data.I2); + } +} + +void fft_input_intdata(int16_t* data, uint8_t point) +{ + uint16_t point_num = 0; + uint16_t i; + fft_data input_data; + + if (point == 0) + point_num = 512; + else if (point == 1) + point_num = 256; + else if (point == 2) + point_num = 128; + else if (point == 3) + point_num = 64; + point_num = point_num / 2; /* one time send two data */ + + for (i = 0; i < point_num; i++) + { + input_data.R1 = data[2 * i]; + input_data.I1 = 0; + input_data.R2 = data[2 * i + 1]; + input_data.I2 = 0; + + fft->fft_input_fifo.fft_input_fifo = *(uint64_t*)&input_data; + } +} + +uint8_t fft_get_finish_flag(void) +{ + return (uint8_t)fft->fft_status.fft_done_status & 0x01; +} + +void FixToDou(float* fData, uint32_t u32Data) +{ + if (u32Data & 0x8000) + *fData = -((float)(u32Data & 0x7fff)) / 32; + else + *fData = ((float)u32Data) / 32; +} + +void fft_get_result(float* x, float* y, uint8_t point) +{ + uint64_t u64Data; + uint16_t point_num = 0; + uint16_t i; + fft_data output_data; + + if (point == 0) + point_num = 512; + else if (point == 1) + point_num = 256; + else if (point == 2) + point_num = 128; + else if (point == 3) + point_num = 64; + point_num = point_num / 2; + + for (i = 0; i < point_num; i++) + { + u64Data = fft_result[i]; /*fft->fft_output_fifo.fft_output_fifo;*/ + + output_data = *(fft_data*)&u64Data; + + x[2 * i] = ((float)output_data.R1) / 32; + y[2 * i] = ((float)output_data.I1) / 32; + x[2 * i + 1] = ((float)output_data.R2) / 32; + y[2 * i + 1] = ((float)output_data.I2) / 32; + } +} + diff --git a/lib/drivers/i2c.c b/lib/drivers/i2c.c new file mode 100644 index 0000000..e0cf919 --- /dev/null +++ b/lib/drivers/i2c.c @@ -0,0 +1,196 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include "i2c.h" +#include "common.h" +#include "fpioa.h" +#include "platform.h" +#include "stdlib.h" +#include "string.h" +#include "sysctl.h" + +volatile struct i2c_t* const i2c[3] = +{ + (volatile struct i2c_t*)I2C0_BASE_ADDR, + (volatile struct i2c_t*)I2C1_BASE_ADDR, + (volatile struct i2c_t*)I2C2_BASE_ADDR +}; + +void i2c_pin_init(uint8_t sel, int clk_pin, int data_pin) +{ + configASSERT(sel < I2C_MAX_NUM); + fpioa_set_function(clk_pin, FUNC_I2C0_SCLK + (2 * sel)); + fpioa_set_function(data_pin, FUNC_I2C0_SDA + (2 * sel)); +} + +void i2c_clk_init(uint8_t sel) +{ + configASSERT(sel < I2C_MAX_NUM); + sysctl_clock_enable(SYSCTL_CLOCK_I2C0 + sel); + sysctl_clock_set_threshold(SYSCTL_THRESHOLD_I2C0 + sel, 3); +} + +void i2c_init(uint8_t sel, int clk_pin, int data_pin) +{ + configASSERT(sel < I2C_MAX_NUM); + i2c_pin_init(sel, clk_pin, data_pin); + i2c_clk_init(sel); + dmac_init(); +} + +void i2c_config(uint8_t sel, size_t slaveAddress, size_t address_width,i2c_bus_speed_mode bus_speed_mode) +{ + configASSERT(sel < I2C_MAX_NUM); + configASSERT(address_width == 7 || address_width == 10); + int speed_mode = 1; + switch (bus_speed_mode) + { + case I2C_BS_STANDARD: + speed_mode = 1; + break; + default: + break; + } + /*set config*/ + volatile struct i2c_t* i2c_adapter = i2c[sel]; + i2c_adapter->enable = 0; + i2c_adapter->con = I2C_CON_MASTER_MODE | I2C_CON_SLAVE_DISABLE | I2C_CON_RESTART_EN | + (address_width == 10 ? I2C_CON_10BITADDR_SLAVE : 0) | I2C_CON_SPEED(speed_mode); + i2c_adapter->ss_scl_hcnt = I2C_SS_SCL_HCNT_COUNT(37); + i2c_adapter->ss_scl_lcnt = I2C_SS_SCL_LCNT_COUNT(40); + i2c_adapter->tar = I2C_TAR_ADDRESS(slaveAddress); + i2c_adapter->intr_mask = 0; + i2c_adapter->dma_cr = 0x3; + i2c_adapter->dma_rdlr = 0; + i2c_adapter->dma_tdlr = 4; + i2c_adapter->enable = I2C_ENABLE_ENABLE; +} + +int i2c_write_reg(uint8_t sel, uint8_t reg, uint8_t* data_buf, uint8_t length) +{ + configASSERT(sel < I2C_MAX_NUM); + volatile struct i2c_t* i2c_adapter = i2c[sel]; + uint8_t fifo_len, index; + + fifo_len = length < 7 ? length : 7; + i2c_adapter->data_cmd = I2C_DATA_CMD_DATA(reg); + for (index = 0; index < fifo_len; index++) + i2c_adapter->data_cmd = I2C_DATA_CMD_DATA(*data_buf++); + length -= fifo_len; + while (length) + { + fifo_len = 8 - i2c_adapter->txflr; + fifo_len = length < fifo_len ? length : fifo_len; + for (index = 0; index < fifo_len; index++) + i2c_adapter->data_cmd = I2C_DATA_CMD_DATA(*data_buf++); + if (i2c_adapter->tx_abrt_source != 0) + return 1; + length -= fifo_len; + } + while (i2c_adapter->status & I2C_STATUS_ACTIVITY) + ; + return 0; +} + +int i2c_write_reg_dma(dmac_channel_number channel_num, uint8_t sel, uint8_t reg, uint8_t* data_buf, uint8_t length) +{ + configASSERT(sel < I2C_MAX_NUM); + volatile struct i2c_t* i2c_adapter = i2c[sel]; + + uint32_t* buf = malloc((length + 1) * sizeof(uint32_t)); + buf[0] = reg; + int i; + for (i = 0; i < length + 1; i++) + { + buf[i + 1] = data_buf[i]; + } + + sysctl_dma_select(channel_num, SYSCTL_DMA_SELECT_I2C0_TX_REQ + sel * 2); + dmac_set_single_mode(channel_num, buf, (void*)(&i2c_adapter->data_cmd), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, length + 1); + + dmac_wait_done(channel_num); + free((void*)buf); + + while (i2c_adapter->status & I2C_STATUS_ACTIVITY) + { + if (i2c_adapter->tx_abrt_source != 0) + configASSERT(!"source abort"); + } + return 0; +} + +int i2c_read_reg(uint8_t sel, uint8_t reg, uint8_t* data_buf, uint8_t length) +{ + uint8_t fifo_len, index; + uint8_t rx_len = length; + configASSERT(sel < I2C_MAX_NUM); + volatile struct i2c_t* i2c_adapter = i2c[sel]; + + fifo_len = length < 7 ? length : 7; + i2c_adapter->data_cmd = I2C_DATA_CMD_DATA(reg); + for (index = 0; index < fifo_len; index++) + i2c_adapter->data_cmd = I2C_DATA_CMD_CMD; + length -= fifo_len; + while (length || rx_len) + { + fifo_len = i2c_adapter->rxflr; + fifo_len = rx_len < fifo_len ? rx_len : fifo_len; + for (index = 0; index < fifo_len; index++) + *data_buf++ = i2c_adapter->data_cmd; + rx_len -= fifo_len; + fifo_len = 8 - i2c_adapter->txflr; + fifo_len = length < fifo_len ? length : fifo_len; + for (index = 0; index < fifo_len; index++) + i2c_adapter->data_cmd = I2C_DATA_CMD_CMD; + if (i2c_adapter->tx_abrt_source != 0) + return 1; + length -= fifo_len; + } + return 0; +} + +int i2c_read_reg_dma(dmac_channel_number w_channel_num, dmac_channel_number r_channel_num, + uint8_t sel, uint8_t reg, uint8_t* data_buf, uint8_t length) +{ + configASSERT(sel < I2C_MAX_NUM); + volatile struct i2c_t* i2c_adapter = i2c[sel]; + + uint32_t* write_cmd = malloc(sizeof(uint32_t) * (1 + length)); + size_t i; + write_cmd[0] = reg; + for (i = 0; i < length; i++) + write_cmd[i + 1] = I2C_DATA_CMD_CMD; + + sysctl_dma_select(w_channel_num, SYSCTL_DMA_SELECT_I2C0_TX_REQ + sel * 2); + sysctl_dma_select(r_channel_num, SYSCTL_DMA_SELECT_I2C0_RX_REQ + sel * 2); + + dmac_set_single_mode(r_channel_num, (void*)(&i2c_adapter->data_cmd), write_cmd, DMAC_ADDR_NOCHANGE, + DMAC_ADDR_INCREMENT,DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, length); + + dmac_set_single_mode(w_channel_num, write_cmd, (void*)(&i2c_adapter->data_cmd), DMAC_ADDR_INCREMENT, + DMAC_ADDR_NOCHANGE,DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, length + 1); + + dmac_wait_done(w_channel_num); + dmac_wait_done(r_channel_num); + + for (i = 0; i < length; i++) + { + data_buf[i] = write_cmd[i]; + } + + free(write_cmd); + return 0; +} diff --git a/lib/drivers/i2s.c b/lib/drivers/i2s.c new file mode 100644 index 0000000..75c5074 --- /dev/null +++ b/lib/drivers/i2s.c @@ -0,0 +1,702 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include "i2s.h" +#include "sysctl.h" +#include "stdlib.h" + +volatile struct i2s_t *const i2s[3] = +{ + (volatile struct i2s_t *)I2S0_BASE_ADDR, + (volatile struct i2s_t *)I2S1_BASE_ADDR, + (volatile struct i2s_t *)I2S2_BASE_ADDR +}; + +void i2s_init(enum i2s_device_num_t device_num, enum i2s_transmit_t rxtx_mode, uint32_t channel_mask) +{ + sysctl_clock_enable(SYSCTL_CLOCK_I2S0 + device_num); + sysctl_reset(SYSCTL_RESET_I2S0 + device_num); + sysctl_clock_set_threshold(SYSCTL_THRESHOLD_I2S0 + device_num, 7); + /*96k:5,44k:12,24k:23,22k:25 16k:35 sampling*/ + /*sample rate*32bit*2 =75MHz/((N+1)*2) */ + i2s_device_enable(device_num); + i2s_disable_block(device_num, TRANSMITTER); + i2s_disable_block(device_num, RECEIVER); + + if (rxtx_mode == TRANSMITTER) + { + for (int i=0; i<4; i++) + { + if ((channel_mask & 0x3) == 0x3) + { + i2s_set_mask_interrupt(device_num, CHANNEL_0 + i, 1, 1, 1, 1); + i2s_transimit_enable(device_num, CHANNEL_0 + i); + } + else + { + i2s_transmit_channel_enable(device_num, CHANNEL_0 + i, 0); + } + channel_mask >>= 2; + } + i2s_transmit_dma_enable(device_num, 1); + } + else + { + for (int i=0; i<4; i++) + { + if ((channel_mask & 0x3) == 0x3) + { + i2s_set_mask_interrupt(device_num, CHANNEL_0 + i, 1, 1, 1, 1); + i2s_receive_enable(device_num, CHANNEL_0 + i); + } + else + { + i2s_receive_channel_enable(device_num, CHANNEL_0 + i, 0); + } + channel_mask >>= 2; + } + i2s_receive_dma_enable(device_num, 1); + } +} + +void i2s_device_enable(enum i2s_device_num_t device_num) +{ + union ier_u u_ier; + + u_ier.reg_data = readl(&i2s[device_num]->ier); + u_ier.ier.ien = 1; + writel(u_ier.reg_data, &i2s[device_num]->ier); +} + +void i2s_dev_enable(enum i2s_device_num_t device_num, uint32_t enable) +{ + union ier_u u_ier; + + u_ier.reg_data = readl(&i2s[device_num]->ier); + u_ier.ier.ien = enable; + writel(u_ier.reg_data, &i2s[device_num]->ier); +} + +void i2s_disable_block(enum i2s_device_num_t device_num, enum i2s_transmit_t rxtx_mode) +{ + union irer_u u_irer; + union iter_u u_iter; + + if (rxtx_mode == RECEIVER) + { + u_irer.reg_data = readl(&i2s[device_num]->irer); + u_irer.irer.rxen = 0; + writel(u_irer.reg_data, &i2s[device_num]->irer); + /* Receiver block disable */ + } + else + { + u_iter.reg_data = readl(&i2s[device_num]->iter); + u_iter.iter.txen = 0; + writel(u_iter.reg_data, &i2s[device_num]->iter); + /* Transmitter block disable */ + } +} + +void i2s_receive_enable(enum i2s_device_num_t device_num, enum i2s_channel_num_t channel_num) +{ + union irer_u u_irer; + + u_irer.reg_data = readl(&i2s[device_num]->irer); + u_irer.irer.rxen = 1; + writel(u_irer.reg_data, &i2s[device_num]->irer); + /* Receiver block enable */ + + i2s_receive_channel_enable(device_num, channel_num, 1); + /* Receive channel enable */ +} + +void i2s_transimit_enable(enum i2s_device_num_t device_num, enum i2s_channel_num_t channel_num) +{ + union iter_u u_iter; + + u_iter.reg_data = readl(&i2s[device_num]->iter); + u_iter.iter.txen = 1; + writel(u_iter.reg_data, &i2s[device_num]->iter); + /* Transmitter block enable */ + + i2s_transmit_channel_enable(device_num, channel_num, 1); + /* Transmit channel enable */ +} + +void i2s_rx_channel_configure(enum i2s_device_num_t device_num, + enum i2s_channel_num_t channel_num, + enum word_length_t word_length, + enum word_select_cycles_t word_select_size, + enum fifo_threshold_t trigger_level, + enum i2s_work_mode_t word_mode) +{ + i2s_receive_channel_enable(device_num, channel_num, 0); + /* Receive channel disable */ + + writel(0, &i2s[device_num]->channel[channel_num].ter); + /* disable tx */ + + writel(1, &i2s[device_num]->channel[channel_num].rff); + /* flash individual fifo */ + + writel(1, &i2s[device_num]->rxffr); + /* flush tx fifo*/ + + i2s_set_rx_word_length(device_num, word_length, channel_num); + /* Word length is RESOLUTION_32_BIT */ + + i2s_master_configure(device_num, + word_select_size, NO_CLOCK_GATING, word_mode); + /* word select size is 32 bits,no clock gating */ + + i2s_set_rx_threshold(device_num, trigger_level, channel_num); + /* Interrupt trigger when FIFO level is 8 */ + + readl(&i2s[device_num]->channel[channel_num].ror); + readl(&i2s[device_num]->channel[channel_num].tor); + + i2s_receive_channel_enable(device_num, channel_num, 1); +} + +void i2s_tx_channel_configure(enum i2s_device_num_t device_num, + enum i2s_channel_num_t channel_num, + enum word_length_t word_length, + enum word_select_cycles_t word_select_size, + enum fifo_threshold_t trigger_level, + enum i2s_work_mode_t word_mode) +{ + writel(0, &i2s[device_num]->channel[channel_num].rer); + /* disable rx */ + + i2s_transmit_channel_enable(device_num, channel_num, 0); + /* Transmit channel disable */ + + writel(1, &i2s[device_num]->txffr); + /* flush tx fifo */ + writel(1, &i2s[device_num]->channel[channel_num].tff); + /* flush individual fifo */ + + if (word_length == RESOLUTION_16_BIT) + { + i2s_transmit_dma_divide(I2S_DEVICE_0, 1); + } + i2s_set_tx_word_length(device_num, word_length, channel_num); + /* Word length is RESOLUTION_16_BIT */ + + i2s_master_configure(device_num, word_select_size, NO_CLOCK_GATING, word_mode); + /* word select size is 16 bits,gating after 16 bit */ + + i2s_set_tx_threshold(device_num, trigger_level, channel_num); + /* Interrupt trigger when FIFO level is 8 */ + + i2s_transmit_channel_enable(device_num, channel_num, 1); +} + +int i2s_set_rx_word_length(enum i2s_device_num_t device_num, + enum word_length_t word_length, + enum i2s_channel_num_t channel_num) +{ + union rcr_tcr_u u_rcr; + + if (word_length > RESOLUTION_32_BIT || word_length < IGNORE_WORD_LENGTH) + return -1; + if (channel_num < CHANNEL_0 || channel_num > CHANNEL_3) + return -1; + + u_rcr.reg_data = readl(&i2s[device_num]->channel[channel_num].rcr); + u_rcr.rcr_tcr.wlen = word_length; + writel(u_rcr.reg_data, &i2s[device_num]->channel[channel_num].rcr); + return 0; +} + +int i2s_set_tx_word_length(enum i2s_device_num_t device_num, + enum word_length_t word_length, + enum i2s_channel_num_t channel_num) +{ + union rcr_tcr_u u_tcr; + + if (word_length > RESOLUTION_32_BIT || word_length < IGNORE_WORD_LENGTH) + return -1; + if (channel_num < CHANNEL_0 || channel_num > CHANNEL_3) + return -1; + + u_tcr.reg_data = readl(&i2s[device_num]->channel[channel_num].tcr); + u_tcr.rcr_tcr.wlen = word_length; + writel(u_tcr.reg_data, &i2s[device_num]->channel[channel_num].tcr); + return 0; +} + +int i2s_master_configure(enum i2s_device_num_t device_num, + enum word_select_cycles_t word_select_size, + enum sclk_gating_cycles_t gating_cycles, + enum i2s_work_mode_t word_mode) +{ + union ccr_u u_ccr; + union cer_u u_cer; + + if (word_select_size < SCLK_CYCLES_16 || + word_select_size > SCLK_CYCLES_32) + return -1; + if (gating_cycles < NO_CLOCK_GATING || + gating_cycles > CLOCK_CYCLES_24) + return -1; + + u_ccr.reg_data = readl(&i2s[device_num]->ccr); + u_ccr.ccr.clk_word_size = word_select_size; + u_ccr.ccr.clk_gate = gating_cycles; + u_ccr.ccr.align_mode = word_mode; + writel(u_ccr.reg_data, &i2s[device_num]->ccr); + + u_cer.reg_data = readl(&i2s[device_num]->cer); + u_cer.cer.clken = 1; + writel(u_cer.reg_data, &i2s[device_num]->cer); + /* Clock generation enable */ + + return 0; +} + +int i2s_set_rx_threshold(enum i2s_device_num_t device_num, + enum fifo_threshold_t threshold, + enum i2s_channel_num_t channel_num) +{ + union rfcr_u u_rfcr; + + if (threshold < TRIGGER_LEVEL_1 || threshold > TRIGGER_LEVEL_16) + return -1; + if (channel_num < CHANNEL_0 || channel_num > CHANNEL_3) + return -1; + + u_rfcr.reg_data = readl(&i2s[device_num]->channel[channel_num].rfcr); + u_rfcr.rfcr.rxchdt = threshold; + writel(u_rfcr.reg_data, &i2s[device_num]->channel[channel_num].rfcr); + + return 0; +} + +int i2s_set_tx_threshold(enum i2s_device_num_t device_num, + enum fifo_threshold_t threshold, + enum i2s_channel_num_t channel_num) +{ + union tfcr_u u_tfcr; + + if (threshold < TRIGGER_LEVEL_1 || threshold > TRIGGER_LEVEL_16) + return -1; + if (channel_num < CHANNEL_0 || channel_num > CHANNEL_3) + return -1; + + u_tfcr.reg_data = readl(&i2s[device_num]->channel[channel_num].tfcr); + u_tfcr.tfcr.txchet = threshold; + writel(u_tfcr.reg_data, &i2s[device_num]->channel[channel_num].tfcr); + return 0; +} + +int i2s_set_mask_interrupt(enum i2s_device_num_t device_num, + enum i2s_channel_num_t channel_num, + uint32_t rx_available_int, uint32_t rx_overrun_int, + uint32_t tx_empty_int, uint32_t tx_overrun_int) +{ + union imr_u u_imr; + + if (channel_num < CHANNEL_0 || channel_num > CHANNEL_3) + return -1; + u_imr.reg_data = readl(&i2s[device_num]->channel[channel_num].imr); + + if (rx_available_int == 1) + u_imr.imr.rxdam = 1; + else + u_imr.imr.rxdam = 0; + if (rx_overrun_int == 1) + u_imr.imr.rxfom = 1; + else + u_imr.imr.rxfom = 0; + + if (tx_empty_int == 1) + u_imr.imr.txfem = 1; + else + u_imr.imr.txfem = 0; + if (tx_overrun_int == 1) + u_imr.imr.txfom = 1; + else + u_imr.imr.txfom = 0; + writel(u_imr.reg_data, &i2s[device_num]->channel[channel_num].imr); + return 0; +} + +int i2s_receive_channel_enable(enum i2s_device_num_t device_num, + enum i2s_channel_num_t channel_num, uint32_t enable) +{ + union rer_u u_rer; + + if (channel_num < CHANNEL_0 || channel_num > CHANNEL_3) + return -1; + u_rer.reg_data = readl(&i2s[device_num]->channel[channel_num].rer); + u_rer.rer.rxchenx = enable; + writel(u_rer.reg_data, &i2s[device_num]->channel[channel_num].rer); + return 0; +} + +int i2s_transmit_channel_enable(enum i2s_device_num_t device_num, + enum i2s_channel_num_t channel_num, uint32_t enable) +{ + union ter_u u_ter; + + if (channel_num < CHANNEL_0 || channel_num > CHANNEL_3) + return -1; + + u_ter.reg_data = readl(&i2s[device_num]->channel[channel_num].ter); + u_ter.ter.txchenx = enable; + writel(u_ter.reg_data, &i2s[device_num]->channel[channel_num].ter); + return 0; +} + +int i2s_transmit_dma_enable(enum i2s_device_num_t device_num, uint32_t enable) +{ + union ccr_u u_ccr; + + if (device_num >= I2S_DEVICE_MAX) + return -1; + + u_ccr.reg_data = readl(&i2s[device_num]->ccr); + u_ccr.ccr.dma_tx_en = enable; + writel(u_ccr.reg_data, &i2s[device_num]->ccr); + + return 0; +} + +int i2s_receive_dma_enable(enum i2s_device_num_t device_num, uint32_t enable) +{ + union ccr_u u_ccr; + + if (device_num >= I2S_DEVICE_MAX) + return -1; + + u_ccr.reg_data = readl(&i2s[device_num]->ccr); + u_ccr.ccr.dma_rx_en = enable; + writel(u_ccr.reg_data, &i2s[device_num]->ccr); + + return 0; +} + +int i2s_transmit_dma_divide(enum i2s_device_num_t device_num, uint32_t enable) +{ + union ccr_u u_ccr; + + if (device_num >= I2S_DEVICE_MAX) + return -1; + + u_ccr.reg_data = readl(&i2s[device_num]->ccr); + u_ccr.ccr.dma_divide_16 = enable; + writel(u_ccr.reg_data, &i2s[device_num]->ccr); + + return 0; +} + +int32_t i2s_receive_data(enum i2s_device_num_t device_num, + enum i2s_channel_num_t channel_num, uint64_t *buf, + uint32_t length) +{ + uint32_t i = 0; + union isr_u u_isr; + + readl(&i2s[device_num]->channel[channel_num].ror); + /*clear over run*/ + + for (i = 0; i < length;) + { + u_isr.reg_data = readl(&i2s[device_num]->channel[channel_num].isr); + if (u_isr.isr.rxda == 1) + { + buf[i] = readl(&i2s[device_num]->channel[channel_num].left_rxtx); + buf[i] <<= 32; + buf[i++] |= readl(&i2s[device_num]->channel[channel_num].right_rxtx); + } + } + return 0; +} + +int32_t i2s_receive_data_dma(enum i2s_device_num_t device_num, uint32_t *buf, + uint32_t length, dmac_channel_number channel_num) +{ + sysctl_dma_select(channel_num, SYSCTL_DMA_SELECT_I2S0_RX_REQ + device_num * 2); + dmac_set_single_mode(channel_num, (void *)(&i2s[device_num]->rxdma), /*pcm*/buf, DMAC_ADDR_NOCHANGE, DMAC_ADDR_INCREMENT, + DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, length); + dmac_wait_done(channel_num); + return 0; +} + +int32_t i2s_recv_dma(enum i2s_device_num_t device_num, uint32_t *buf, + uint32_t length, dmac_channel_number channel_num) +{ + static uint8_t dmac_recv_flag[6] = {0,0,0,0,0,0}; + if(dmac_recv_flag[channel_num]) + dmac_wait_done(channel_num); + else + dmac_recv_flag[channel_num] = 1; + sysctl_dma_select(channel_num, SYSCTL_DMA_SELECT_I2S0_RX_REQ + device_num * 2); + dmac_set_single_mode(channel_num, (void *)(&i2s[device_num]->rxdma), /*pcm*/buf, DMAC_ADDR_NOCHANGE, DMAC_ADDR_INCREMENT, + DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, length); + return 0; +} + +int32_t i2s_special_dma(enum i2s_device_num_t device_src_num, enum i2s_device_num_t device_dest_num, + uint32_t length, dmac_channel_number channel_num) +{ + static uint8_t dmac_recv_flag[6] = {0,0,0,0,0,0}; + if(dmac_recv_flag[channel_num]) + dmac_wait_done(channel_num); + else + dmac_recv_flag[channel_num] = 1; + sysctl_dma_select(channel_num, SYSCTL_DMA_SELECT_I2S0_RX_REQ + device_src_num * 2); + dmac_set_single_mode(channel_num, (void *)(&i2s[device_src_num]->rxdma), (void *)(&i2s[device_dest_num]->txdma), DMAC_ADDR_NOCHANGE, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, length); + return 0; +} + +int i2s_transmit_data(enum i2s_device_num_t device_num, + enum i2s_channel_num_t channel_num, uint8_t *pcm, uint32_t length, uint8_t single_length) +{ + union isr_u u_isr; + uint32_t left_buffer = 0; + uint32_t right_buffer = 0; + uint32_t i = 0; + uint32_t j = 0; + if (channel_num < CHANNEL_0 || channel_num > CHANNEL_3) + return -1; + + length = length / (single_length / 8) / 2; /* sample num */ + readl(&i2s[device_num]->channel[channel_num].tor); + /* read clear overrun flag */ + + for (j = 0; j < length;) + { + u_isr.reg_data = readl(&i2s[device_num]->channel[channel_num].isr); + if (u_isr.isr.txfe == 1) + { + switch(single_length) + { + case 16: + left_buffer = ((uint16_t *)pcm)[i++]; + right_buffer = ((uint16_t *)pcm)[i++]; + break; + case 24: + left_buffer = 0; + left_buffer |= pcm[i++]; + left_buffer |= pcm[i++] << 8; + left_buffer |= pcm[i++] << 16; + right_buffer = 0; + right_buffer |= pcm[i++]; + right_buffer |= pcm[i++] << 8; + right_buffer |= pcm[i++] << 16; + break; + case 32: + left_buffer = ((uint32_t *)pcm)[i++]; + right_buffer = ((uint32_t *)pcm)[i++]; + break; + default: + left_buffer = pcm[i++]; + right_buffer = pcm[i++]; + break; + } + writel(left_buffer, &i2s[device_num]->channel[channel_num].left_rxtx); + writel(right_buffer, &i2s[device_num]->channel[channel_num].right_rxtx); + j++; + } + } + return 0; +} + +int i2s_trans_data(enum i2s_device_num_t device_num,enum i2s_channel_num_t channel_num, + uint8_t *pcm, uint32_t length, uint8_t single_length, uint8_t track_num) +{ + union isr_u u_isr; + uint32_t left_buffer = 0; + uint32_t right_buffer = 0; + uint32_t i = 0; + uint32_t j = 0; + if (channel_num < CHANNEL_0 || channel_num > CHANNEL_3) + return -1; + readl(&i2s[device_num]->channel[channel_num].tor); + /* read clear overrun flag */ + + for (j = 0; j < length;) + { + u_isr.reg_data = readl(&i2s[device_num]->channel[channel_num].isr); + if (u_isr.isr.txfe == 1) + { + switch(single_length) + { + case 16: + left_buffer = ((uint16_t *)pcm)[i++]; + track_num == 2 ? (right_buffer = ((uint16_t *)pcm)[i++]) : (right_buffer = 0); + break; + case 24: + left_buffer = 0; + left_buffer |= pcm[i++]; + left_buffer |= pcm[i++] << 8; + left_buffer |= pcm[i++] << 16; + right_buffer = 0; + if(track_num == 2) + { + right_buffer |= pcm[i++]; + right_buffer |= pcm[i++] << 8; + right_buffer |= pcm[i++] << 16; + } + break; + case 32: + left_buffer = ((uint32_t *)pcm)[i++]; + track_num == 2 ? (right_buffer = ((uint32_t *)pcm)[i++]) : (right_buffer = 0); + break; + default: + left_buffer = pcm[i++]; + track_num == 2 ? (right_buffer = pcm[i++]) : (right_buffer = 0); + break; + } + writel(left_buffer, &i2s[device_num]->channel[channel_num].left_rxtx); + writel(right_buffer, &i2s[device_num]->channel[channel_num].right_rxtx); + j ++; + } + } + return 0; +} + +int i2s_transmit_data_dma(enum i2s_device_num_t device_num, + void *pcm, uint32_t length, uint8_t single_length, dmac_channel_number channel_num) +{ + length = length / (single_length / 8) / 2; + sysctl_dma_select(channel_num, SYSCTL_DMA_SELECT_I2S0_TX_REQ + device_num * 2); + dmac_set_single_mode(channel_num, pcm/*buf*/, (void *)(&i2s[device_num]->txdma), DMAC_ADDR_INCREMENT, + DMAC_ADDR_NOCHANGE,DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, length); + dmac_wait_done(channel_num); + return 0; +} + +void i2s_send_data_dma(enum i2s_device_num_t device_num, + void *pcm, uint32_t length, dmac_channel_number channel_num) +{ + static uint8_t dmac_init_flag[6] = {0,0,0,0,0,0}; + if(dmac_init_flag[channel_num]) + dmac_wait_done(channel_num); + else + dmac_init_flag[channel_num] = 1; + sysctl_dma_select(channel_num, SYSCTL_DMA_SELECT_I2S0_TX_REQ + device_num * 2); + dmac_set_single_mode(channel_num, pcm, (void *)(&i2s[device_num]->txdma), DMAC_ADDR_INCREMENT, + DMAC_ADDR_NOCHANGE, DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, length); +} + +void parse_voice(uint32_t *buf, uint8_t *pcm, uint32_t length, uint32_t bits_per_sample, + uint8_t track_num, uint32_t *send_len) +{ + uint32_t i,j=0; + *send_len = length * 2; + switch(bits_per_sample) + { + case 16: + i2s_transmit_dma_divide(I2S_DEVICE_0, 1); + for(i = 0; i < length; i++) + { + buf[i] = ((uint16_t *)pcm)[i]; + } + *send_len = length; + break; + case 24: + for(i = 0; i < length; i++) + { + buf[2*i] = 0; + buf[2*i] |= pcm[j++]; + buf[2*i] |= pcm[j++] << 8; + buf[2*i] |= pcm[j++] << 16; + buf[2*i+1] = 0; + if(track_num == 2) + { + buf[2*i+1] |= pcm[j++]; + buf[2*i+1] |= pcm[j++] << 8; + buf[2*i+1] |= pcm[j++] << 16; + } + } + break; + case 32: + for(i = 0; i < length; i++) + { + buf[2*i] = ((uint32_t *)pcm)[i]; + buf[2*i+1] = 0; + } + break; + default: + break; + } +} + +int i2s_play(enum i2s_device_num_t device_num,dmac_channel_number channel_num, + uint8_t *buf, size_t length, uint32_t frame, uint32_t bits_per_sample, uint8_t track_num) +{ + uint32_t sample_cnt = length / ( bits_per_sample / 8 ) / track_num; + uint32_t frame_cnt = sample_cnt / frame; + uint32_t frame_remain = sample_cnt % frame; + uint32_t i; + uint8_t *trans_buf; + + if (bits_per_sample == 16 && track_num == 2) + { + for (i = 0; i < frame_cnt; i++) + { + trans_buf = buf + i * frame * (bits_per_sample / 8) * track_num; + i2s_send_data_dma(device_num,trans_buf, frame, channel_num); + } + if(frame_remain) + { + trans_buf = buf + frame_cnt * frame * (bits_per_sample / 8) * track_num; + i2s_send_data_dma(device_num, trans_buf, frame_remain, channel_num); + } + } + else if (bits_per_sample == 32 && track_num == 2) + { + for (i = 0; i < frame_cnt; i++) + { + trans_buf = buf + i * frame * (bits_per_sample / 8) * track_num; + i2s_send_data_dma(device_num,trans_buf, frame * 2, channel_num); + } + if(frame_remain) + { + trans_buf = buf + frame_cnt * frame * (bits_per_sample / 8) * track_num; + i2s_send_data_dma(device_num, trans_buf, frame_remain * 2, channel_num); + } + } + else + { + uint32_t *buff[2]; + buff[0] = malloc(frame * 2 * sizeof(uint32_t) * 2); + buff[1] = buff[0] + frame * 2; + uint8_t flag = 0; + uint32_t send_len = 0; + for (i = 0; i < frame_cnt; i++) + { + trans_buf = buf + i * frame * (bits_per_sample / 8) * track_num; + parse_voice(buff[flag], trans_buf, frame, bits_per_sample, track_num, &send_len); + i2s_send_data_dma(device_num,buff[flag], send_len, channel_num); + flag = !flag; + } + if (frame_remain) + { + trans_buf = buf + frame_cnt * frame * (bits_per_sample / 8) * track_num; + parse_voice(buff[flag], trans_buf, frame_remain, bits_per_sample, track_num, &send_len); + i2s_send_data_dma(device_num, trans_buf, send_len, channel_num); + } + free(buff[0]); + } + return 0; +} + diff --git a/lib/drivers/include/aes.h b/lib/drivers/include/aes.h new file mode 100644 index 0000000..5aa86ff --- /dev/null +++ b/lib/drivers/include/aes.h @@ -0,0 +1,257 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _DRIVER_AES_H +#define _DRIVER_AES_H + +#include +#include "env/encoding.h" +#include "platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _aes_mode_ctl +{ + /* set the first bit and second bit 00:ecb; 01:cbc,10:aes_gcm */ + uint32_t cipher_mode : 3; + /* [4:3]:00:128; 01:192; 10:256;11:reserved*/ + uint32_t kmode : 2; + uint32_t endian : 6; + uint32_t stream_mode : 3; + uint32_t reserved : 18; +} __attribute__((packed, aligned(4))) aes_mode_ctl; + +/** + * @brief AES + */ +typedef struct _aes +{ + uint32_t aes_key[4]; + /* 0: encrption ; 1: dencrption */ + uint32_t encrypt_sel; + /** + * [1:0], Set the first bit and second bit 00:ecb; 01:cbc; + * 10,11:aes_gcm + */ + aes_mode_ctl mode_ctl; + uint32_t aes_iv[4]; + /* aes interrupt enable */ + uint32_t aes_endian; + /* aes interrupt flag */ + uint32_t aes_finish; + /* gcm add data begin address */ + uint32_t dma_sel; + /* gcm add data end address */ + uint32_t gb_aad_end_adr; + /* gcm plantext/ciphter text data begin address */ + uint32_t gb_pc_ini_adr; + /* gcm plantext/ciphter text data end address */ + uint32_t gb_pc_end_adr; + /* gcm plantext/ciphter text data */ + uint32_t aes_text_data; + /* AAD data */ + uint32_t aes_aad_data; + /** + * [1:0],00:check not finish; 01: check fail; 10: check success;11: + * reversed + */ + uint32_t tag_chk; + /* data can input flag 1: data can input; 0 : data cannot input */ + uint32_t data_in_flag; + /* gcm input tag for compare with the calculate tag */ + uint32_t gcm_in_tag[4]; + /* gcm plantext/ciphter text data */ + uint32_t aes_out_data; + uint32_t gb_aes_en; + /* data can output flag 1: data ready 0: data not ready */ + uint32_t data_out_flag; + /* allow tag input when use GCM */ + uint32_t tag_in_flag; + uint32_t tag_clear; + uint32_t gcm_out_tag[4]; + uint32_t aes_key_ext[4]; +} __attribute__((packed, aligned(4))) aes_t; + +enum aes_cipher_mod +{ + AES_ECB = 0, + AES_CBC = 1, + AES_GCM = 2, +}; + +enum aes_kmode +{ + AES_128 = 0, + AES_192 = 1, + AES_256 = 2, +}; + +enum aes_encrypt_sel +{ + AES_ENCRYPTION = 0, + AES_DECRYPTION = 1, +}; + +/** + * @brief Aes initialize + * + * @param[in] key_addr Key address + * @param[in] key_length Key length + * @param[in] aes_iv Aes iv + * @param[in] iv_length Iv length + * @param[in] aes_aad Aes aad + * @param[in] cipher_mod Aes cipher mode + * @param[in] encrypt_sel Aes encrypt select + * @param[in] add_size Aad size + * @param[in] data_size Data size + * + * @return result + * - 1 Success + * - Other Fail + */ +int aes_init(uint8_t* key_addr, uint8_t key_length, uint8_t* aes_iv, + uint8_t iv_length, uint8_t* aes_aad, enum aes_cipher_mod cipher_mod, + enum aes_encrypt_sel encrypt_sel, uint32_t add_size, uint32_t data_size); + +/** + * @brief Aes write aad data + * + * @param[in] aad_data Aes aad data + * + * @return result + * - 0 Success + * - Other Fail + */ +int aes_write_aad(uint32_t aad_data); + +/** + * @brief Aes write text data + * + * @param[in] text_data Aes aad data + * + * @return result + * - 0 Success + * - Other Fail + */ +int aes_write_text(uint32_t text_data); + +/** + * @brief Aes write tag + * + * @param[in] text_data Aes tag point + * + * @return result + * - 0 Success + * - Other Fail + */ +int aes_write_tag(uint32_t* tag); + +/** + * @brief Aes get data in flag + * + * @return Data in flag + */ +int aes_get_data_in_flag(void); + +/** + * @brief Aes get data out flag + * + * @return Data out flag + */ +int aes_get_data_out_flag(void); + +/** + * @brief Aes get tag in flag + * + * @return Tag in flag + */ +int aes_get_tag_in_flag(void); + +/** + * @brief Aes read out data + * + * @return Out data + */ +uint32_t aes_read_out_data(void); + +/** + * @brief Aes check tag + * + * @return Tag check result + * - 0 Check not finish + * - 1 Check fail + * - 2 Check success + */ +int aes_check_tag(void); + +/** + * @brief Aes get gcm out tag + * + * @param[out] l_tag gcm out tag + * + * @return Tag check result + * - 1 Success + * - Other Fail + */ +int aes_get_tag(uint8_t* l_tag); + +/** + * @brief Aes clear check tag + * + * @return Tag check result + * - 0 Success + * - Other Fail + */ +int aes_clear_chk_tag(void); + +/** + * @brief Aes process + * + * @param[in] aes_in_data Aes in data + * @param[in] aes_out_data Aes out data + * @param[in] data_size Aes data size + * @param[in] cipher_mod Aes cipher mode + * + * @return Tag check result + * - 1 Success + * - Other Fail + */ +int aes_process(uint8_t* aes_in_data, + uint8_t* aes_out_data, + uint32_t data_size, + enum aes_cipher_mod cipher_mod); + +/** + * @brief Aes check gcm tag + * + * @param[in] aes_gcm_tag Aes gcm tag + * + * @return Tag check result + * - 1 Success + * - Other Fail + */ +int aes_check_gcm_tag(uint32_t* aes_gcm_tag); + +/** + * @brief Aes clock initialize + */ +void aes_clkinit(); + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_AES_H */ diff --git a/lib/drivers/include/audio_bf.h b/lib/drivers/include/audio_bf.h new file mode 100644 index 0000000..3c992eb --- /dev/null +++ b/lib/drivers/include/audio_bf.h @@ -0,0 +1,329 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _DRIVER_AUDIO_BF_H +#define _DRIVER_AUDIO_BF_H + +#ifdef __cplusplus +extern "C" { +#endif + +extern volatile struct audio_bf_reg_t* const audio_bf; + +enum en_bf_dir +{ + BF_DIR0 = 0, + BF_DIR1, + BF_DIR2, + BF_DIR3, + BF_DIR4, + BF_DIR5, + BF_DIR6, + BF_DIR7, + BF_DIR8, + BF_DIR9, + BF_DIR10, + BF_DIR11, + BF_DIR12, + BF_DIR13, + BF_DIR14, + BF_DIR15, +}; + +struct audio_bf_ch_cfg_t +{ + /** + * BF unit sound channel enable control bits. + * Bit 'x' corresponds to enable bit for sound channel 'x' (x = 0, 1, 2, + * . . ., 7). BF sound channels are related with I2S host RX channels. + * BF sound channel 0/1 correspond to the left/right channel of I2S RX0; + * BF channel 2/3 correspond to left/right channels of I2S RX1; and + * things like that. 0x1: writing '1' to enable the corresponding BF + * sound channel. 0x0: writing '0' to close the corresponding BF sound + * channel. + */ + uint32_t bf_sound_ch_en : 8; + /** + * Target direction select for valid voice output. + * When the source voice direaction searching is done, software can use + * this field to select one from 16 sound directions for the following + * voice recognition. 0x0: select sound direction 0; 0x1: select sound + * direction 1; . . . . . . 0xF: select sound direction 15. + */ + uint32_t bf_target_dir : 4; + /** + * This is the audio sample gain factor. Using this gain factor to + * enhance or reduce the stength of the sum of at most 8 source + * sound channel outputs. This is a unsigned 11-bit fix-point number, + * bit 10 is integer part and bit 9~0 are the fractional part. + */ + uint32_t audio_gain : 11; + uint32_t reserved1 : 1; + /** + * audio data source configure parameter. This parameter controls where + * the audio data source comes from. 0x0: audio data directly sourcing + * from audio_bf internal buffer; 0x1: audio data sourcing from + * FFT result buffer. + */ + uint32_t data_src_mode : 1; + uint32_t reserved2 : 3; + /** + * write enable for bf_sound_ch_en parameter. + * 0x1: allowing updates made to 'bf_sound_ch_en'. + * Access Mode: write only + */ + uint32_t we_bf_sound_ch_en : 1; + /** + * write enable for bf_target_dir parameter. + * 0x1: allowing updates made to 'bf_target_dir'. + * Access Mode: write only + */ + uint32_t we_bf_target_dir : 1; + /** + * write enable for audio_gain parameter. + * 0x1: allowing updates made to 'audio_gain'. + * Access Mode: write only + */ + uint32_t we_audio_gain : 1; + /** + * write enable for data_out_mode parameter. + * 0x1: allowing updates made to 'data_src_mode'. + */ + uint32_t we_data_src_mode : 1; +} __attribute__((packed, aligned(4))); + +struct audio_bf_ctl_t +{ + /** + * Sound direction searching enable bit. + * Software writes '1' to start sound direction searching function. + * When all the sound sample buffers are filled full, this bit is + * cleared by hardware (this sample buffers are used for direction + * detect only). 0x1: enable direction searching. + */ + uint32_t bf_dir_search_en : 1; + /* + *use this parameter to reset all the control logic on direction search processing path. This bit is self-clearing. + * 0x1: apply reset to direction searching control logic; + * 0x0: No operation. + */ + uint32_t search_path_reset : 1; + uint32_t reserved : 2; + /** + * Valid voice sample stream generation enable bit. + * After sound direction searching is done, software can configure this + * bit to generate a stream of voice samples for voice recognition. 0x1: + * enable output of voice sample stream. 0x0: stop the voice samlpe + * stream output. + */ + uint32_t bf_stream_gen_en : 1; + /* + *use this parameter to reset all the control logic on voice stream generating path. This bit is self-clearing. + * 0x1: apply reset to voice stream generating control logic; + * 0x0: No operation. + */ + uint32_t voice_gen_path_reset : 1; + /* + *use this parameter to switch to a new voice source direction. Software write '1' here and hardware will automatically clear it. + * 0x1: write '1' here to request switching to new voice source direction. + */ + uint32_t update_voice_dir : 1; + + uint32_t reserved1 : 1; + //write enable for 'bf_dir_search_en' parameter. + uint32_t we_bf_dir_search_en : 1; + uint32_t we_search_path_rst : 1; + uint32_t we_bf_stream_gen : 1; + uint32_t we_voice_gen_path_rst : 1; + uint32_t we_update_voice_dir : 1; + uint32_t reserved2 : 19; + +} __attribute__((packed, aligned(4))); + +struct audio_bf_dir_bidx_t +{ + uint32_t dir_rd_idx0 : 6; + uint32_t reserved : 2; + uint32_t dir_rd_idx1 : 6; + uint32_t reserved1 : 2; + uint32_t dir_rd_idx2 : 6; + uint32_t reserved2 : 2; + uint32_t dir_rd_idx3 : 6; + uint32_t reserved3 : 2; +} __attribute__((packed, aligned(4))); + +struct audio_bf_fir_coef_t +{ + uint32_t fir_tap0 : 16; + uint32_t fir_tap1 : 16; +} __attribute__((packed, aligned(4))); + +struct audio_bf_dwsz_cfg_t +{ + /** + * TThe down-sizing ratio used for direction searching. + * 0x0: no down-sizing; + * 0x1: 1/2 down sizing; + * 0x2: 1/3 down sizing; + * . . . . . . + * 0xF: 1/16 down sizing. + */ + uint32_t dir_dwn_siz_rate : 4; + /** + * The down-sizing ratio used for voice stream generation. + * 0x0: no down-sizing; + * 0x1: 1/2 down sizing; + * 0x2: 1/3 down sizing; + * . . . . . . + * 0xF: 1/16 down sizing. + */ + uint32_t voc_dwn_siz_rate : 4; + /** + * This bit field is used to perform sample precision reduction when + * the source sound sample (from I2S0 host receiving channels) + * precision is 20/24/32 bits. + * 0x0: take bits 15~0 from the source sound sample; + * 0x1: take bits 16~1 from the source sound sample; + * 0x2: take bits 17~2 from the source sound sample; + * . . . . . . + * 0x10: take bits 31~16 from the source sound sample; + */ + uint32_t smpl_shift_bits : 5; + uint32_t reserved : 19; +} __attribute__((packed, aligned(4))); + +struct audio_bf_fft_cfg_t +{ + uint32_t fft_shift_factor : 9; + uint32_t reserved1 : 3; + uint32_t fft_enable : 1; + uint32_t reserved2 : 19; +} __attribute__((packed, aligned(4))); + +struct audio_bf_int_stat_t +{ + /** + * sound direction searching data ready interrupt event. + * Writing '1' to clear this interrupt event. + * 0x1: data is ready for sound direction detect; + * 0x0: no event. + */ + uint32_t dir_search_data_rdy : 1; + /** + * voice output stream buffer data ready interrupt event. + * When a block of 512 voice samples are collected, this interrupt event + * is asserted. Writing '1' to clear this interrupt event. 0x1: voice + * output stream buffer data is ready; 0x0: no event. + */ + uint32_t voc_buf_data_rdy : 1; + uint32_t reserved : 30; +} __attribute__((packed, aligned(4))); + +struct audio_bf_int_mask_t +{ + /** + * This is the interrupt mask to dir searching data ready interrupt. + * 0x1: mask off this interrupt; + * 0x0: enable this interrupt. + */ + uint32_t dir_data_rdy_msk : 1; + /** + * This is the interrupt mask to voice output stream buffer ready + * interrupt. 0x1: mask off this interrupt; 0x0: enable this interrupt. + */ + uint32_t voc_buf_rdy_msk : 1; + uint32_t reserved : 30; +} __attribute__((packed, aligned(4))); + +struct audio_bf_reg_t +{ + /* 0x200 */ + struct audio_bf_ch_cfg_t bf_ch_cfg_reg; + /* 0x204 */ + struct audio_bf_ctl_t bf_ctl_reg; + /* 0x208 */ + struct audio_bf_dir_bidx_t bf_dir_bidx[16][2]; + /* 0x288 */ + struct audio_bf_fir_coef_t bf_pre_fir0_coef[9]; + /* 0x2ac */ + struct audio_bf_fir_coef_t bf_post_fir0_coef[9]; + /* 0x2d0 */ + struct audio_bf_fir_coef_t bf_pre_fir1_coef[9]; + /* 0x2f4 */ + struct audio_bf_fir_coef_t bf_post_fir1_coef[9]; + /* 0x318 */ + struct audio_bf_dwsz_cfg_t bf_dwsz_cfg_reg; + /* 0x31c */ + struct audio_bf_fft_cfg_t bf_fft_cfg_reg; + /* 0x320 */ + /** + * This is the read register for system DMA to read data stored in + * sample out buffers (the sample out buffers are used for sound + * direction detect). Each data contains two sound samples. + */ + volatile uint32_t sobuf_dma_rdata; + /* 0x324 */ + /** + * This is the read register for system DMA to read data stored in voice + * out buffers (the voice out buffers are used for voice recognition). + * Each data contains two sound samples. + */ + volatile uint32_t vobuf_dma_rdata; + /* 0x328 */ + struct audio_bf_int_stat_t bf_int_stat_reg; + /* 0x32c */ + struct audio_bf_int_mask_t bf_int_mask_reg; + /* 0x330 */ + uint32_t saturation_counter; + /* 0x334 */ + uint32_t saturation_limits; +} __attribute__((packed, aligned(4))); + +void audio_bf_set_audio_gain(uint16_t gain); +void audio_bf_set_smpl_shift(uint8_t smpl_shift); +uint8_t audio_bf_get_smpl_shift(void); +void audio_bf_set_channel_enabled(uint8_t channel_bit); +void audio_bf_set_direction_delay(uint8_t dir_num, uint8_t* dir_bidx); +void audio_bf_set_fft_shift_factor(uint8_t enable_flag, uint16_t shift_factor); +void audio_bf_set_down_size(uint8_t dir_dwn_siz, uint8_t voc_dwn_siz); +void audio_bf_set_interrupt_mask(uint8_t dir_int_mask, uint8_t voc_int_mask); + +void audio_bf_dir_enable(void); +void audio_bf_dir_reset(void); +void audio_bf_dir_set_prev_fir(uint16_t* fir_coef); +void audio_bf_dir_set_post_fir(uint16_t* fir_coef); +void audio_bf_dir_set_down_size(uint8_t dir_dwn_size); +void audio_bf_dir_set_interrupt_mask(uint8_t dir_int_mask); +void audio_bf_dir_clear_int_state(void); + +void audio_bf_voc_enable(uint8_t enable_flag); +void audio_bf_voc_reset(void); +void audio_bf_voc_set_direction(enum en_bf_dir direction); +void audio_bf_voc_set_prev_fir(uint16_t* fir_coef); +void audio_bf_voc_set_post_fir(uint16_t* fir_coef); +void audio_bf_voc_set_down_size(uint8_t voc_dwn_size); +void audio_bf_voc_set_interrupt_mask(uint8_t voc_int_mask); +void audio_bf_voc_clear_int_state(void); +void audio_bf_voc_reset_saturation_counter(void); +uint32_t audio_bf_voc_get_saturation_counter(void); +void audio_bf_voc_set_saturation_limit(uint16_t upper, uint16_t bottom); +uint32_t audio_bf_voc_get_saturation_limit(void); + +void audio_bf_print_setting(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_AUDIO_BF_H */ diff --git a/lib/drivers/include/clint.h b/lib/drivers/include/clint.h new file mode 100644 index 0000000..f1fae7c --- /dev/null +++ b/lib/drivers/include/clint.h @@ -0,0 +1,323 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file + * @brief The CLINT block holds memory-mapped control and status registers + * associated with local interrupts for a Coreplex. + * + * @note CLINT RAM Layout + * + * | Address -| Description | + * |------------|---------------------------------| + * | 0x02000000 | msip for hart 0 | + * | 0x02000004 | msip for hart 1 | + * | ... | ... | + * | 0x02003FF8 | msip for hart 4094 | + * | | | + * | 0x02004000 | mtimecmp for hart 0 | + * | 0x02004008 | mtimecmp for hart 1 | + * | ... | ... | + * | 0x0200BFF0 | mtimecmp For hart 4094 | + * | 0x0200BFF8 | mtime | + * | | | + * | 0x0200C000 | Reserved | + * | ... | ... | + * | 0x0200EFFC | Reserved | + */ + +#ifndef _DRIVER_CLINT_H +#define _DRIVER_CLINT_H + +#include +#include +#include "platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* clang-format off */ +/* Register address offsets */ +#define CLINT_MSIP (0x0000) +#define CLINT_MSIP_SIZE (0x4) +#define CLINT_MTIMECMP (0x4000) +#define CLINT_MTIMECMP_SIZE (0x8) +#define CLINT_MTIME (0xBFF8) +#define CLINT_MTIME_SIZE (0x8) +/* Max number of cores */ +#define CLINT_MAX_HARTS (4095) +/* Real number of cores */ +#define CLINT_NUM_HARTS (2) +/* Clock frequency division factor */ +#define CLINT_CLOCK_DIV (50) +/* clang-format on */ + +/** + * @brief MSIP Registers + * + * Machine-mode software interrupts are generated by writing to a + * per-hart memory-mapped control register. The msip registers are + * 32-bit wide WARL registers, where the LSB is reflected in the + * msip bit of the associated hart’s mip register. Other bits in + * the msip registers are hardwired to zero. The mapping supports + * up to 4095 machine-mode harts. + */ +struct clint_msip_t +{ + uint32_t msip : 1; /*!< Bit 0 is msip */ + uint32_t zero : 31; /*!< Bits [32:1] is 0 */ +} __attribute__((packed, aligned(4))); + +/** + * @brief Timer compare Registers Machine-mode timer interrupts are + * generated by a real-time counter and a per-hart comparator. The + * mtime register is a 64-bit read-only register that contains the + * current value of the real-time counter. Each mtimecmp register + * holds its hart’s time comparator. A timer interrupt is pending + * whenever mtime is greater than or equal to the value in a + * hart’s mtimecmp register. The timer interrupt is reflected in + * the mtip bit of the associated hart’s mip register. + */ +typedef uint64_t clint_mtimecmp_t; + +/** + * @brief Timer Registers + * + * The mtime register has a 64-bit precision on all RV32, RV64, + * and RV128 systems. Platforms provide a 64-bit memory-mapped + * machine-mode timer compare register (mtimecmp), which causes a + * timer interrupt to be posted when the mtime register contains a + * value greater than or equal to the value in the mtimecmp + * register. The interrupt remains posted until it is cleared by + * writing the mtimecmp register. The interrupt will only be taken + * if interrupts are enabled and the MTIE bit is set in the mie + * register. + */ +typedef uint64_t clint_mtime_t; + +/** + * @brief CLINT object + * + * Coreplex-Local INTerrupts, which includes software interrupts, + * local timer interrupts, and other interrupts routed directly to + * a core. + */ +struct clint_t +{ + /* 0x0000 to 0x3FF8, MSIP Registers */ + struct clint_msip_t msip[CLINT_MAX_HARTS]; + /* Resverd space, do not use */ + uint32_t resv0; + /* 0x4000 to 0xBFF0, Timer Compare Registers */ + clint_mtimecmp_t mtimecmp[CLINT_MAX_HARTS]; + /* 0xBFF8, Time Register */ + clint_mtime_t mtime; +} __attribute__((packed, aligned(4))); + +/** + * @brief Clint object instanse + */ +extern volatile struct clint_t* const clint; + +/** + * @brief Definitions for the timer callbacks + */ +typedef int (*clint_timer_callback_t)(void* ctx); + +/** + * @brief Definitions for local interprocessor interrupt callbacks + */ +typedef int (*clint_ipi_callback_t)(void* ctx); + +/** + * @brief Get the time form CLINT timer register + * + * @note The CLINT must init to get right time + * + * @return 64bit Time + */ +uint64_t clint_get_time(void); + +/** + * @brief Init the CLINT timer + * + * @note MIP_MTIP will be clear after init. The MSTATUS_MIE must set by + * user. + * + * @return result + * - 0 Success + * - Other Fail + */ +int clint_timer_init(void); + +/** + * @brief Stop the CLINT timer + * + * @note MIP_MTIP will be clear after stop + * + * @return result + * - 0 Success + * - Other Fail + */ +int clint_timer_stop(void); + +/** + * @brief Start the CLINT timer + * + * @param[in] interval The interval with Millisecond(ms) + * @param[in] single_shot Single shot or repeat + * + * @return result + * - 0 Success + * - Other Fail + */ +int clint_timer_start(uint64_t interval, int single_shot); + +/** + * @brief Get the interval of timer + * + * @return The interval with Millisecond(ms) + */ +uint64_t clint_timer_get_interval(void); + +/** + * @brief Set the interval with Millisecond(ms) + * + * @param[in] interval The interval with Millisecond(ms) + * + * @return result + * - 0 Success + * - Other Fail + */ +int clint_timer_set_interval(uint64_t interval); + +/** + * @brief Get whether the timer is a single shot timer + * + * @return result + * - 0 It is a repeat timer + * - 1 It is a single shot timer + */ +int clint_timer_get_single_shot(void); + +/** + * @brief Set the timer working as a single shot timer or repeat timer + * + * @param[in] single_shot Single shot or repeat + * + * @return result + * - 0 Success + * - Other Fail + */ +int clint_timer_set_single_shot(int single_shot); + +/** + * @brief Set user callback function when timer is timeout + * + * @param[in] callback The callback function + * @param[in] ctx The context + * + * @return result + * - 0 Success + * - Other Fail + */ +int clint_timer_register(clint_timer_callback_t callback, void* ctx); + +/** + * @brief Deregister user callback function + * + * @return result + * - 0 Success + * - Other Fail + */ +int clint_timer_deregister(void); + +/** + * @brief Initialize local interprocessor interrupt + * + * @return result + * - 0 Success + * - Other Fail + */ +int clint_ipi_init(void); + +/** + * @brief Enable local interprocessor interrupt + * + * @return result + * - 0 Success + * - Other Fail + */ +int clint_ipi_enable(void); + +/** + * @brief Disable local interprocessor interrupt + * + * @return result + * - 0 Success + * - Other Fail + */ +int clint_ipi_disable(void); + +/** + * @brief Send local interprocessor interrupt to core by hart id + * + * @param[in] hart_id The hart identifier + * + * @return result + * - 0 Success + * - Other Fail + */ +int clint_ipi_send(size_t hart_id); + +/** + * @brief Clear local interprocessor interrupt + * + * @param[in] hart_id The hart identifier + * + * @return result + * - 1 An IPI was pending + * - 0 Non IPI was pending + * - -1 Fail + */ +int clint_ipi_clear(size_t hart_id); + +/** + * @brief Set user callback function when interprocessor interrupt + * + * @param[in] callback The callback function + * @param[in] ctx The context + * + * @return result + * - 0 Success + * - Other Fail + */ +int clint_ipi_register(clint_ipi_callback_t callback, void* ctx); + +/** + * @brief Deregister user callback function + * + * @return result + * - 0 Success + * - Other Fail + */ +int clint_ipi_deregister(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_CLINT_H */ + diff --git a/lib/drivers/include/common.h b/lib/drivers/include/common.h new file mode 100644 index 0000000..a72122a --- /dev/null +++ b/lib/drivers/include/common.h @@ -0,0 +1,357 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _DRIVER_COMMON_H +#define _DRIVER_COMMON_H + +#ifdef __cplusplus +#include +#include +#include +#else /* __cplusplus */ +#include +#include +#include +#include +#endif /* __cplusplus */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define KENDRYTE_MIN(a, b) ((a) > (b) ? (b) : (a)) +#define KENDRYTE_MAX(a, b) ((a) > (b) ? (a) : (b)) + +#ifdef __ASSEMBLY__ +#define KENDRYTE_CAST(type, ptr) ptr +#else /* __ASSEMBLY__ */ +/** + * @brief Cast the pointer to specified pointer type. + * + * @param[in] type The pointer type to cast to + * @param[in] ptr The pointer to apply the type cast to + */ +#define KENDRYTE_CAST(type, ptr) ((type)(ptr)) +#endif /* __ASSEMBLY__ */ + +/** + * @addtogroup UTIL_RW_FUNC Memory Read/Write Utilities + * + * This section implements read and write functionality for various + * memory untis. The memory unit terms used for these functions are + * consistent with those used in the ARM Architecture Reference Manual + * ARMv7-A and ARMv7-R edition manual. The terms used for units of memory are: + * + * Unit of Memory | Abbreviation | Size in Bits + * :---------------|:-------------|:------------: + * Byte | byte | 8 + * Half Word | hword | 16 + * Word | word | 32 + * Double Word | dword | 64 + * + */ + +/** + * @brief Write the 8 bit byte to the destination address in device memory. + * + * @param[in] dest Write destination pointer address + * @param[in] src 8 bit data byte to write to memory + */ +#define kendryte_write_byte(dest, src) \ + (*KENDRYTE_CAST(volatile uint8_t*, (dest)) = (src)) + +/** + * @brief Read and return the 8 bit byte from the source address in device memory. + * + * @param[in] src Read source pointer address + * + * @return 8 bit data byte value + */ +#define kendryte_read_byte(src) (*KENDRYTE_CAST(volatile uint8_t*, (src))) + +/** + * @brief Write the 16 bit half word to the destination address in device memory. + * + * @param[in] dest Write destination pointer address + * @param[in] src 16 bit data half word to write to memory + */ +#define kendryte_write_hword(dest, src) \ + (*KENDRYTE_CAST(volatile uint16_t*, (dest)) = (src)) + +/** + * @brief Read and return the 16 bit half word from the source address in device + * + * @param[in] src Read source pointer address + * + * @return 16 bit data half word value + */ +#define kendryte_read_hword(src) (*KENDRYTE_CAST(volatile uint16_t*, (src))) + +/** + * @brief Write the 32 bit word to the destination address in device memory. + * + * @param[in] dest Write destination pointer address + * @param[in] src 32 bit data word to write to memory + */ +#define kendryte_write_word(dest, src) \ + (*KENDRYTE_CAST(volatile uint32_t*, (dest)) = (src)) + +/** + * @brief Read and return the 32 bit word from the source address in device memory. + * + * @param[in] src Read source pointer address + * + * @return 32 bit data half word value + */ +#define kendryte_read_word(src) (*KENDRYTE_CAST(volatile uint32_t*, (src))) + +/** + * @brief Write the 64 bit double word to the destination address in device memory. + * + * @param[in] dest Write destination pointer address + * @param[in] src 64 bit data word to write to memory + */ +#define kendryte_write_dword(dest, src) \ + (*KENDRYTE_CAST(volatile uint64_t*, (dest)) = (src)) + +/** + * @brief Read and return the 64 bit double word from the source address in device + * + * @param[in] src Read source pointer address + * + * @return 64 bit data half word value + */ +#define kendryte_read_dword(src) (*KENDRYTE_CAST(volatile uint64_t*, (src))) + +/** + * @brief Set selected bits in the 8 bit byte at the destination address in device + * + * @param[in] dest Destination pointer address + * @param[in] bits Bits to set in destination byte + */ +#define kendryte_setbits_byte(dest, bits) \ + (kendryte_write_byte(dest, kendryte_read_byte(dest) | (bits))) + +/** + * @brief Clear selected bits in the 8 bit byte at the destination address in device + * + * @param[in] dest Destination pointer address + * @param[in] bits Bits to clear in destination byte + */ +#define kendryte_clrbits_byte(dest, bits) \ + (kendryte_write_byte(dest, kendryte_read_byte(dest) & ~(bits))) + +/** + * @brief Change or toggle selected bits in the 8 bit byte at the destination address + * + * @param[in] dest Destination pointer address + * @param[in] bits Bits to change in destination byte + */ +#define kendryte_xorbits_byte(dest, bits) \ + (kendryte_write_byte(dest, kendryte_read_byte(dest) ^ (bits))) + +/** + * @brief Replace selected bits in the 8 bit byte at the destination address in device + * + * @param[in] dest Destination pointer address + * @param[in] msk Bits to replace in destination byte + * @param[in] src Source bits to write to cleared bits in destination byte + */ +#define kendryte_replbits_byte(dest, msk, src) \ + (kendryte_write_byte(dest, (kendryte_read_byte(dest) & ~(msk)) | ((src) & (msk)))) + +/** + * @brief Set selected bits in the 16 bit halfword at the destination address in + * + * @param[in] dest Destination pointer address + * @param[in] bits Bits to set in destination halfword + */ +#define kendryte_setbits_hword(dest, bits) \ + (kendryte_write_hword(dest, kendryte_read_hword(dest) | (bits))) + +/** + * @brief Clear selected bits in the 16 bit halfword at the destination address in + * + * @param[in] dest Destination pointer address + * @param[in] bits Bits to clear in destination halfword + */ +#define kendryte_clrbits_hword(dest, bits) \ + (kendryte_write_hword(dest, kendryte_read_hword(dest) & ~(bits))) + +/** + * @brief Change or toggle selected bits in the 16 bit halfword at the destination + * + * @param[in] dest Destination pointer address + * @param[in] bits Bits to change in destination halfword + */ +#define kendryte_xorbits_hword(dest, bits) \ + (kendryte_write_hword(dest, kendryte_read_hword(dest) ^ (bits))) + +/** + * @brief Replace selected bits in the 16 bit halfword at the destination address in + * + * @param[in] dest Destination pointer address + * @param[in] msk Bits to replace in destination byte + * @param[in] src Source bits to write to cleared bits in destination halfword + */ +#define kendryte_replbits_hword(dest, msk, src) \ + (kendryte_write_hword(dest, (kendryte_read_hword(dest) & ~(msk)) | ((src) & (msk)))) + +/** + * @brief Set selected bits in the 32 bit word at the destination address in device + * + * @param[in] dest Destination pointer address + * @param[in] bits Bits to set in destination word + */ +#define kendryte_setbits_word(dest, bits) \ + (kendryte_write_word(dest, kendryte_read_word(dest) | (bits))) + +/** + * @brief Clear selected bits in the 32 bit word at the destination address in device + * + * @param[in] dest Destination pointer address + * @param[in] bits Bits to clear in destination word + */ +#define kendryte_clrbits_word(dest, bits) \ + (kendryte_write_word(dest, kendryte_read_word(dest) & ~(bits))) + +/** + * @brief Change or toggle selected bits in the 32 bit word at the destination address + * + * @param[in] dest Destination pointer address + * @param[in] bits Bits to change in destination word + */ +#define kendryte_xorbits_word(dest, bits) \ + (kendryte_write_word(dest, kendryte_read_word(dest) ^ (bits))) + +/** + * @brief Replace selected bits in the 32 bit word at the destination address in + * + * @param[in] dest Destination pointer address + * @param[in] msk Bits to replace in destination word + * @param[in] src Source bits to write to cleared bits in destination word + */ +#define kendryte_replbits_word(dest, msk, src) \ + (kendryte_write_word(dest, (kendryte_read_word(dest) & ~(msk)) | ((src) & (msk)))) + +/** + * @brief Set selected bits in the 64 bit doubleword at the destination address in + * + * @param[in] dest Destination pointer address + * @param[in] bits Bits to set in destination doubleword + */ +#define kendryte_setbits_dword(dest, bits) \ + (kendryte_write_dword(dest, kendryte_read_dword(dest) | (bits))) + +/** + * @brief Clear selected bits in the 64 bit doubleword at the destination address in + * + * @param[in] dest Destination pointer address + * @param[in] bits Bits to clear in destination doubleword + */ +#define kendryte_clrbits_dword(dest, bits) \ + (kendryte_write_dword(dest, kendryte_read_dword(dest) & ~(bits))) + +/** + * @brief Change or toggle selected bits in the 64 bit doubleword at the destination + * + * @param[in] dest Destination pointer address + * @param[in] bits Bits to change in destination doubleword + */ +#define kendryte_xorbits_dword(dest, bits) \ + (kendryte_write_dword(dest, kendryte_read_dword(dest) ^ (bits))) + +/** + * @brief Replace selected bits in the 64 bit doubleword at the destination address in + * + * @param[in] dest Destination pointer address + * @param[in] msk its to replace in destination doubleword + * @param[in] src Source bits to write to cleared bits in destination word + */ +#define kendryte_replbits_dword(dest, msk, src) \ + (kendryte_write_dword(dest, (kendryte_read_dword(dest) & ~(msk)) | ((src) & (msk)))) + +#define configASSERT(x) \ + if ((x) == 0) \ + { \ + printf("(%s:%d) %s", __FILE__, __LINE__, #x); \ + for (;;) \ + ; \ + } + +/** + * @brief Set value by mask + * + * @param[in] bits The one be set + * @param[in] mask mask value + * @param[in] value The value to set + */ +void set_bit(volatile uint32_t* bits, uint32_t mask, uint32_t value); + +/** + * @brief Set value by mask + * + * @param[in] bits The one be set + * @param[in] mask Mask value + * @param[in] offset Mask's offset + * @param[in] value The value to set + */ +void set_bit_offset(volatile uint32_t* bits, uint32_t mask, size_t offset, uint32_t value); + +/** + * @brief Set bit for gpio, only set one bit + * + * @param[in] bits The one be set + * @param[in] idx Offset value + * @param[in] value The value to set + */ +void set_gpio_bit(volatile uint32_t* bits, size_t idx, uint32_t value); + +/** + * @brief Get bits value of mask + * + * @param[in] bits The source data + * @param[in] mask Mask value + * @param[in] offset Mask's offset + * + * @return The bits value of mask + */ +uint32_t get_bit(volatile uint32_t* bits, uint32_t mask, size_t offset); + +/** + * @brief Get a bit value by offset + * + * @param[in] bits The source data + * @param[in] offset Bit's offset + * + * + * @return The bit value + */ +uint32_t get_gpio_bit(volatile uint32_t* bits, size_t offset); + +/** + * @brief Enable interrupt + */ +void machine_irq_enable(); + +/** + * @brief Disable interrupt + */ +void machine_irq_disable(); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* _DRIVER_COMMON_H */ + diff --git a/lib/drivers/include/dmac.h b/lib/drivers/include/dmac.h new file mode 100644 index 0000000..a78e6e1 --- /dev/null +++ b/lib/drivers/include/dmac.h @@ -0,0 +1,1686 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _DRIVER_DMAC_H +#define _DRIVER_DMAC_H + +#include +#include "io.h" +#include "platform.h" +#include "stdbool.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* DMAC */ +#define DMAC_CHANNEL_COUNT (DMAC_CHANNEL_MAX) +#define LAST_ROW (-1) + +typedef enum _dmac_channel_number +{ + DMAC_CHANNEL0 = 0, + DMAC_CHANNEL1 = 1, + DMAC_CHANNEL2 = 2, + DMAC_CHANNEL3 = 3, + DMAC_CHANNEL4 = 4, + DMAC_CHANNEL5 = 5, + DMAC_CHANNEL_MAX +} dmac_channel_number; + +typedef enum _dmac_src_dst_select +{ + DMAC_SRC = 0x1, + DMAC_DST = 0x2, + DMAC_SRC_DST = 0x3 +} dmac_src_dst_select; + +typedef enum _state_value +{ + clear = 0, + set = 1 +} state_value; + +enum dmac_lock_bus_ch +{ + DMAC_LOCK_BUS = 0x1, + DMAC_LOCK_CHANNEL = 0x2, + DMAC_LOCK_BUS_CH = 0x3 +}; + +enum dmac_sw_hw_hs_select +{ + DMAC_HS_HARDWARE = 0x0, + DMAC_HS_SOFTWARE = 0x1 +}; + +enum dmac_scatter_gather_param +{ + DMAC_SG_COUNT = 0x0, + DMAC_SG_INTERVAL = 0x1 +}; + +enum dmac_irq +{ + /* no interrupts */ + DMAC_IRQ_NONE = 0x00, + /* transfer complete */ + DMAC_IRQ_TFR = 0x01, + /* block transfer complete */ + DMAC_IRQ_BLOCK = 0x02, + /* source transaction complete */ + DMAC_IRQ_SRCTRAN = 0x04, + /* destination transaction complete */ + DMAC_IRQ_DSTTRAN = 0x08, + /* error */ + DMAC_IRQ_ERR = 0x10, + /* all interrupts */ + DMAC_IRQ_ALL = 0x1f +}; + +enum dmac_software_req +{ + /* ReqSrcReq/ReqDstReq */ + DMAC_REQUEST = 0x1, + /* SglReqSrcReq/SglReqDstReq */ + DMAC_SINGLE_REQUEST = 0x2, + /* LstReqSrcReq/LstReqDstReq */ + DMAC_LAST_REQUEST = 0x4 +}; + +enum dmac_master_number +{ + DMAC_MASTER1 = 0x0, + DMAC_MASTER2 = 0x1 +}; + +enum dmac_transfer_flow +{ + /* mem to mem - DMAC flow ctlr */ + DMAC_MEM2MEM_DMA = 0x0, + /* mem to prf - DMAC flow ctlr */ + DMAC_MEM2PRF_DMA = 0x1, + /* prf to mem - DMAC flow ctlr */ + DMAC_PRF2MEM_DMA = 0x2, + /* prf to prf - DMAC flow ctlr */ + DMAC_PRF2PRF_DMA = 0x3, + /* prf to mem - periph flow ctlr */ + DMAC_PRF2MEM_PRF = 0x4, + /* prf to prf - source flow ctlr */ + DMAC_PRF2PRF_SRCPRF = 0x5, + /* mem to prf - periph flow ctlr */ + DMAC_MEM2PRF_PRF = 0x6, + /* prf to prf - dest flow ctlr */ + DMAC_PRF2PRF_DSTPRF = 0x7 +}; + +enum dmac_burst_trans_length +{ + DMAC_MSIZE_1 = 0x0, + DMAC_MSIZE_4 = 0x1, + DMAC_MSIZE_8 = 0x2, + DMAC_MSIZE_16 = 0x3, + DMAC_MSIZE_32 = 0x4, + DMAC_MSIZE_64 = 0x5, + DMAC_MSIZE_128 = 0x6, + DMAC_MSIZE_256 = 0x7 +}; + +enum dmac_address_increment +{ + DMAC_ADDR_INCREMENT = 0x0, + DMAC_ADDR_NOCHANGE = 0x1 +}; + +enum dmac_transfer_width +{ + DMAC_TRANS_WIDTH_8 = 0x0, + DMAC_TRANS_WIDTH_16 = 0x1, + DMAC_TRANS_WIDTH_32 = 0x2, + DMAC_TRANS_WIDTH_64 = 0x3, + DMAC_TRANS_WIDTH_128 = 0x4, + DMAC_TRANS_WIDTH_256 = 0x5 +}; + +enum dmac_hs_interface +{ + DMAC_HS_IF0 = 0x0, + DMAC_HS_IF1 = 0x1, + DMAC_HS_IF2 = 0x2, + DMAC_HS_IF3 = 0x3, + DMAC_HS_IF4 = 0x4, + DMAC_HS_IF5 = 0x5, + DMAC_HS_IF6 = 0x6, + DMAC_HS_IF7 = 0x7, + DMAC_HS_IF8 = 0x8, + DMAC_HS_IF9 = 0x9, + DMAC_HS_IF10 = 0xa, + DMAC_HS_IF11 = 0xb, + DMAC_HS_IF12 = 0xc, + DMAC_HS_IF13 = 0xd, + DMAC_HS_IF14 = 0xe, + DMAC_HS_IF15 = 0xf +}; + +enum dmac_multiblk_transfer_type +{ + CONTIGUOUS = 0, + RELOAD = 1, + SHADOWREGISTER = 2, + LINKEDLIST = 3 +}; + +enum dmac_multiblk_type +{ + DMAC_SRC_DST_CONTINUE = 0, + DMAC_SRC_CONTINUE_DST_RELAOD = 2, + DMAC_SRC_CONTINUE_DST_LINKEDLIST = 3, + DMAC_SRC_RELOAD_DST_CONTINUE = 4, + DMAC_SRC_RELOAD_DST_RELOAD = 5, + DMAC_SRC_RELOAD_DST_LINKEDLIST = 6, + DMAC_SRC_LINKEDLIST_DST_CONTINUE = 7, + DMAC_SRC_LINKEDLIST_DST_RELOAD = 8, + DMAC_SRC_LINKEDLIST_DST_LINKEDLIST = 9, + DMAC_SRC_SHADOWREG_DST_CONTINUE = 10 +}; + +enum dmac_transfer_type +{ + DMAC_TRANSFER_ROW1 = 0x1, + DMAC_TRANSFER_ROW2 = 0x2, + DMAC_TRANSFER_ROW3 = 0x3, + DMAC_TRANSFER_ROW4 = 0x4, + DMAC_TRANSFER_ROW5 = 0x5, + DMAC_TRANSFER_ROW6 = 0x6, + DMAC_TRANSFER_ROW7 = 0x7, + DMAC_TRANSFER_ROW8 = 0x8, + DMAC_TRANSFER_ROW9 = 0x9, + DMAC_TRANSFER_ROW10 = 0xa +}; + +enum dmac_prot_level +{ + /* default prot level */ + DMAC_NONCACHE_NONBUFF_NONPRIV_OPCODE = 0x0, + DMAC_NONCACHE_NONBUFF_NONPRIV_DATA = 0x1, + DMAC_NONCACHE_NONBUFF_PRIV_OPCODE = 0x2, + DMAC_NONCACHE_NONBUFF_PRIV_DATA = 0x3, + DMAC_NONCACHE_BUFF_NONPRIV_OPCODE = 0x4, + DMAC_NONCACHE_BUFF_NONPRIV_DATA = 0x5, + DMAC_NONCACHE_BUFF_PRIV_OPCODE = 0x6, + DMAC_NONCACHE_BUFF_PRIV_DATA = 0x7, + DMAC_CACHE_NONBUFF_NONPRIV_OPCODE = 0x8, + DMAC_CACHE_NONBUFF_NONPRIV_DATA = 0x9, + DMAC_CACHE_NONBUFF_PRIV_OPCODE = 0xa, + DMAC_CACHE_NONBUFF_PRIV_DATA = 0xb, + DMAC_CACHE_BUFF_NONPRIV_OPCODE = 0xc, + DMAC_CACHE_BUFF_NONPRIV_DATA = 0xd, + DMAC_CACHE_BUFF_PRIV_OPCODE = 0xe, + DMAC_CACHE_BUFF_PRIV_DATA = 0xf +}; + +enum dmac_fifo_mode +{ + DMAC_FIFO_MODE_SINGLE = 0x0, + DMAC_FIFO_MODE_HALF = 0x1 +}; + +enum dw_dmac_flow_ctl_mode +{ + DMAC_DATA_PREFETCH_ENABLED = 0x0, + DMAC_DATA_PREFETCH_DISABLED = 0x1 +}; + +enum dmac_polarity_level +{ + DMAC_ACTIVE_HIGH = 0x0, + DMAC_ACTIVE_LOW = 0x1 +}; + +enum dmac_lock_level +{ + DMAC_LOCK_LEVEL_DMA_TRANSFER = 0x0, + DMAC_LOCK_LEVEL_BLOCK_TRANSFER = 0x1, + DMAC_LOCK_LEVEL_TRANSACTION = 0x2 +}; + +enum dmac_channel_priority +{ + DMAC_PRIORITY_0 = 0x0, + DMAC_PRIORITY_1 = 0x1, + DMAC_PRIORITY_2 = 0x2, + DMAC_PRIORITY_3 = 0x3, + DMAC_PRIORITY_4 = 0x4, + DMAC_PRIORITY_5 = 0x5, + DMAC_PRIORITY_6 = 0x6, + DMAC_PRIORITY_7 = 0x7 +}; + +enum dmac_state +{ + ZERO, + ONE +}; + +enum dmca_common_int +{ + SLVIF_COMMON_DEC_ERR = 0, + SLVIF_COMMON_WR2RO_ERR = 1, + SLVIF_COMMON_RD2WO_ERR = 2, + SLVIF_COMMON__WRONHOLD_ERR = 3, + SLVIF_UNDEFINED_DEC_ERR = 4, + SLVIF_ALL_INT = 5 +}; + +struct dmac_cfg_t +{ + /** + * Bit 0 is used to enable dmac + * 0x1 for enable, 0x0 for disable + */ + uint64_t dmac_en : 1; + /** + * Bit 1 is used to glabally enable interrupt generation + * 0x1 for enable interrupt, 0x0 for disable interrupt + */ + uint64_t int_en : 1; + /* Bits [63:2] is reserved */ + uint64_t rsvd : 62; +} __attribute__((packed, aligned(8))); + +union dmac_cfg_u +{ + struct dmac_cfg_t cfg; + uint64_t data; +}; + +struct damc_chen_t +{ + /** + * Bit 0 is used to enable channel 1 + * 0x1 for enable, 0x0 for disable + */ + uint64_t ch1_en : 1; + /** + * Bit 1 is used to enable channel 2 + * 0x1 for enable, 0x0 for disable + */ + uint64_t ch2_en : 1; + /** + * Bit 2 is used to enable channel 3 + * 0x1 for enable, 0x0 for disable + */ + uint64_t ch3_en : 1; + /** + * Bit 3 is used to enable channel 4 + * 0x1 for enable, 0x0 for disable + */ + uint64_t ch4_en : 1; + /** + * Bit 4 is used to enable channel 5 + * 0x1 for enable, 0x0 for disable + */ + uint64_t ch5_en : 1; + /** + * Bit 5 is used to enable channel 6 + * 0x1 for enable, 0x0 for disable + */ + uint64_t ch6_en : 1; + /* Bits [7:6] is reserved */ + uint64_t rsvd1 : 2; + /** + * Bit 8 is write enable bit + * 0x1 for enable, 0x0 for disable + */ + uint64_t ch1_en_we : 1; + /** + * Bit 9 is write enable bit + * 0x1 for enable, 0x0 for disable + */ + uint64_t ch2_en_we : 1; + /** + * Bit 10 is write enable bit + * 0x1 for enable, 0x0 for disable + */ + uint64_t ch3_en_we : 1; + /** + * Bit 11 is write enable bit + * 0x1 for enable, 0x0 for disable + */ + uint64_t ch4_en_we : 1; + /** + * Bit 12 is write enable bit + * 0x1 for enable, 0x0 for disable + */ + uint64_t ch5_en_we : 1; + /** + * Bit 13 is write enable bit + * 0x1 for enable, 0x0 for disable + */ + uint64_t ch6_en_we : 1; + /* Bits [15:14] is reserved */ + uint64_t rsvd2 : 2; + /** + * Bit 16 is susped reuest + * 0x1 for request channel suspend + * 0x0 for no channel suspend request + */ + uint64_t ch1_susp : 1; + /** + * Bit 17 is susped reuest + * 0x1 for request channel suspend + * 0x0 for no channel suspend request + */ + uint64_t ch2_susp : 1; + /* Bit 18 is susped reuest + * 0x1 for request channel suspend + * 0x0 for no channel suspend request + */ + uint64_t ch3_susp : 1; + /** + * Bit 19 is susped reuest + * 0x1 for request channel suspend + * 0x0 for no channel suspend request + */ + uint64_t ch4_susp : 1; + /** + * Bit 20 is susped reuest + * 0x1 for request channel suspend + * 0x0 for no channel suspend request + */ + uint64_t ch5_susp : 1; + /** + * Bit 21 is susped reuest + * 0x1 for request channel suspend + * 0x0 for no channel suspend request + */ + uint64_t ch6_susp : 1; + /* Bits [23:22] is reserved */ + uint64_t rsvd3 : 2; + /** + * Bit 24 is write enable to the channel suspend bit + * 0x1 for enable write to CH1_SUSP bit + * 0x0 for disable write to CH1_SUSP bit + */ + uint64_t ch1_susp_we : 1; + /** + * Bit 25 is write enable to the channel suspend bit + * 0x1 for enable write to CH2_SUSP bit + * 0x0 for disable write to CH2_SUSP bit + */ + uint64_t ch2_susp_we : 1; + /** + * Bit 26 is write enable to the channel suspend bit + * 0x1 for enable write to CH3_SUSP bit + * 0x0 for disable write to CH3_SUSP bit + */ + uint64_t ch3_susp_we : 1; + /** + * Bit 27 is write enable to the channel suspend bit + * 0x1 for enable write to CH4_SUSP bit + * 0x0 for disable write to CH4_SUSP bit + */ + uint64_t ch4_susp_we : 1; + /** + * Bit 28 is write enable to the channel suspend bit + * 0x1 for enable write to CH5_SUSP bit + * 0x0 for disable write to CH5_SUSP bit + */ + uint64_t ch5_susp_we : 1; + /** + * Bit 29 is write enable to the channel suspend bit + * 0x1 for enable write to CH6_SUSP bit + * 0x0 for disable write to CH6_SUSP bit + */ + uint64_t ch6_susp_we : 1; + /* Bits [31:30] is reserved */ + uint64_t rsvd4 : 2; + /** + * Bit 32 is channel-1 abort requst bit + * 0x1 for request for channnel abort + * 0x0 for no channel abort request + */ + uint64_t ch1_abort : 1; + /** + * Bit 33 is channel-2 abort requst bit + * 0x1 for request for channnel abort + * 0x0 for no channel abort request + */ + uint64_t ch2_abort : 1; + /** + * Bit 34 is channel-3 abort requst bit + * 0x1 for request for channnel abort + * 0x0 for no channel abort request + */ + uint64_t ch3_abort : 1; + /** + * Bit 35 is channel-4 abort requst bit + * 0x1 for request for channnel abort + * 0x0 for no channel abort request + */ + uint64_t ch4_abort : 1; + /** + * Bit 36 is channel-5 abort requst bit + * 0x1 for request for channnel abort + * 0x0 for no channel abort request + */ + uint64_t ch5_abort : 1; + /** + * Bit 37 is channel-6 abort requst bit + * 0x1 for request for channnel abort + * 0x0 for no channel abort request + */ + uint64_t ch6_abort : 1; + /* Bits [39:38] is reserved */ + uint64_t rsvd5 : 2; + /** + * Bit 40 is ued to write enable channel-1 abort bit + * 0x1 for enable write to CH1_ABORT bit + * 0x0 for disable write to CH1_ABORT bit + */ + uint64_t ch1_abort_we : 1; + /** + * Bit 41 is ued to write enable channel-2 abort bit + * 0x1 for enable write to CH2_ABORT bit + * 0x0 for disable write to CH2_ABORT bit + */ + uint64_t ch2_abort_we : 1; + /** + * Bit 42 is ued to write enable channel-3 abort bit + * 0x1 for enable write to CH3_ABORT bit + * 0x0 for disable write to CH3_ABORT bit + */ + uint64_t ch3_abort_we : 1; + /** + * Bit 43 is ued to write enable channel-4 abort bit + * 0x1 for enable write to CH4_ABORT bit + * 0x0 for disable write to CH4_ABORT bit + */ + uint64_t ch4_abort_we : 1; + /** + * Bit 44 is ued to write enable channel-5 abort bit + * 0x1 for enable write to CH5_ABORT bit + * 0x0 for disable write to CH5_ABORT bit + */ + uint64_t ch5_abort_we : 1; + /** + * Bit 45 is ued to write enable channel-6 abort bit + * 0x1 for enable write to CH6_ABORT bit + * 0x0 for disable write to CH6_ABORT bit + */ + uint64_t ch6_abort_we : 1; + /* Bits [47:46] is reserved */ + uint64_t rsvd6 : 2; + /* Bits [63:48] is reserved */ + uint64_t rsvd7 : 16; +} __attribute__((packed, aligned(8))); + +union dmac_chen_u +{ + struct damc_chen_t dmac_chen; + uint64_t data; +}; + +struct dmac_intstatus_t +{ + /** + * Bit 0 is channel 1 interrupt bit + * 0x1 for channel 1 interrupt active + * 0x0 for channel 1 interrupt inactive + */ + uint64_t ch1_intstat : 1; + /** + * Bit 1 is channel 1 interrupt bit + * 0x1 for channel 2 interrupt active + * 0x0 for channel 2 interrupt inactive + */ + uint64_t ch2_intstat : 1; + /** + * Bit 2 is channel 3 interrupt bit + * 0x1 for channel 3 interrupt active + * 0x0 for channel 3 interrupt inactive + */ + uint64_t ch3_intstat : 1; + /** + * Bit 3 is channel 4 interrupt bit + * 0x1 for channel 4 interrupt active + * 0x0 for channel 4 interrupt inactive + */ + uint64_t ch4_intstat : 1; + /** + * Bit 4 is channel 5 interrupt bit + * 0x1 for channel 5 interrupt active + * 0x0 for channel 5 interrupt inactive + */ + uint64_t ch5_intstat : 1; + /** + * Bit 5 is channel 6 interrupt bit + * 0x1 for channel 6 interrupt active + * 0x0 for channel 6 interrupt inactive + */ + uint64_t ch6_intstat : 1; + /* Bits [15:6] is reserved */ + uint64_t rsvd1 : 10; + /** + * Bit 16 is commom register status bit + * 0x1 for common register interrupt is active + * 0x0 for common register interrupt inactive + */ + uint64_t commonreg_intstat : 1; + /* Bits [63:17] is reserved */ + uint64_t rsvd2 : 47; +} __attribute__((packed, aligned(8))); + +union dmac_intstatus_u +{ + struct dmac_intstatus_t intstatus; + uint64_t data; +}; + +struct dmac_commonreg_intclear_t +{ + /** + * Bit 0 is slave nterface Common Register + * Decode Error Interrupt clear Bit + * x01 for clear SLVIF_CommonReg_DEC_ERR interrupt + * in DMAC_COMMONREG_INTSTATUSREG + * 0x0 for inactive signal + */ + uint64_t cear_slvif_dec_err_intstat : 1; + /** + * Bit 1 is Slave Interface Common Register Write + * to Read only Error Interrupt clear Bit + * x01 for clear SLVIF_CommonReg_WR2RO_ERR interrupt + * in DMAC_COMMONREG_INTSTATUSREG + * 0x0 for inactive signal + */ + uint64_t clear_slvif_wr2ro_err_intstat : 1; + /** + * Bit 2 is Slave Interface Common Register Read to + * Write only Error Interrupt clear Bit + * x01 for clear SLVIF_CommonReg_RD2WO_ERR interrupt + * in DMAC_COMMONREG_INTSTATUSREG + * 0x0 for inactive signal + */ + uint64_t clear_slvif_rd2wo_err_intstat : 1; + /** + * Bit 3 is Slave Interface Common Register Write + * On Hold Error Interrupt clear Bit + * x01 for clear SSLVIF_CommonReg_WrOnHold_ERR interrupt + * in DMAC_COMMONREG_INTSTATUSREG + * 0x0 for inactive signal + */ + uint64_t clear_slvif_wronhold_err_intstat : 1; + /* Bits [7:4] is reserved */ + uint64_t rsvd1 : 4; + /** + * Bit 8 is Slave Interface Undefined register + * Decode Error Interrupt clear Bit + * x01 for clear SLVIF_UndefinedReg_DEC_ERRinterrupt + * in DMAC_COMMONREG_INTSTATUSREG + * 0x0 for inactive signal + */ + uint64_t clear_slvif_undefinedreg_dec_err_intstat : 1; + /* Bits [63:9] is reserved */ + uint64_t rsvd2 : 55; +} __attribute__((packed, aligned(8))); + +union dmac_commonreg_intclear_u +{ + struct dmac_commonreg_intclear_t com_intclear; + uint64_t data; +}; + +struct dmac_commonreg_intstatus_enable_t +{ + /** + * Bit 0 is Slave Interface Common Register Decode Error + * Interrupt Status Enable Bit + * 0x1 for SLVIF_CommonReg_DEC_ERR_IntStat bit enable + * 0x0 for SLVIF_CommonReg_DEC_ERR_IntStat bit disable + */ + uint64_t enable_slvif_dec_err_intstat : 1; + /** + * Bit 1 is Slave Interface Common Register Write to Read + * only Error Interrupt Status Enable Bit + * 0x1 for SLVIF_CommonReg_WR2RO_ERR_IntStat bit enable + * 0x0 for SLVIF_CommonReg_WR2RO_ERR_IntStat bit disable + */ + uint64_t enable_slvif_wr2ro_err_intstat : 1; + /*!< + * Bit 2 is Slave Interface Common Register Read to Write + * only Error Interrupt Status Enable Bit + * 0x1 for SLVIF_CommonReg_RD2WO_ERR_IntStat bit enable + * 0x0 for SLVIF_CommonReg_RD2WO_ERR_IntStat bit disable + */ + uint64_t enable_slvif_rd2wo_err_intstat : 1; + /** + * Bit 3 is Slave Interface Common Register Write On Hold + * Error Interrupt Status Enable Bit + * 0x1 for SLVIF_CommonReg_WrOnHold_ERR_IntStat bit enable + * 0x0 for SLVIF_CommonReg_WrOnHold_ERR_IntStat bit disable + */ + uint64_t enable_slvif_wronhold_err_intstat : 1; + /* Bits [7:4] is reserved */ + uint64_t rsvd1 : 4; + /** + * Bit 8 is Slave Interface Undefined register Decode + * Error Interrupt Status enable Bit + * 0x1 for SLVIF_UndefinedReg_DEC_ERR_IntStat bit enable + * 0x0 for SLVIF_UndefinedReg_DEC_ERR_IntStat disable + */ + uint64_t enable_slvif_undefinedreg_dec_err_intstat : 1; + /* Bits [63:9] is reserved */ + uint64_t rsvd2 : 55; +} __attribute__((packed, aligned(8))); + +union dmac_commonreg_intstatus_enable_u +{ + struct dmac_commonreg_intstatus_enable_t intstatus_enable; + uint64_t data; +}; + +struct dmac_commonreg_intsignal_enable_t +{ + /** + * Bit 0 is Slave Interface Common Register Decode Error + * Interrupt Signal Enable Bit + * 0x1 for SLVIF_CommonReg_DEC_ERR_IntStat signal enable + * 0x0 for SLVIF_CommonReg_DEC_ERR_IntStat signal disable + */ + uint64_t enable_slvif_dec_err_intsignal : 1; + /** + * Bit 1 is Slave Interface Common Register Write to Read only + * Error Interrupt Signal Enable Bit + * 0x1 for SLVIF_CommonReg_WR2RO_ERR_IntStat signal enable + * 0x0 for SLVIF_CommonReg_WR2RO_ERR_IntStat signal disable + */ + uint64_t enable_slvif_wr2ro_err_intsignal : 1; + /** + * Bit 2 is Slave Interface Common Register Read to + * Write only Error Interrupt Status Enable Bit + * 0x1 for SLVIF_CommonReg_RD2WO_ERR_IntStat bit enable + * 0x0 for SLVIF_CommonReg_RD2WO_ERR_IntStat bit disable + */ + uint64_t enable_slvif_rd2wo_err_intsignal : 1; + /** + * Bit 3 is Slave Interface Common Register Write On Hold Error + * Interrupt Signal Enable Bit + * 0x1 for SLVIF_CommonReg_WrOnHold_ERR_IntStat signal enable + * 0x0 for SLVIF_CommonReg_WrOnHold_ERR_IntStat signal disable + */ + uint64_t enable_slvif_wronhold_err_intsignal : 1; + /* Bits [7:4] is reserved */ + uint64_t rsvd1 : 4; + /** + * Bit 8 is Slave Interface Undefined register Decode Error + * Interrupt Signal Enable Bit + * 0x1 for SLVIF_UndefinedReg_DEC_ERR_IntStat signal enable + * 0x0 for SLVIF_UndefinedReg_DEC_ERR_IntStat signal disable + */ + uint64_t enable_slvif_undefinedreg_dec_err_intsignal : 1; + /* Bits [63:9] is reserved */ + uint64_t rsvd2 : 55; +} __attribute__((packed, aligned(8))); + +union dmac_commonreg_intsignal_enable_u +{ + struct dmac_commonreg_intsignal_enable_t intsignal_enable; + uint64_t data; +}; + +struct dmac_commonreg_intstatus_t +{ + /** + * Bit 0 is Slave Interface Common Register Decode + * Error Interrupt Status Bit + * 0x1 for Slave Interface Decode Error detected + * 0x0 for No Slave Interface Decode Errors + */ + uint64_t slvif_dec_err_intstat : 1; + /** + * Bit 1 is Slave Interface Common Register Write to Read Only + * Error Interrupt Status bit + * 0x1 for Slave Interface Write to Read Only Error detected + * 0x0 No Slave Interface Write to Read Only Errors + */ + uint64_t slvif_wr2ro_err_intstat : 1; + /** + * Bit 2 is Slave Interface Common Register Read to Write + * only Error Interrupt Status bit + * 0x1 for Slave Interface Read to Write Only Error detected + * 0x0 for No Slave Interface Read to Write Only Errors + */ + uint64_t slvif_rd2wo_err_intstat : 1; + /** + * Bit 3 is Slave Interface Common Register Write On + * Hold Error Interrupt Status Bit + * 0x1 for Slave Interface Common Register Write On Hold Error detected + * 0x0 for No Slave Interface Common Register Write On Hold Errors + */ + uint64_t slvif_wronhold_err_intstat : 1; + /*!< Bits [7:4] is reserved */ + uint64_t rsvd1 : 4; + /** + * Bit 8 is Slave Interface Undefined register Decode + * Error Interrupt Signal Enable Bit + * 0x1 for Slave Interface Decode Error detected + * 0x0 for No Slave Interface Decode Errors + */ + uint64_t slvif_undefinedreg_dec_err_intstat : 1; + /* Bits [63:9] is reserved */ + uint64_t rsvd2 : 55; +} __attribute__((packed, aligned(8))); + +union dmac_commonreg_intstatus_u +{ + struct dmac_commonreg_intstatus_t commonreg_intstatus; + uint64_t data; +}; + +struct dmac_reset_t +{ + /* Bit 0 is DMAC reset request bit */ + uint64_t rst : 1; + /* Bits [63:1] is reserved */ + uint64_t rsvd : 63; +} __attribute__((packed, aligned(8))); + +union dmac_reset_u +{ + struct dmac_reset_t reset; + uint64_t data; +}; + +struct dmac_ch_block_ts_t +{ + uint64_t block_ts : 22; + /*!< Bit [21:0] is block transfer size*/ + uint64_t rsvd : 42; + /*!< Bits [63:22] is reserved */ +} __attribute__((packed, aligned(8))); + +union dmac_ch_block_ts_u +{ + struct dmac_ch_block_ts_t block_ts; + uint64_t data; +}; + +struct dmac_ch_ctl_t +{ + /** + * Bit 0 is source master select + * 1 for AXI master 2, 0 for AXI master 1 + */ + uint64_t sms : 1; + /* Bit 1 is reserved */ + uint64_t rsvd1 : 1; + /** + * Bit 2 is destination master select + * 0x1 for AXI master 2,0x0 for AXI master 1 + */ + uint64_t dms : 1; + /* Bit 3 is reserved */ + uint64_t rsvd2 : 1; + /** + * Bit 4 is source address increment + * 0x1 for no change, 0x0 for incremnet + */ + uint64_t sinc : 1; + /** + * Bit 5 is reserved + */ + uint64_t rsvd3 : 1; + /** + * Bit 6 is destination address incremnet + * 0x1 for no change, 0x0 for increment + */ + uint64_t dinc : 1; + /* Bit 7 is reserved*/ + uint64_t rsvd4 : 1; + /** + * Bits [10:8] is source transfer width + * 0x0 for source transfer width is 8 bits + * 0x1 for source transfer width is 16 bits + * 0x2 for source transfer width is 32 bits + * 0x3 for source transfer width is 64 bits + * 0x4 for source transfer width is 128 bits + * 0x5 for source transfer width is 256 bits + * 0x6 for source transfer width is 512 bits + */ + uint64_t src_tr_width : 3; + /** + * Bits [13:11] is detination transfer width + * 0x0 for detination transfer width is 8 bits + * 0x1 for detination transfer width is 16 bits + * 0x2 for detination transfer width is 32 bits + * 0x3 for detination transfer width is 64 bits + * 0x4 for detination transfer width is 128 bits + * 0x5 for detination transfer width is 256 bits + * 0x6 for detination transfer width is 512 bits + */ + uint64_t dst_tr_width : 3; + /** + * Bits [17:14] is source burst transaction length + * 0x0 for 1 data item read from rource in the burst transaction + * 0x1 for 4 data item read from rource in the burst transaction + * 0x2 for 8 data item read from rource in the burst transaction + * 0x3 for 16 data item read from rource in the burst transaction + * 0x4 for 32 data item read from rource in the burst transaction + * 0x5 for 64 data item read from rource in the burst transaction + * 0x6 for 128 data item read from rource in the burst transaction + * 0x7 for 256 data item read from rource in the burst transaction + * 0x8 for 512 data item read from rource in the burst transaction + * 0x9 for 1024 data item read from rource in the burst transaction + */ + uint64_t src_msize : 4; + /** + * Bits [17:14] is sdestination burst transaction length + * 0x0 for 1 data item read from rource in the burst transaction + * 0x1 for 4 data item read from rource in the burst transaction + * 0x2 for 8 data item read from rource in the burst transaction + * 0x3 for 16 data item read from rource in the burst transaction + * 0x4 for 32 data item read from rource in the burst transaction + * 0x5 for 64 data item read from rource in the burst transaction + * 0x6 for 128 data item read from rource in the burst transaction + * 0x7 for 256 data item read from rource in the burst transaction + * 0x8 for 512 data item read from rource in the burst transaction + * 0x9 for 1024 data item read from rource in the burst transaction + */ + uint64_t dst_msize : 4; + /** + * Bits [25:22] is reserved + */ + uint64_t rsvd5 : 4; + /*!< Bits [29:26] is reserved */ + uint64_t rsvd6 : 4; + /** + * Bit 30 is Non Posted Last Write Enable + * 0x1 for posted writes may be used till the end of the block + * 0x 0 for posted writes may be used throughout the block transfer + */ + uint64_t nonposted_lastwrite_en : 1; + /* Bit 31 is resrved */ + uint64_t rsvd7 : 1; + /* Bits [34:32] is reserved*/ + uint64_t rsvd8 : 3; + /* Bits [37:35] is reserved*/ + uint64_t rsvd9 : 3; + /** + * Bit 38 is source burst length enable + * 1 for enable, 0 for disable + */ + uint64_t arlen_en : 1; + /* Bits [46:39] is source burst length*/ + uint64_t arlen : 8; + /** + * Bit 47 is destination burst length enable + * 1 for enable, 0 for disable + */ + uint64_t awlen_en : 1; + /* Bits [55:48] is destination burst length */ + uint64_t awlen : 8; + /** + * Bit 56 is source status enable + * 0x1 for enable, 0x0 for disable + */ + uint64_t src_stat_en : 1; + /** + * Bit 57 is destination status enable + * 0x1 for enable, 0x0 for disable + */ + uint64_t dst_stat_en : 1; + /** + * Bit 58 is interrupt completion of block transfer + * 0x1 for enable CHx_IntStatusReg.BLOCK_TFR_DONE_IntStat field + * 0x0 for dsiable CHx_IntStatusReg.BLOCK_TFR_DONE_IntStat field + */ + uint64_t ioc_blktfr : 1; + /** + * Bits [61:59] is reserved + */ + uint64_t rsvd10 : 3; + /** + * Bit 62 is last shadow linked list item + * 0x1 for indicate shadowreg/LLI content is the last one + * 0x0 for indicate shadowreg/LLI content not the last one + */ + uint64_t shadowreg_or_lli_last : 1; + /** + * Bit 63 is last shadow linked list item valid + * 0x1 for indicate shadowreg/LLI content is valid + * 0x0 for indicate shadowreg/LLI content is invalid + */ + uint64_t shadowreg_or_lli_valid : 1; +} __attribute__((packed, aligned(8))); + +union dmac_ch_ctl_u +{ + struct dmac_ch_ctl_t ch_ctl; + uint64_t data; +}; + +struct dmac_ch_cfg_t +{ + /** + * Bit[1:0] is source multi block transfer type + * 0x0 for continuous multiblock type + * 0x1 for reload multiblock type + * 0x2 for shadow register based multiblock type + * 0x3 for linked lisr bases multiblock type + */ + uint64_t src_multblk_type : 2; + /** + * Bit[3:2] is source multi block transfer type + * 0x0 for continuous multiblock type + * 0x1 for reload multiblock type + * 0x2 for shadow register based multiblock type + * 0x3 for linked lisr bases multiblock type + */ + uint64_t dst_multblk_type : 2; + /* Bits [31:4] is reserved*/ + uint64_t rsvd1 : 28; + /** + * Bits [34:32] is transfer type and flow control + * 0x0 transfer memory to memory and flow controler is dmac + * 0x1 transfer memory to peripheral and flow controler is dmac + * 0x2 transfer peripheral to memory and flow controler is dmac + * 0x3 transfer peripheral to peripheral and flow controler is dmac + * 0x4 transfer peripheral to memory and flow controler is + * source peripheral + * 0x5 transfer peripheral to peripheral and flow controler + * is source peripheral + * 0x6 transfer memory to peripheral and flow controler is + * destination peripheral + * 0x7 transfer peripheral to peripheral and flow controler + * is destination peripheral + */ + uint64_t tt_fc : 3; + /** + * Bit 35 is source software or hardware handshaking select + * 0x1 for software handshaking is used + * 0x0 for hardware handshaking is used + */ + uint64_t hs_sel_src : 1; + /** + * Bit 36 is destination software or hardware handshaking select + *0x1 for software handshaking is used + *0x0 for hardware handshaking is used + */ + uint64_t hs_sel_dst : 1; + /** + * Bit 37 is sorce hardware handshaking interface polarity + * 0x1 active low, 0x0 active high + */ + uint64_t src_hwhs_pol : 1; + /** + * Bit 38 is destination hardware handshaking interface polarity + * 0x1 active low, 0x0 active high + */ + uint64_t dst_hwhs_pol : 1; + /** + * Bits [41:39] is assign a hardware handshaking interface + * to source of channel x + */ + uint64_t src_per : 4; + /* Bit 43 is reserved*/ + uint64_t rsvd3 : 1; + /** + * Bits [46:44] is assign a hardware handshaking interface + * to destination of channel x + */ + uint64_t dst_per : 4; + /* Bit 48 is reserved*/ + uint64_t rsvd5 : 1; + /* Bits [51:49] is channel priority,7 is highest, 0 is lowest*/ + uint64_t ch_prior : 3; + /** + * Bit 52 is channel lock bit + * 0x0 for channel is not locked, 0x1 for channel is locked + */ + uint64_t lock_ch : 1; + /** + * Bits [54:53] is chnannel lock level + * 0x0 for duration of channel is locked for entire DMA transfer + * 0x1 for duration of channel is locked for current block transfer + */ + uint64_t lock_ch_l : 2; + uint64_t src_osr_lmt : 4; + /* Bits [58:55] is source outstanding request limit */ + uint64_t dst_osr_lmt : 4; + /* Bits [62:59] is destination outstanding request limit */ +} __attribute__((packed, aligned(8))); + +union dmac_ch_cfg_u +{ + struct dmac_ch_cfg_t ch_cfg; + uint64_t data; +}; + +struct dmac_ch_llp_t +{ + /** + * Bit 0 is LLI master select + * 0x0 for next linked list item resides on AXI madster1 interface + * 0x1 for next linked list item resides on AXI madster2 interface + */ + uint64_t lms : 1; + /* Bits [5:1] is reserved */ + uint64_t rsvd1 : 5; + /* Bits [63:6] is starting address memeory of LLI block */ + uint64_t loc : 58; +} __attribute__((packed, aligned(8))); + +union dmac_ch_llp_u +{ + struct dmac_ch_llp_t llp; + uint64_t data; +}; + +struct dmac_ch_status_t +{ + /* Bits [21:0] is completed block transfer size */ + uint64_t cmpltd_blk_size : 22; + /* Bits [46:32] is reserved */ + uint64_t rsvd1 : 15; + /* Bits [63:47] is reserved */ + uint64_t rsvd2 : 17; +} __attribute__((packed, aligned(8))); + +union dmac_ch_status_u +{ + struct dmac_ch_status_t status; + uint64_t data; +}; + +struct dmac_ch_swhssrc_t +{ + /** + * Bit 0 is software handshake request for channel source + * 0x1 source periphraral request for a dma transfer + * 0x0 source peripheral is not request for a burst transfer + */ + uint64_t swhs_req_src : 1; + /** + * Bit 1 is write enable bit for software handshake request + *0x1 for enable, 0x0 for disable + */ + uint64_t swhs_req_src_we : 1; + /** + * Bit 2 is software handshake single request for channel source + * 0x1 for source peripheral requesr for a single dma transfer + * 0x0 for source peripheral is not requesting for a single transfer + */ + uint64_t swhs_sglreq_src : 1; + /** + * Bit 3 is write enable bit for software handshake + * single request for channle source + * 0x1 for enable write, 0x0 for disable write + */ + uint64_t swhs_sglreq_src_we : 1; + /** + * Bit 4 software handshake last request for channel source + * 0x1 for current transfer is last transfer + * 0x0 for current transfer is not the last transfer + */ + uint64_t swhs_lst_src : 1; + /** + * Bit 5 is write enable bit for software + * handshake last request + * 0x1 for enable, 0x0 for disable + */ + uint64_t swhs_lst_src_we : 1; + /* Bits [63:6] is reserved */ + uint64_t rsvd : 58; +} __attribute__((packed, aligned(8))); + +union dmac_ch_swhssrc_u +{ + struct dmac_ch_swhssrc_t swhssrc; + uint64_t data; +}; + +struct dmac_ch_swhsdst_t +{ + /** + * Bit 0 is software handshake request for channel destination + * 0x1 destination periphraral request for a dma transfer + * 0x0 destination peripheral is not request for a burst transfer + */ + uint64_t swhs_req_dst : 1; + /** + * Bit 1 is write enable bit for software handshake request + * 0x1 for enable, 0x0 for disable + */ + uint64_t swhs_req_dst_we : 1; + /** + * Bit 2 is software handshake single request for channel destination + * 0x1 for destination peripheral requesr for a single dma transfer + * 0x0 for destination peripheral is not requesting + * for a single transfer + */ + uint64_t swhs_sglreq_dst : 1; + /** + * Bit 3 is write enable bit for software handshake + * single request for channle destination + * 0x1 for enable write, 0x0 for disable write + */ + uint64_t swhs_sglreq_dst_we : 1; + /** + * Bit 4 software handshake last request for channel dstination + * 0x1 for current transfer is last transfer + * 0x0 for current transfer is not the last transfer + */ + uint64_t swhs_lst_dst : 1; + /** + * Bit 5 is write enable bit for software handshake last request + * 0x1 for enable, 0x0 for disable + */ + uint64_t swhs_lst_dst_we : 1; + /* Bits [63:6] is reserved */ + uint64_t rsvd : 58; +} __attribute__((packed, aligned(8))); + +union dmac_ch_swhsdst_u +{ + struct dmac_ch_swhsdst_t swhsdst; + uint64_t data; +}; + +struct dmac_ch_blk_tfr_resumereq_t +{ + /** + * Bit 0 is block transfer resume request bit + * 0x1 for request for resuming + * 0x0 for no request to resume + */ + uint64_t blk_tfr_resumereq : 1; + /* Bits [63:1] is reserved */ + uint64_t rsvd : 63; +} __attribute__((packed, aligned(8))); + +union dmac_ch_blk_tfr_resumereq_u +{ + struct dmac_ch_blk_tfr_resumereq_t blk_tfr_resumereq; + uint64_t data; +}; + +struct dmac_ch_intstatus_enable_t +{ + /* Bit 0 is block transfer done interrupt status enable */ + uint64_t enable_block_tfr_done_intstatus : 1; + /* DMA transfer done interrupt status enable */ + uint64_t enable_dma_tfr_done_intstat : 1; + /* Bit 2 reserved */ + uint64_t rsvd1 : 1; + /* Bit 3 source transaction complete status enable */ + uint64_t enable_src_transcomp_intstat : 1; + /* Bit 4 destination transaction complete */ + uint64_t enable_dst_transcomp_intstat : 1; + /* Bit 5 Source Decode Error Status Enable */ + uint64_t enable_src_dec_err_intstat : 1; + /* Bit 6 Destination Decode Error Status Enable */ + uint64_t enable_dst_dec_err_intstat : 1; + /* Bit 7 Source Slave Error Status Enable */ + uint64_t enable_src_slv_err_intstat : 1; + /* Bit 8 Destination Slave Error Status Enable */ + uint64_t enable_dst_slv_err_intstat : 1; + /* Bit 9 LLI Read Decode Error Status Enable */ + uint64_t enable_lli_rd_dec_err_intstat : 1; + /* Bit 10 LLI WRITE Decode Error Status Enable */ + uint64_t enable_lli_wr_dec_err_intstat : 1; + /* Bit 11 LLI Read Slave Error Status Enable */ + uint64_t enable_lli_rd_slv_err_intstat : 1; + /* Bit 12 LLI WRITE Slave Error Status Enable */ + uint64_t enable_lli_wr_slv_err_intstat : 1; + uint64_t rsvd2 : 51; +}; + +union dmac_ch_intstatus_enable_u +{ + struct dmac_ch_intstatus_enable_t ch_intstatus_enable; + uint64_t data; +}; + +struct dmac_ch_intclear_t +{ + /* Bit 0 block transfer done interrupt clear bit.*/ + uint64_t blk_tfr_done_intstat : 1; + /* Bit 1 DMA transfer done interrupt clear bit */ + uint64_t dma_tfr_done_intstat : 1; + /* Bit 2 is reserved */ + uint64_t resv1 : 1; + uint64_t resv2 : 61; +} __attribute__((packed, aligned(8))); + +union dmac_ch_intclear_u +{ + uint64_t data; + struct dmac_ch_intclear_t intclear; +}; + +struct dmac_channel_t +{ + /* (0x100) SAR Address Register */ + uint64_t sar; + /* (0x108) DAR Address Register */ + uint64_t dar; + /* (0x110) Block Transfer Size Register */ + uint64_t block_ts; + /* (0x118) Control Register */ + uint64_t ctl; + /* (0x120) Configure Register */ + uint64_t cfg; + /* (0x128) Linked List Pointer register */ + uint64_t llp; + /* (0x130) Channelx Status Register */ + uint64_t status; + /* (0x138) Channelx Software handshake Source Register */ + uint64_t swhssrc; + /* (0x140) Channelx Software handshake Destination Register */ + uint64_t swhsdst; + /* (0x148) Channelx Block Transfer Resume Request Register */ + uint64_t blk_tfr; + /* (0x150) Channelx AXI ID Register */ + uint64_t axi_id; + /* (0x158) Channelx AXI QOS Register */ + uint64_t axi_qos; + /* Reserved address */ + uint64_t reserved1[4]; + /* (0x180) Interrupt Status Enable Register */ + uint64_t intstatus_en; + /* (0x188) Channelx Interrupt Status Register */ + uint64_t intstatus; + /* (0x190) Interrupt Siganl Enable Register */ + uint64_t intsignal_en; + /* (0x198) Interrupt Clear Register */ + uint64_t intclear; + uint64_t reserved2[12]; +} __attribute__((packed, aligned(8))); + +struct dmac_t +{ + /* (0x00) DMAC ID Rgister */ + uint64_t id; + /* (0x08) DMAC COMPVER Register */ + uint64_t compver; + /* (0x10) DMAC Configure Register */ + uint64_t cfg; + /* (0x18) Channel Enable Register */ + uint64_t chen; + uint64_t reserved1[2]; + /* (0x30) DMAC Interrupt Status Register */ + uint64_t intstatus; + /* (0x38) DMAC Common register Interrupt Status Register */ + uint64_t com_intclear; + /* (0x40) DMAC Common Interrupt Enable Register */ + uint64_t com_intstatus_en; + /* (0x48) DMAC Common Interrupt Signal Enable Register */ + uint64_t com_intsignal_en; + /* (0x50) DMAC Common Interrupt Status */ + uint64_t com_intstatus; + /* (0x58) DMAC Reset register */ + uint64_t reset; + uint64_t reserved2[20]; + struct dmac_channel_t channel[DMAC_CHANNEL_COUNT]; +} __attribute__((packed, aligned(8))); + +struct dmac_channel_config_t +{ + uint64_t sar; + uint64_t dar; + uint8_t ctl_sms; + uint8_t ctl_dms; + uint8_t ctl_src_msize; + uint8_t ctl_drc_msize; + uint8_t ctl_sinc; + uint8_t ctl_dinc; + uint8_t ctl_src_tr_width; + uint8_t ctl_dst_tr_width; + uint8_t ctl_ioc_blktfr; + uint8_t ctl_src_stat_en; + uint8_t ctl_dst_stat_en; + uint8_t cfg_dst_per; + uint8_t cfg_src_per; + uint8_t cfg_src_hs_pol; + uint8_t cfg_dst_hs_pol; + uint8_t cfg_hs_sel_src; + uint8_t cfg_hs_sel_dst; + uint64_t cfg_src_multblk_type; + uint64_t cfg_dst_multblk_type; + uint64_t llp_loc; + uint8_t llp_lms; + uint64_t ctl_block_ts; + uint8_t ctl_tt_fc; + uint8_t cfg_protctl; + uint8_t cfg_fifo_mode; + uint8_t cfg_fcmode; + uint8_t cfg_lock_ch_l; + uint8_t cfg_ch_prior; +}; + +#define LIST_ENTRY(ptr, type, member) \ + ((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member))) + +struct list_head_t +{ + struct list_head_t *next, *prev; +}; + +/** + * @brief Dmac.data/dw_dmac_lli_item + * + * @desc This structure is used when creating Linked List Items. + * + * @see dw_dmac_addLliItem() + */ +struct dmac_lli_item_t +{ + uint64_t sar; + uint64_t dar; + uint64_t ch_block_ts; + uint64_t llp; + uint64_t ctl; + uint64_t sstat; + uint64_t dstat; + uint64_t resv; +} __attribute__((packed, aligned(64))); + +extern volatile struct dmac_t *const dmac; + +/** + * @brief Dmac initialize + */ +void dmac_init(void); + +/** + * @brief Read dmac id + * + * @return Dmac id + */ +uint64_t dmac_read_id(void); + +/** + * @brief Read dmac component version + * + * @return Dmac version + */ +uint64_t dmac_read_version(void); + +/** + * @brief Read AXI channel id + * + * @param[in] channel_num The channel number + * + * @return channel AXI ID data + */ +uint64_t dmac_read_channel_id(dmac_channel_number ch); + +/** + * @brief Set channle configure + * + * @param[in] channel_num The channel number + * @param[in] cfg_param The configuration parameter + * + * @return result + * - 0 Success + * - Other Fail + */ +int dmac_set_channel_config(dmac_channel_number channel_num, + struct dmac_channel_config_t *cfg_param); + +/** + * @brief Get channel configure param + * + * @param[in] channel_num The channel number + * @param[out] cfg_param The configuration parameter + * + * @return result + * - 0 Success + * - Other Fail + */ +int dmac_get_channel_config(dmac_channel_number channel_num, + struct dmac_channel_config_t *cfg_param); + +/** + * @brief Enable dmac source transaction complete interrupt + * + * @param[in] channel_num The channel number + */ +void src_transaction_complete_int_enable(dmac_channel_number channel_num); + +/** + * @brief Enable dmac channel + * + * @param[in] channel_num The channel number + */ +void dmac_channel_enable(dmac_channel_number channel_num); + +/** + * @brief Enable dmac + */ +void dmac_enable(void); + +/** + * @brief Enable dmac channel interrupt status + * + * @param[in] channel_num The channel number + */ +void dmac_enable_channel_interrupt_status(dmac_channel_number channel_num); + +/** + * @brief Disable dmac channel interrupt status + * + * @param[in] channel_num The channel number + */ +void dmac_disable_channel_interrupt_status(dmac_channel_number channel_num); + +/** + * @brief Check whether channel is busy + * + * @param[in] channel_num The channel number + * + * @return result + * - 0 Not busy + * - 1 Busy + */ +int32_t dmac_check_channel_busy(dmac_channel_number channel_num); + +/** + * @brief Clear interrupt status + * + * @param[in] channel_num The channel number + */ +void dmac_chanel_interrupt_clear(dmac_channel_number channel_num); + +/** + * @brief Create link list item + * + * @param[in] channel_num The channel number + * @param[in] LLI_row_num The lli row number + * @param[in] LLI_last_row The lli last row + * @param[out] lli_item The lli item + * @param[in] cfg_param The configuration parameter + */ +void dmac_link_list_item(dmac_channel_number channel_num, uint8_t lli_row_num, + int8_t lli_last_row, struct dmac_lli_item_t *lli_item, + struct dmac_channel_config_t *cfg_param); + +/** + * @brief linked list mode list addr entry, + * descriptor table must be 64 byte aligned + * + * @param[in] channel_num The channel number + * @param[in] addr The address + */ +void dmac_set_linked_list_addr_point(dmac_channel_number channel_num, + uint64_t *addr); + +/** + * @brief Set flow control + * + * @param[in] channel_num The channel number + * @param[in] flow_control The flow control + */ +void dmac_set_flow_control(dmac_channel_number channel_num, + enum dmac_transfer_flow flow_control); + +/** + * @brief Set multitransfer type and handshake + * + * @param[in] channel_num The channel number + * @param[in] transfer_type The transfer type + * @param[in] handshak_select The handshake select + */ +void dmac_set_destination_transfer_control(dmac_channel_number channel_num, + enum dmac_multiblk_transfer_type transfer_type, + enum dmac_sw_hw_hs_select handshak_select); + +/** + * @brief Set multitransfer type and handshak + * + * @param[in] channel_num The channel number + * @param[in] transfer_type The transfer type + * @param[in] handshak_select The handshake select + */ +void dmac_set_source_transfer_control(dmac_channel_number channel_num, + enum dmac_multiblk_transfer_type transfer_type, + enum dmac_sw_hw_hs_select handshak_select); + +/** + * @brief Set destination's master,address mode, transfer width and transfer length + * + * @param[in] channel_num The channel number + * @param[in] master_select The master select + * @param[in] address_mode The address mode + * @param[in] tr_width The tr width + * @param[in] burst_length The burst length + */ +void dmac_master_control(dmac_channel_number channel_num, + enum dmac_master_number master_select, + enum dmac_address_increment address_mode, + enum dmac_transfer_width tr_width, + enum dmac_burst_trans_length burst_length); + +/** + * @brief Set source's master,address mode, transfer width and transfer length + * + * @param[in] channel_num The channel number + * @param[in] master_select The master select + * @param[in] address_mode The address mode + * @param[in] tr_width The transfer width + * @param[in] burst_length The burst transfer length + */ +void dmac_source_control(dmac_channel_number channel_num, + enum dmac_master_number master_select, + enum dmac_address_increment address_mode, + enum dmac_transfer_width tr_width, + enum dmac_burst_trans_length burst_length); + +/** + * @brief Set block transfer size + * + * @param[in] channel_num The channel number + * @param[in] block_size The block size + */ +void dmac_set_block_ts(dmac_channel_number channel_num, uint32_t block_size); + +/** + * @brief Set dmac address + * + * @param[in] channel_num The channel number + * @param src_addr The source address + * @param dst_src The destination source + */ +void dmac_set_address(dmac_channel_number channel_num, uint64_t src_addr, + uint64_t dst_addr); + +/** + * @brief Disable channel + * + * @param[in] channel_num The channel number + */ +void dmac_channel_disable(dmac_channel_number channel_num); + +/** + * @brief Update dmac shadow register + * + * @param[in] channel_num The channel number + * @param[in] last_block The last block + * @param[in] cfg_param The configuration parameter + */ +void dmac_update_shandow_register(dmac_channel_number channel_num, int8_t last_block, + struct dmac_channel_config_t *cfg_param); + +/** + * @brief Set shadow register invalid flag, used for first block transfer, after configure + * + * @param[in] channel_num The channel number + */ +void dmac_set_shadow_invalid_flag(dmac_channel_number channel_num); + +/** + * @brief Set dmac channel parameters + * + * @param[in] channel_num The channel number + * @param[in] src The source address + * @param[in] dest The destination address + * @param[in] src_inc Whether the source address auto increment + * @param[in] dest_inc Whether the destination address auto increment + * @param[in] dmac_msize The dmac burst transfer length + * @param[in] dmac_trans_width The dmac transfer width + * @param[in] blockSize The block size + * + * @return result + * - 0 Success + * - Other Fail + */ +int dmac_set_channel_param(dmac_channel_number channel_num, + void *src, void *dest, enum dmac_address_increment src_inc, enum dmac_address_increment dest_inc, + enum dmac_burst_trans_length dmac_msize, + enum dmac_transfer_width dmac_trans_width, + uint32_t blockSize); + +/** + * @brief Set dmac param + * + * @param[in] channel_num Dmac channel + * @param[in] src Dmac source + * @param[in] dest Dmac dest + * @param[in] src_inc Source address increase or not + * @param[in] dest_inc Dest address increase or not + * @param[in] dmac_msize Dmac burst length + * @param[in] dmac_trans_width Dmac transfer data width + * @param[in] blockSize Dmac transfer length + * + */ +void dmac_set_single_mode(dmac_channel_number channel_num, + void *src, void *dest, enum dmac_address_increment src_inc, enum dmac_address_increment dest_inc, + enum dmac_burst_trans_length dmac_msize, + enum dmac_transfer_width dmac_trans_width, + uint32_t blockSize); + +/** + * @brief Wait for dmac work done + * + * @param[in] channel_num Dmac channel + * + */ +void dmac_wait_done(dmac_channel_number channel_num); + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_DMAC_H */ diff --git a/lib/drivers/include/dvp.h b/lib/drivers/include/dvp.h new file mode 100644 index 0000000..9041d4d --- /dev/null +++ b/lib/drivers/include/dvp.h @@ -0,0 +1,284 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _DRIVER_DVP_H +#define _DRIVER_DVP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* clang-format off */ +/** + * @brief DVP object + */ +struct dvp_t +{ + volatile uint32_t dvp_cfg; + volatile uint32_t r_addr; + volatile uint32_t g_addr; + volatile uint32_t b_addr; + volatile uint32_t cmos_cfg; + volatile uint32_t sccb_cfg; + volatile uint32_t sccb_ctl; + volatile uint32_t axi; + volatile uint32_t sts; + volatile uint32_t reverse; + volatile uint32_t rgb_addr; +} __attribute__((packed, aligned(4))); + +/* DVP Config Register */ +#define DVP_CFG_START_INT_ENABLE 0x00000001 +#define DVP_CFG_FINISH_INT_ENABLE 0x00000002 +#define DVP_CFG_AI_OUTPUT_ENABLE 0x00000004 +#define DVP_CFG_DISPLAY_OUTPUT_ENABLE 0x00000008 +#define DVP_CFG_AUTO_ENABLE 0x00000010 +#define DVP_CFG_BURST_SIZE_4BEATS 0x00000100 +#define DVP_CFG_FORMAT_MASK 0x00000600 +#define DVP_CFG_RGB_FORMAT 0x00000000 +#define DVP_CFG_YUV_FORMAT 0x00000200 +#define DVP_CFG_Y_FORMAT 0x00000600 +#define DVP_CFG_HREF_BURST_NUM_MASK 0x000FF000 +#define DVP_CFG_HREF_BURST_NUM(x) ((x) << 12) +#define DVP_CFG_LINE_NUM_MASK 0x3FF00000 +#define DVP_CFG_LINE_NUM(x) ((x) << 20) + +/* DVP CMOS Config Register */ +#define DVP_CMOS_CLK_DIV_MASK 0x000000FF +#define DVP_CMOS_CLK_DIV(x) ((x) << 0) +#define DVP_CMOS_CLK_ENABLE 0x00000100 +#define DVP_CMOS_RESET 0x00010000 +#define DVP_CMOS_POWER_DOWN 0x01000000 + +/* DVP SCCB Config Register */ +#define DVP_SCCB_BYTE_NUM_MASK 0x00000003 +#define DVP_SCCB_BYTE_NUM_2 0x00000001 +#define DVP_SCCB_BYTE_NUM_3 0x00000002 +#define DVP_SCCB_BYTE_NUM_4 0x00000003 +#define DVP_SCCB_SCL_LCNT_MASK 0x0000FF00 +#define DVP_SCCB_SCL_LCNT(x) ((x) << 8) +#define DVP_SCCB_SCL_HCNT_MASK 0x00FF0000 +#define DVP_SCCB_SCL_HCNT(x) ((x) << 16) +#define DVP_SCCB_RDATA_BYTE(x) ((x) >> 24) + +/* DVP SCCB Control Register */ +#define DVP_SCCB_WRITE_ENABLE 0x00000001 +#define DVP_SCCB_DEVICE_ADDRESS(x) ((x) << 0) +#define DVP_SCCB_REG_ADDRESS(x) ((x) << 8) +#define DVP_SCCB_WDATA_BYTE0(x) ((x) << 16) +#define DVP_SCCB_WDATA_BYTE1(x) ((x) << 24) + +/* DVP AXI Register */ +#define DVP_AXI_GM_MLEN_MASK 0x000000FF +#define DVP_AXI_GM_MLEN_1BYTE 0x00000000 +#define DVP_AXI_GM_MLEN_4BYTE 0x00000003 + +/* DVP STS Register */ +#define DVP_STS_FRAME_START 0x00000001 +#define DVP_STS_FRAME_START_WE 0x00000002 +#define DVP_STS_FRAME_FINISH 0x00000100 +#define DVP_STS_FRAME_FINISH_WE 0x00000200 +#define DVP_STS_DVP_EN 0x00010000 +#define DVP_STS_DVP_EN_WE 0x00020000 +#define DVP_STS_SCCB_EN 0x01000000 +#define DVP_STS_SCCB_EN_WE 0x02000000 +/* clang-format on */ + +/** + * @brief DVP object instance + */ +extern volatile struct dvp_t* const dvp; + +/** + * @brief Initialize DVP + * + * @return result + * - 0 Success + * - Other Fail + */ +int dvp_init(uint8_t reglen); + +/** + * @brief Set image format + * + * @param[in] format The image format + * + * @return result + * - 0 Success + * - Other Fail + */ +int dvp_set_image_format(uint32_t format); + +/** + * @brief Set image size + * + * @param[in] width The width of image + * @param[in] height The height of image + * + * @return result + * - 0 Success + * - Other Fail + */ +int dvp_set_image_size(uint32_t width, uint32_t height); + +/** + * @brief Set the address of RGB for AI + * + * @param[in] r_addr The R address of RGB + * @param[in] g_addr The G address of RGB + * @param[in] b_addr The B address of RGB + * + * @return result + * - 0 Success + * - Other Fail + */ +int dvp_set_ai_addr(uint32_t r_addr, uint32_t g_addr, uint32_t b_addr); + +/** + * @brief Set the address of RGB for display + * + * @param[in] r_addr The R address of RGB + * @param[in] g_addr The G address of RGB + * @param[in] b_addr The B address of RGB + * + * @return result + * - 0 Success + * - Other Fail + */ +int dvp_set_display_addr(uint32_t addr); + +/** + * @brief The frame start transfer + * + * @return result + * - 0 Success + * - Other Fail + */ +int dvp_frame_start(void); + +/** + * @brief The DVP convert start + * + * @return result + * - 0 Success + * - Other Fail + */ +void dvp_convert_start(void); + +/** + * @brief The DVP convert finish + * + * @return result + * - 0 Success + * - Other Fail + */ +int dvp_convert_finish(void); + +/** + * @brief Get the image data + * + * @note The image data stored in the address of RGB + * + * @return result + * - 0 Success + * - Other Fail + */ +int dvp_get_image(void); + +/** + * @brief Use SCCB write register + * + * @param[in] dev_addr The device address + * @param[in] reg_addr The register address + * @param[in] reg_data The register data + * + * @return result + * - 0 Success + * - Other Fail + */ +int dvp_sccb_write(uint8_t dev_addr, uint16_t reg_addr, uint8_t reg_data); + +/** + * @brief Use SCCB read register + * + * @param[in] dev_addr The device address + * @param[in] reg_addr The register address + * + * @return The register value + */ +uint8_t dvp_sccb_read(uint8_t dev_addr, uint16_t reg_addr); + +/** + * @brief Enable dvp burst + */ +void dvp_burst_enable(void); + +/** + * @brief Disable dvp burst + */ +void dvp_burst_disable(void); + +/** + * @brief Enable or disable dvp interrupt + * + * @param[in] interrupt Dvp interrupt + * @param[in] status 0:disable 1:enable + * + */ +void dvp_interrupt_config(uint32_t interrupt, uint8_t status); + +/** + * @brief Get dvp interrupt status + * + * @param[in] interrupt Dvp interrupt + * + * + * @return Interrupt status + * - 0 false + * - 1 true + */ +int dvp_interrupt_get(uint32_t interrupt); + +/** + * @brief Clear dvp interrupt status + * + * @param[in] interrupt Dvp interrupt + * + */ +void dvp_interrupt_clear(uint32_t interrupt); + +/** + * @brief Enable dvp auto mode + */ +void dvp_enable_auto(void); + +/** + * @brief Disable dvp auto mode + */ +void dvp_disable_auto(void); + +/** + * @brief Dvp ouput data enable or not + * + * @param[in] index 0:AI, 1:display + * @param[in] enable 0:disable, 1:enable + * + */ +void dvp_set_output_enable(size_t index, int enable); + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_DVP_H */ diff --git a/lib/drivers/include/fpioa.h b/lib/drivers/include/fpioa.h new file mode 100644 index 0000000..eb5bb18 --- /dev/null +++ b/lib/drivers/include/fpioa.h @@ -0,0 +1,980 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file + * @brief Field Programmable GPIO Array (FPIOA) + * + * The FPIOA peripheral supports the following features: + * + * - 48 IO with 256 functions + * + * - Schmitt trigger + * + * - Invert input and output + * + * - Pull up and pull down + * + * - Driving selector + * + * - Static input and output + * + */ + +#ifndef _DRIVER_FPIOA_H +#define _DRIVER_FPIOA_H + +#include +#include "platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* clang-format off */ +/* Pad number settings */ +#define FPIOA_NUM_IO (48) +/* clang-format on */ + +/** + * @brief FPIOA IO functions + * + * @note FPIOA pin function table + * + * | Function | Name | Description | + * |-----------|------------------|-----------------------------------| + * | 0 | JTAG_TCLK | JTAG Test Clock | + * | 1 | JTAG_TDI | JTAG Test Data In | + * | 2 | JTAG_TMS | JTAG Test Mode Select | + * | 3 | JTAG_TDO | JTAG Test Data Out | + * | 4 | SPI0_D0 | SPI0 Data 0 | + * | 5 | SPI0_D1 | SPI0 Data 1 | + * | 6 | SPI0_D2 | SPI0 Data 2 | + * | 7 | SPI0_D3 | SPI0 Data 3 | + * | 8 | SPI0_D4 | SPI0 Data 4 | + * | 9 | SPI0_D5 | SPI0 Data 5 | + * | 10 | SPI0_D6 | SPI0 Data 6 | + * | 11 | SPI0_D7 | SPI0 Data 7 | + * | 12 | SPI0_SS0 | SPI0 Chip Select 0 | + * | 13 | SPI0_SS1 | SPI0 Chip Select 1 | + * | 14 | SPI0_SS2 | SPI0 Chip Select 2 | + * | 15 | SPI0_SS3 | SPI0 Chip Select 3 | + * | 16 | SPI0_ARB | SPI0 Arbitration | + * | 17 | SPI0_SCLK | SPI0 Serial Clock | + * | 18 | UARTHS_RX | UART High speed Receiver | + * | 19 | UARTHS_TX | UART High speed Transmitter | + * | 20 | CLK_IN1 | Clock Input 1 | + * | 21 | CLK_IN2 | Clock Input 2 | + * | 22 | CLK_SPI1 | Clock SPI1 | + * | 23 | CLK_I2C1 | Clock I2C1 | + * | 24 | GPIOHS0 | GPIO High speed 0 | + * | 25 | GPIOHS1 | GPIO High speed 1 | + * | 26 | GPIOHS2 | GPIO High speed 2 | + * | 27 | GPIOHS3 | GPIO High speed 3 | + * | 28 | GPIOHS4 | GPIO High speed 4 | + * | 29 | GPIOHS5 | GPIO High speed 5 | + * | 30 | GPIOHS6 | GPIO High speed 6 | + * | 31 | GPIOHS7 | GPIO High speed 7 | + * | 32 | GPIOHS8 | GPIO High speed 8 | + * | 33 | GPIOHS9 | GPIO High speed 9 | + * | 34 | GPIOHS10 | GPIO High speed 10 | + * | 35 | GPIOHS11 | GPIO High speed 11 | + * | 36 | GPIOHS12 | GPIO High speed 12 | + * | 37 | GPIOHS13 | GPIO High speed 13 | + * | 38 | GPIOHS14 | GPIO High speed 14 | + * | 39 | GPIOHS15 | GPIO High speed 15 | + * | 40 | GPIOHS16 | GPIO High speed 16 | + * | 41 | GPIOHS17 | GPIO High speed 17 | + * | 42 | GPIOHS18 | GPIO High speed 18 | + * | 43 | GPIOHS19 | GPIO High speed 19 | + * | 44 | GPIOHS20 | GPIO High speed 20 | + * | 45 | GPIOHS21 | GPIO High speed 21 | + * | 46 | GPIOHS22 | GPIO High speed 22 | + * | 47 | GPIOHS23 | GPIO High speed 23 | + * | 48 | GPIOHS24 | GPIO High speed 24 | + * | 49 | GPIOHS25 | GPIO High speed 25 | + * | 50 | GPIOHS26 | GPIO High speed 26 | + * | 51 | GPIOHS27 | GPIO High speed 27 | + * | 52 | GPIOHS28 | GPIO High speed 28 | + * | 53 | GPIOHS29 | GPIO High speed 29 | + * | 54 | GPIOHS30 | GPIO High speed 30 | + * | 55 | GPIOHS31 | GPIO High speed 31 | + * | 56 | GPIO0 | GPIO pin 0 | + * | 57 | GPIO1 | GPIO pin 1 | + * | 58 | GPIO2 | GPIO pin 2 | + * | 59 | GPIO3 | GPIO pin 3 | + * | 60 | GPIO4 | GPIO pin 4 | + * | 61 | GPIO5 | GPIO pin 5 | + * | 62 | GPIO6 | GPIO pin 6 | + * | 63 | GPIO7 | GPIO pin 7 | + * | 64 | UART1_RX | UART1 Receiver | + * | 65 | UART1_TX | UART1 Transmitter | + * | 66 | UART2_RX | UART2 Receiver | + * | 67 | UART2_TX | UART2 Transmitter | + * | 68 | UART3_RX | UART3 Receiver | + * | 69 | UART3_TX | UART3 Transmitter | + * | 70 | SPI1_D0 | SPI1 Data 0 | + * | 71 | SPI1_D1 | SPI1 Data 1 | + * | 72 | SPI1_D2 | SPI1 Data 2 | + * | 73 | SPI1_D3 | SPI1 Data 3 | + * | 74 | SPI1_D4 | SPI1 Data 4 | + * | 75 | SPI1_D5 | SPI1 Data 5 | + * | 76 | SPI1_D6 | SPI1 Data 6 | + * | 77 | SPI1_D7 | SPI1 Data 7 | + * | 78 | SPI1_SS0 | SPI1 Chip Select 0 | + * | 79 | SPI1_SS1 | SPI1 Chip Select 1 | + * | 80 | SPI1_SS2 | SPI1 Chip Select 2 | + * | 81 | SPI1_SS3 | SPI1 Chip Select 3 | + * | 82 | SPI1_ARB | SPI1 Arbitration | + * | 83 | SPI1_SCLK | SPI1 Serial Clock | + * | 84 | SPI_SLAVE_D0 | SPI Slave Data 0 | + * | 85 | SPI_SLAVE_SS | SPI Slave Select | + * | 86 | SPI_SLAVE_SCLK | SPI Slave Serial Clock | + * | 87 | I2S0_MCLK | I2S0 Master Clock | + * | 88 | I2S0_SCLK | I2S0 Serial Clock(BCLK) | + * | 89 | I2S0_WS | I2S0 Word Select(LRCLK) | + * | 90 | I2S0_IN_D0 | I2S0 Serial Data Input 0 | + * | 91 | I2S0_IN_D1 | I2S0 Serial Data Input 1 | + * | 92 | I2S0_IN_D2 | I2S0 Serial Data Input 2 | + * | 93 | I2S0_IN_D3 | I2S0 Serial Data Input 3 | + * | 94 | I2S0_OUT_D0 | I2S0 Serial Data Output 0 | + * | 95 | I2S0_OUT_D1 | I2S0 Serial Data Output 1 | + * | 96 | I2S0_OUT_D2 | I2S0 Serial Data Output 2 | + * | 97 | I2S0_OUT_D3 | I2S0 Serial Data Output 3 | + * | 98 | I2S1_MCLK | I2S1 Master Clock | + * | 99 | I2S1_SCLK | I2S1 Serial Clock(BCLK) | + * | 100 | I2S1_WS | I2S1 Word Select(LRCLK) | + * | 101 | I2S1_IN_D0 | I2S1 Serial Data Input 0 | + * | 102 | I2S1_IN_D1 | I2S1 Serial Data Input 1 | + * | 103 | I2S1_IN_D2 | I2S1 Serial Data Input 2 | + * | 104 | I2S1_IN_D3 | I2S1 Serial Data Input 3 | + * | 105 | I2S1_OUT_D0 | I2S1 Serial Data Output 0 | + * | 106 | I2S1_OUT_D1 | I2S1 Serial Data Output 1 | + * | 107 | I2S1_OUT_D2 | I2S1 Serial Data Output 2 | + * | 108 | I2S1_OUT_D3 | I2S1 Serial Data Output 3 | + * | 109 | I2S2_MCLK | I2S2 Master Clock | + * | 110 | I2S2_SCLK | I2S2 Serial Clock(BCLK) | + * | 111 | I2S2_WS | I2S2 Word Select(LRCLK) | + * | 112 | I2S2_IN_D0 | I2S2 Serial Data Input 0 | + * | 113 | I2S2_IN_D1 | I2S2 Serial Data Input 1 | + * | 114 | I2S2_IN_D2 | I2S2 Serial Data Input 2 | + * | 115 | I2S2_IN_D3 | I2S2 Serial Data Input 3 | + * | 116 | I2S2_OUT_D0 | I2S2 Serial Data Output 0 | + * | 117 | I2S2_OUT_D1 | I2S2 Serial Data Output 1 | + * | 118 | I2S2_OUT_D2 | I2S2 Serial Data Output 2 | + * | 119 | I2S2_OUT_D3 | I2S2 Serial Data Output 3 | + * | 120 | RESV0 | Reserved function | + * | 121 | RESV1 | Reserved function | + * | 122 | RESV2 | Reserved function | + * | 123 | RESV3 | Reserved function | + * | 124 | RESV4 | Reserved function | + * | 125 | RESV5 | Reserved function | + * | 126 | I2C0_SCLK | I2C0 Serial Clock | + * | 127 | I2C0_SDA | I2C0 Serial Data | + * | 128 | I2C1_SCLK | I2C1 Serial Clock | + * | 129 | I2C1_SDA | I2C1 Serial Data | + * | 130 | I2C2_SCLK | I2C2 Serial Clock | + * | 131 | I2C2_SDA | I2C2 Serial Data | + * | 132 | CMOS_XCLK | DVP System Clock | + * | 133 | CMOS_RST | DVP System Reset | + * | 134 | CMOS_PWND | DVP Power Down Mode | + * | 135 | CMOS_VSYNC | DVP Vertical Sync | + * | 136 | CMOS_HREF | DVP Horizontal Reference output | + * | 137 | CMOS_PCLK | Pixel Clock | + * | 138 | CMOS_D0 | Data Bit 0 | + * | 139 | CMOS_D1 | Data Bit 1 | + * | 140 | CMOS_D2 | Data Bit 2 | + * | 141 | CMOS_D3 | Data Bit 3 | + * | 142 | CMOS_D4 | Data Bit 4 | + * | 143 | CMOS_D5 | Data Bit 5 | + * | 144 | CMOS_D6 | Data Bit 6 | + * | 145 | CMOS_D7 | Data Bit 7 | + * | 146 | SCCB_SCLK | SCCB Serial Clock | + * | 147 | SCCB_SDA | SCCB Serial Data | + * | 148 | UART1_CTS | UART1 Clear To Send | + * | 149 | UART1_DSR | UART1 Data Set Ready | + * | 150 | UART1_DCD | UART1 Data Carrier Detect | + * | 151 | UART1_RI | UART1 Ring Indicator | + * | 152 | UART1_SIR_IN | UART1 Serial Infrared Input | + * | 153 | UART1_DTR | UART1 Data Terminal Ready | + * | 154 | UART1_RTS | UART1 Request To Send | + * | 155 | UART1_OUT2 | UART1 User-designated Output 2 | + * | 156 | UART1_OUT1 | UART1 User-designated Output 1 | + * | 157 | UART1_SIR_OUT | UART1 Serial Infrared Output | + * | 158 | UART1_BAUD | UART1 Transmit Clock Output | + * | 159 | UART1_RE | UART1 Receiver Output Enable | + * | 160 | UART1_DE | UART1 Driver Output Enable | + * | 161 | UART1_RS485_EN | UART1 RS485 Enable | + * | 162 | UART2_CTS | UART2 Clear To Send | + * | 163 | UART2_DSR | UART2 Data Set Ready | + * | 164 | UART2_DCD | UART2 Data Carrier Detect | + * | 165 | UART2_RI | UART2 Ring Indicator | + * | 166 | UART2_SIR_IN | UART2 Serial Infrared Input | + * | 167 | UART2_DTR | UART2 Data Terminal Ready | + * | 168 | UART2_RTS | UART2 Request To Send | + * | 169 | UART2_OUT2 | UART2 User-designated Output 2 | + * | 170 | UART2_OUT1 | UART2 User-designated Output 1 | + * | 171 | UART2_SIR_OUT | UART2 Serial Infrared Output | + * | 172 | UART2_BAUD | UART2 Transmit Clock Output | + * | 173 | UART2_RE | UART2 Receiver Output Enable | + * | 174 | UART2_DE | UART2 Driver Output Enable | + * | 175 | UART2_RS485_EN | UART2 RS485 Enable | + * | 176 | UART3_CTS | UART3 Clear To Send | + * | 177 | UART3_DSR | UART3 Data Set Ready | + * | 178 | UART3_DCD | UART3 Data Carrier Detect | + * | 179 | UART3_RI | UART3 Ring Indicator | + * | 180 | UART3_SIR_IN | UART3 Serial Infrared Input | + * | 181 | UART3_DTR | UART3 Data Terminal Ready | + * | 182 | UART3_RTS | UART3 Request To Send | + * | 183 | UART3_OUT2 | UART3 User-designated Output 2 | + * | 184 | UART3_OUT1 | UART3 User-designated Output 1 | + * | 185 | UART3_SIR_OUT | UART3 Serial Infrared Output | + * | 186 | UART3_BAUD | UART3 Transmit Clock Output | + * | 187 | UART3_RE | UART3 Receiver Output Enable | + * | 188 | UART3_DE | UART3 Driver Output Enable | + * | 189 | UART3_RS485_EN | UART3 RS485 Enable | + * | 190 | TIMER0_TOGGLE1 | TIMER0 Toggle Output 1 | + * | 191 | TIMER0_TOGGLE2 | TIMER0 Toggle Output 2 | + * | 192 | TIMER0_TOGGLE3 | TIMER0 Toggle Output 3 | + * | 193 | TIMER0_TOGGLE4 | TIMER0 Toggle Output 4 | + * | 194 | TIMER1_TOGGLE1 | TIMER1 Toggle Output 1 | + * | 195 | TIMER1_TOGGLE2 | TIMER1 Toggle Output 2 | + * | 196 | TIMER1_TOGGLE3 | TIMER1 Toggle Output 3 | + * | 197 | TIMER1_TOGGLE4 | TIMER1 Toggle Output 4 | + * | 198 | TIMER2_TOGGLE1 | TIMER2 Toggle Output 1 | + * | 199 | TIMER2_TOGGLE2 | TIMER2 Toggle Output 2 | + * | 200 | TIMER2_TOGGLE3 | TIMER2 Toggle Output 3 | + * | 201 | TIMER2_TOGGLE4 | TIMER2 Toggle Output 4 | + * | 202 | CLK_SPI2 | Clock SPI2 | + * | 203 | CLK_I2C2 | Clock I2C2 | + * | 222 | CONSTANT | Constant function | + * | 224 | DEBUG0 | Debug function 0 | + * | 225 | DEBUG1 | Debug function 1 | + * | 226 | DEBUG2 | Debug function 2 | + * | 227 | DEBUG3 | Debug function 3 | + * | 228 | DEBUG4 | Debug function 4 | + * | 229 | DEBUG5 | Debug function 5 | + * | 230 | DEBUG6 | Debug function 6 | + * | 231 | DEBUG7 | Debug function 7 | + * | 232 | DEBUG8 | Debug function 8 | + * | 233 | DEBUG9 | Debug function 9 | + * | 234 | DEBUG10 | Debug function 10 | + * | 235 | DEBUG11 | Debug function 11 | + * | 236 | DEBUG12 | Debug function 12 | + * | 237 | DEBUG13 | Debug function 13 | + * | 238 | DEBUG14 | Debug function 14 | + * | 239 | DEBUG15 | Debug function 15 | + * | 240 | DEBUG16 | Debug function 16 | + * | 241 | DEBUG17 | Debug function 17 | + * | 242 | DEBUG18 | Debug function 18 | + * | 243 | DEBUG19 | Debug function 19 | + * | 244 | DEBUG20 | Debug function 20 | + * | 245 | DEBUG21 | Debug function 21 | + * | 246 | DEBUG22 | Debug function 22 | + * | 247 | DEBUG23 | Debug function 23 | + * | 248 | DEBUG24 | Debug function 24 | + * | 249 | DEBUG25 | Debug function 25 | + * | 250 | DEBUG26 | Debug function 26 | + * | 251 | DEBUG27 | Debug function 27 | + * | 252 | DEBUG28 | Debug function 28 | + * | 253 | DEBUG29 | Debug function 29 | + * | 254 | DEBUG30 | Debug function 30 | + * | 255 | DEBUG31 | Debug function 31 | + * + * Any IO of FPIOA have 256 functions, it is a IO-function matrix. + * All IO have default reset function, after reset, re-configure + * IO function is required. + */ + +/* clang-format off */ +enum fpioa_function_e +{ + FUNC_JTAG_TCLK = 0, /*!< JTAG Test Clock */ + FUNC_JTAG_TDI = 1, /*!< JTAG Test Data In */ + FUNC_JTAG_TMS = 2, /*!< JTAG Test Mode Select */ + FUNC_JTAG_TDO = 3, /*!< JTAG Test Data Out */ + FUNC_SPI0_D0 = 4, /*!< SPI0 Data 0 */ + FUNC_SPI0_D1 = 5, /*!< SPI0 Data 1 */ + FUNC_SPI0_D2 = 6, /*!< SPI0 Data 2 */ + FUNC_SPI0_D3 = 7, /*!< SPI0 Data 3 */ + FUNC_SPI0_D4 = 8, /*!< SPI0 Data 4 */ + FUNC_SPI0_D5 = 9, /*!< SPI0 Data 5 */ + FUNC_SPI0_D6 = 10, /*!< SPI0 Data 6 */ + FUNC_SPI0_D7 = 11, /*!< SPI0 Data 7 */ + FUNC_SPI0_SS0 = 12, /*!< SPI0 Chip Select 0 */ + FUNC_SPI0_SS1 = 13, /*!< SPI0 Chip Select 1 */ + FUNC_SPI0_SS2 = 14, /*!< SPI0 Chip Select 2 */ + FUNC_SPI0_SS3 = 15, /*!< SPI0 Chip Select 3 */ + FUNC_SPI0_ARB = 16, /*!< SPI0 Arbitration */ + FUNC_SPI0_SCLK = 17, /*!< SPI0 Serial Clock */ + FUNC_UARTHS_RX = 18, /*!< UART High speed Receiver */ + FUNC_UARTHS_TX = 19, /*!< UART High speed Transmitter */ + FUNC_CLK_IN1 = 20, /*!< Clock Input 1 */ + FUNC_CLK_IN2 = 21, /*!< Clock Input 2 */ + FUNC_CLK_SPI1 = 22, /*!< Clock SPI1 */ + FUNC_CLK_I2C1 = 23, /*!< Clock I2C1 */ + FUNC_GPIOHS0 = 24, /*!< GPIO High speed 0 */ + FUNC_GPIOHS1 = 25, /*!< GPIO High speed 1 */ + FUNC_GPIOHS2 = 26, /*!< GPIO High speed 2 */ + FUNC_GPIOHS3 = 27, /*!< GPIO High speed 3 */ + FUNC_GPIOHS4 = 28, /*!< GPIO High speed 4 */ + FUNC_GPIOHS5 = 29, /*!< GPIO High speed 5 */ + FUNC_GPIOHS6 = 30, /*!< GPIO High speed 6 */ + FUNC_GPIOHS7 = 31, /*!< GPIO High speed 7 */ + FUNC_GPIOHS8 = 32, /*!< GPIO High speed 8 */ + FUNC_GPIOHS9 = 33, /*!< GPIO High speed 9 */ + FUNC_GPIOHS10 = 34, /*!< GPIO High speed 10 */ + FUNC_GPIOHS11 = 35, /*!< GPIO High speed 11 */ + FUNC_GPIOHS12 = 36, /*!< GPIO High speed 12 */ + FUNC_GPIOHS13 = 37, /*!< GPIO High speed 13 */ + FUNC_GPIOHS14 = 38, /*!< GPIO High speed 14 */ + FUNC_GPIOHS15 = 39, /*!< GPIO High speed 15 */ + FUNC_GPIOHS16 = 40, /*!< GPIO High speed 16 */ + FUNC_GPIOHS17 = 41, /*!< GPIO High speed 17 */ + FUNC_GPIOHS18 = 42, /*!< GPIO High speed 18 */ + FUNC_GPIOHS19 = 43, /*!< GPIO High speed 19 */ + FUNC_GPIOHS20 = 44, /*!< GPIO High speed 20 */ + FUNC_GPIOHS21 = 45, /*!< GPIO High speed 21 */ + FUNC_GPIOHS22 = 46, /*!< GPIO High speed 22 */ + FUNC_GPIOHS23 = 47, /*!< GPIO High speed 23 */ + FUNC_GPIOHS24 = 48, /*!< GPIO High speed 24 */ + FUNC_GPIOHS25 = 49, /*!< GPIO High speed 25 */ + FUNC_GPIOHS26 = 50, /*!< GPIO High speed 26 */ + FUNC_GPIOHS27 = 51, /*!< GPIO High speed 27 */ + FUNC_GPIOHS28 = 52, /*!< GPIO High speed 28 */ + FUNC_GPIOHS29 = 53, /*!< GPIO High speed 29 */ + FUNC_GPIOHS30 = 54, /*!< GPIO High speed 30 */ + FUNC_GPIOHS31 = 55, /*!< GPIO High speed 31 */ + FUNC_GPIO0 = 56, /*!< GPIO pin 0 */ + FUNC_GPIO1 = 57, /*!< GPIO pin 1 */ + FUNC_GPIO2 = 58, /*!< GPIO pin 2 */ + FUNC_GPIO3 = 59, /*!< GPIO pin 3 */ + FUNC_GPIO4 = 60, /*!< GPIO pin 4 */ + FUNC_GPIO5 = 61, /*!< GPIO pin 5 */ + FUNC_GPIO6 = 62, /*!< GPIO pin 6 */ + FUNC_GPIO7 = 63, /*!< GPIO pin 7 */ + FUNC_UART1_RX = 64, /*!< UART1 Receiver */ + FUNC_UART1_TX = 65, /*!< UART1 Transmitter */ + FUNC_UART2_RX = 66, /*!< UART2 Receiver */ + FUNC_UART2_TX = 67, /*!< UART2 Transmitter */ + FUNC_UART3_RX = 68, /*!< UART3 Receiver */ + FUNC_UART3_TX = 69, /*!< UART3 Transmitter */ + FUNC_SPI1_D0 = 70, /*!< SPI1 Data 0 */ + FUNC_SPI1_D1 = 71, /*!< SPI1 Data 1 */ + FUNC_SPI1_D2 = 72, /*!< SPI1 Data 2 */ + FUNC_SPI1_D3 = 73, /*!< SPI1 Data 3 */ + FUNC_SPI1_D4 = 74, /*!< SPI1 Data 4 */ + FUNC_SPI1_D5 = 75, /*!< SPI1 Data 5 */ + FUNC_SPI1_D6 = 76, /*!< SPI1 Data 6 */ + FUNC_SPI1_D7 = 77, /*!< SPI1 Data 7 */ + FUNC_SPI1_SS0 = 78, /*!< SPI1 Chip Select 0 */ + FUNC_SPI1_SS1 = 79, /*!< SPI1 Chip Select 1 */ + FUNC_SPI1_SS2 = 80, /*!< SPI1 Chip Select 2 */ + FUNC_SPI1_SS3 = 81, /*!< SPI1 Chip Select 3 */ + FUNC_SPI1_ARB = 82, /*!< SPI1 Arbitration */ + FUNC_SPI1_SCLK = 83, /*!< SPI1 Serial Clock */ + FUNC_SPI_SLAVE_D0 = 84, /*!< SPI Slave Data 0 */ + FUNC_SPI_SLAVE_SS = 85, /*!< SPI Slave Select */ + FUNC_SPI_SLAVE_SCLK = 86, /*!< SPI Slave Serial Clock */ + FUNC_I2S0_MCLK = 87, /*!< I2S0 Master Clock */ + FUNC_I2S0_SCLK = 88, /*!< I2S0 Serial Clock(BCLK) */ + FUNC_I2S0_WS = 89, /*!< I2S0 Word Select(LRCLK) */ + FUNC_I2S0_IN_D0 = 90, /*!< I2S0 Serial Data Input 0 */ + FUNC_I2S0_IN_D1 = 91, /*!< I2S0 Serial Data Input 1 */ + FUNC_I2S0_IN_D2 = 92, /*!< I2S0 Serial Data Input 2 */ + FUNC_I2S0_IN_D3 = 93, /*!< I2S0 Serial Data Input 3 */ + FUNC_I2S0_OUT_D0 = 94, /*!< I2S0 Serial Data Output 0 */ + FUNC_I2S0_OUT_D1 = 95, /*!< I2S0 Serial Data Output 1 */ + FUNC_I2S0_OUT_D2 = 96, /*!< I2S0 Serial Data Output 2 */ + FUNC_I2S0_OUT_D3 = 97, /*!< I2S0 Serial Data Output 3 */ + FUNC_I2S1_MCLK = 98, /*!< I2S1 Master Clock */ + FUNC_I2S1_SCLK = 99, /*!< I2S1 Serial Clock(BCLK) */ + FUNC_I2S1_WS = 100, /*!< I2S1 Word Select(LRCLK) */ + FUNC_I2S1_IN_D0 = 101, /*!< I2S1 Serial Data Input 0 */ + FUNC_I2S1_IN_D1 = 102, /*!< I2S1 Serial Data Input 1 */ + FUNC_I2S1_IN_D2 = 103, /*!< I2S1 Serial Data Input 2 */ + FUNC_I2S1_IN_D3 = 104, /*!< I2S1 Serial Data Input 3 */ + FUNC_I2S1_OUT_D0 = 105, /*!< I2S1 Serial Data Output 0 */ + FUNC_I2S1_OUT_D1 = 106, /*!< I2S1 Serial Data Output 1 */ + FUNC_I2S1_OUT_D2 = 107, /*!< I2S1 Serial Data Output 2 */ + FUNC_I2S1_OUT_D3 = 108, /*!< I2S1 Serial Data Output 3 */ + FUNC_I2S2_MCLK = 109, /*!< I2S2 Master Clock */ + FUNC_I2S2_SCLK = 110, /*!< I2S2 Serial Clock(BCLK) */ + FUNC_I2S2_WS = 111, /*!< I2S2 Word Select(LRCLK) */ + FUNC_I2S2_IN_D0 = 112, /*!< I2S2 Serial Data Input 0 */ + FUNC_I2S2_IN_D1 = 113, /*!< I2S2 Serial Data Input 1 */ + FUNC_I2S2_IN_D2 = 114, /*!< I2S2 Serial Data Input 2 */ + FUNC_I2S2_IN_D3 = 115, /*!< I2S2 Serial Data Input 3 */ + FUNC_I2S2_OUT_D0 = 116, /*!< I2S2 Serial Data Output 0 */ + FUNC_I2S2_OUT_D1 = 117, /*!< I2S2 Serial Data Output 1 */ + FUNC_I2S2_OUT_D2 = 118, /*!< I2S2 Serial Data Output 2 */ + FUNC_I2S2_OUT_D3 = 119, /*!< I2S2 Serial Data Output 3 */ + FUNC_RESV0 = 120, /*!< Reserved function */ + FUNC_RESV1 = 121, /*!< Reserved function */ + FUNC_RESV2 = 122, /*!< Reserved function */ + FUNC_RESV3 = 123, /*!< Reserved function */ + FUNC_RESV4 = 124, /*!< Reserved function */ + FUNC_RESV5 = 125, /*!< Reserved function */ + FUNC_I2C0_SCLK = 126, /*!< I2C0 Serial Clock */ + FUNC_I2C0_SDA = 127, /*!< I2C0 Serial Data */ + FUNC_I2C1_SCLK = 128, /*!< I2C1 Serial Clock */ + FUNC_I2C1_SDA = 129, /*!< I2C1 Serial Data */ + FUNC_I2C2_SCLK = 130, /*!< I2C2 Serial Clock */ + FUNC_I2C2_SDA = 131, /*!< I2C2 Serial Data */ + FUNC_CMOS_XCLK = 132, /*!< DVP System Clock */ + FUNC_CMOS_RST = 133, /*!< DVP System Reset */ + FUNC_CMOS_PWND = 134, /*!< DVP Power Down Mode */ + FUNC_CMOS_VSYNC = 135, /*!< DVP Vertical Sync */ + FUNC_CMOS_HREF = 136, /*!< DVP Horizontal Reference output */ + FUNC_CMOS_PCLK = 137, /*!< Pixel Clock */ + FUNC_CMOS_D0 = 138, /*!< Data Bit 0 */ + FUNC_CMOS_D1 = 139, /*!< Data Bit 1 */ + FUNC_CMOS_D2 = 140, /*!< Data Bit 2 */ + FUNC_CMOS_D3 = 141, /*!< Data Bit 3 */ + FUNC_CMOS_D4 = 142, /*!< Data Bit 4 */ + FUNC_CMOS_D5 = 143, /*!< Data Bit 5 */ + FUNC_CMOS_D6 = 144, /*!< Data Bit 6 */ + FUNC_CMOS_D7 = 145, /*!< Data Bit 7 */ + FUNC_SCCB_SCLK = 146, /*!< SCCB Serial Clock */ + FUNC_SCCB_SDA = 147, /*!< SCCB Serial Data */ + FUNC_UART1_CTS = 148, /*!< UART1 Clear To Send */ + FUNC_UART1_DSR = 149, /*!< UART1 Data Set Ready */ + FUNC_UART1_DCD = 150, /*!< UART1 Data Carrier Detect */ + FUNC_UART1_RI = 151, /*!< UART1 Ring Indicator */ + FUNC_UART1_SIR_IN = 152, /*!< UART1 Serial Infrared Input */ + FUNC_UART1_DTR = 153, /*!< UART1 Data Terminal Ready */ + FUNC_UART1_RTS = 154, /*!< UART1 Request To Send */ + FUNC_UART1_OUT2 = 155, /*!< UART1 User-designated Output 2 */ + FUNC_UART1_OUT1 = 156, /*!< UART1 User-designated Output 1 */ + FUNC_UART1_SIR_OUT = 157, /*!< UART1 Serial Infrared Output */ + FUNC_UART1_BAUD = 158, /*!< UART1 Transmit Clock Output */ + FUNC_UART1_RE = 159, /*!< UART1 Receiver Output Enable */ + FUNC_UART1_DE = 160, /*!< UART1 Driver Output Enable */ + FUNC_UART1_RS485_EN = 161, /*!< UART1 RS485 Enable */ + FUNC_UART2_CTS = 162, /*!< UART2 Clear To Send */ + FUNC_UART2_DSR = 163, /*!< UART2 Data Set Ready */ + FUNC_UART2_DCD = 164, /*!< UART2 Data Carrier Detect */ + FUNC_UART2_RI = 165, /*!< UART2 Ring Indicator */ + FUNC_UART2_SIR_IN = 166, /*!< UART2 Serial Infrared Input */ + FUNC_UART2_DTR = 167, /*!< UART2 Data Terminal Ready */ + FUNC_UART2_RTS = 168, /*!< UART2 Request To Send */ + FUNC_UART2_OUT2 = 169, /*!< UART2 User-designated Output 2 */ + FUNC_UART2_OUT1 = 170, /*!< UART2 User-designated Output 1 */ + FUNC_UART2_SIR_OUT = 171, /*!< UART2 Serial Infrared Output */ + FUNC_UART2_BAUD = 172, /*!< UART2 Transmit Clock Output */ + FUNC_UART2_RE = 173, /*!< UART2 Receiver Output Enable */ + FUNC_UART2_DE = 174, /*!< UART2 Driver Output Enable */ + FUNC_UART2_RS485_EN = 175, /*!< UART2 RS485 Enable */ + FUNC_UART3_CTS = 176, /*!< UART3 Clear To Send */ + FUNC_UART3_DSR = 177, /*!< UART3 Data Set Ready */ + FUNC_UART3_DCD = 178, /*!< UART3 Data Carrier Detect */ + FUNC_UART3_RI = 179, /*!< UART3 Ring Indicator */ + FUNC_UART3_SIR_IN = 180, /*!< UART3 Serial Infrared Input */ + FUNC_UART3_DTR = 181, /*!< UART3 Data Terminal Ready */ + FUNC_UART3_RTS = 182, /*!< UART3 Request To Send */ + FUNC_UART3_OUT2 = 183, /*!< UART3 User-designated Output 2 */ + FUNC_UART3_OUT1 = 184, /*!< UART3 User-designated Output 1 */ + FUNC_UART3_SIR_OUT = 185, /*!< UART3 Serial Infrared Output */ + FUNC_UART3_BAUD = 186, /*!< UART3 Transmit Clock Output */ + FUNC_UART3_RE = 187, /*!< UART3 Receiver Output Enable */ + FUNC_UART3_DE = 188, /*!< UART3 Driver Output Enable */ + FUNC_UART3_RS485_EN = 189, /*!< UART3 RS485 Enable */ + FUNC_TIMER0_TOGGLE1 = 190, /*!< TIMER0 Toggle Output 1 */ + FUNC_TIMER0_TOGGLE2 = 191, /*!< TIMER0 Toggle Output 2 */ + FUNC_TIMER0_TOGGLE3 = 192, /*!< TIMER0 Toggle Output 3 */ + FUNC_TIMER0_TOGGLE4 = 193, /*!< TIMER0 Toggle Output 4 */ + FUNC_TIMER1_TOGGLE1 = 194, /*!< TIMER1 Toggle Output 1 */ + FUNC_TIMER1_TOGGLE2 = 195, /*!< TIMER1 Toggle Output 2 */ + FUNC_TIMER1_TOGGLE3 = 196, /*!< TIMER1 Toggle Output 3 */ + FUNC_TIMER1_TOGGLE4 = 197, /*!< TIMER1 Toggle Output 4 */ + FUNC_TIMER2_TOGGLE1 = 198, /*!< TIMER2 Toggle Output 1 */ + FUNC_TIMER2_TOGGLE2 = 199, /*!< TIMER2 Toggle Output 2 */ + FUNC_TIMER2_TOGGLE3 = 200, /*!< TIMER2 Toggle Output 3 */ + FUNC_TIMER2_TOGGLE4 = 201, /*!< TIMER2 Toggle Output 4 */ + FUNC_CLK_SPI2 = 202, /*!< Clock SPI2 */ + FUNC_CLK_I2C2 = 203, /*!< Clock I2C2 */ + FUNC_INTERNAL0 = 204, /*!< Internal function signal 0 */ + FUNC_INTERNAL1 = 205, /*!< Internal function signal 1 */ + FUNC_INTERNAL2 = 206, /*!< Internal function signal 2 */ + FUNC_INTERNAL3 = 207, /*!< Internal function signal 3 */ + FUNC_INTERNAL4 = 208, /*!< Internal function signal 4 */ + FUNC_INTERNAL5 = 209, /*!< Internal function signal 5 */ + FUNC_INTERNAL6 = 210, /*!< Internal function signal 6 */ + FUNC_INTERNAL7 = 211, /*!< Internal function signal 7 */ + FUNC_INTERNAL8 = 212, /*!< Internal function signal 8 */ + FUNC_INTERNAL9 = 213, /*!< Internal function signal 9 */ + FUNC_INTERNAL10 = 214, /*!< Internal function signal 10 */ + FUNC_INTERNAL11 = 215, /*!< Internal function signal 11 */ + FUNC_INTERNAL12 = 216, /*!< Internal function signal 12 */ + FUNC_INTERNAL13 = 219, /*!< Internal function signal 13 */ + FUNC_INTERNAL14 = 220, /*!< Internal function signal 14 */ + FUNC_INTERNAL15 = 221, /*!< Internal function signal 15 */ + FUNC_CONSTANT = 222, /*!< Constant function */ + FUNC_INTERNAL16 = 223, /*!< Internal function signal 16 */ + FUNC_DEBUG0 = 224, /*!< Debug function 0 */ + FUNC_DEBUG1 = 225, /*!< Debug function 1 */ + FUNC_DEBUG2 = 226, /*!< Debug function 2 */ + FUNC_DEBUG3 = 227, /*!< Debug function 3 */ + FUNC_DEBUG4 = 228, /*!< Debug function 4 */ + FUNC_DEBUG5 = 229, /*!< Debug function 5 */ + FUNC_DEBUG6 = 230, /*!< Debug function 6 */ + FUNC_DEBUG7 = 231, /*!< Debug function 7 */ + FUNC_DEBUG8 = 232, /*!< Debug function 8 */ + FUNC_DEBUG9 = 233, /*!< Debug function 9 */ + FUNC_DEBUG10 = 234, /*!< Debug function 10 */ + FUNC_DEBUG11 = 235, /*!< Debug function 11 */ + FUNC_DEBUG12 = 236, /*!< Debug function 12 */ + FUNC_DEBUG13 = 237, /*!< Debug function 13 */ + FUNC_DEBUG14 = 238, /*!< Debug function 14 */ + FUNC_DEBUG15 = 239, /*!< Debug function 15 */ + FUNC_DEBUG16 = 240, /*!< Debug function 16 */ + FUNC_DEBUG17 = 241, /*!< Debug function 17 */ + FUNC_DEBUG18 = 242, /*!< Debug function 18 */ + FUNC_DEBUG19 = 243, /*!< Debug function 19 */ + FUNC_DEBUG20 = 244, /*!< Debug function 20 */ + FUNC_DEBUG21 = 245, /*!< Debug function 21 */ + FUNC_DEBUG22 = 246, /*!< Debug function 22 */ + FUNC_DEBUG23 = 247, /*!< Debug function 23 */ + FUNC_DEBUG24 = 248, /*!< Debug function 24 */ + FUNC_DEBUG25 = 249, /*!< Debug function 25 */ + FUNC_DEBUG26 = 250, /*!< Debug function 26 */ + FUNC_DEBUG27 = 251, /*!< Debug function 27 */ + FUNC_DEBUG28 = 252, /*!< Debug function 28 */ + FUNC_DEBUG29 = 253, /*!< Debug function 29 */ + FUNC_DEBUG30 = 254, /*!< Debug function 30 */ + FUNC_DEBUG31 = 255, /*!< Debug function 31 */ + FUNC_MAX = 256, /*!< Function numbers */ +}; +/* clang-format on */ + +/** + * @brief FPIOA pull settings + * + * @note FPIOA pull settings description + * + * | PU | PD | Description | + * |-----|-----|-----------------------------------| + * | 0 | 0 | No Pull | + * | 0 | 1 | Pull Down | + * | 1 | 0 | Pull Up | + * | 1 | 1 | Undefined | + * + */ + +/* clang-format off */ +enum fpioa_pull_e +{ + FPIOA_PULL_NONE, /*!< No Pull */ + FPIOA_PULL_DOWN, /*!< Pull Down */ + FPIOA_PULL_UP, /*!< Pull Up */ + FPIOA_PULL_MAX /*!< Count of pull settings */ +}; +/* clang-format on */ + +/** + * @brief FPIOA driving settings + * + * @note FPIOA driving settings description + * There are 16 kinds of driving settings + * + * @note Low Level Output Current + * + * |DS[3:0] |Min(mA)|Typ(mA)|Max(mA)| + * |--------|-------|-------|-------| + * |0000 |3.2 |5.4 |8.3 | + * |0001 |4.7 |8.0 |12.3 | + * |0010 |6.3 |10.7 |16.4 | + * |0011 |7.8 |13.2 |20.2 | + * |0100 |9.4 |15.9 |24.2 | + * |0101 |10.9 |18.4 |28.1 | + * |0110 |12.4 |20.9 |31.8 | + * |0111 |13.9 |23.4 |35.5 | + * + * @note High Level Output Current + * + * |DS[3:0] |Min(mA)|Typ(mA)|Max(mA)| + * |--------|-------|-------|-------| + * |0000 |5.0 |7.6 |11.2 | + * |0001 |7.5 |11.4 |16.8 | + * |0010 |10.0 |15.2 |22.3 | + * |0011 |12.4 |18.9 |27.8 | + * |0100 |14.9 |22.6 |33.3 | + * |0101 |17.4 |26.3 |38.7 | + * |0110 |19.8 |30.0 |44.1 | + * |0111 |22.3 |33.7 |49.5 | + * + */ + +/* clang-format off */ +enum fpioa_driving_e +{ + FPIOA_DRIVING_0, /*!< 0000 */ + FPIOA_DRIVING_1, /*!< 0001 */ + FPIOA_DRIVING_2, /*!< 0010 */ + FPIOA_DRIVING_3, /*!< 0011 */ + FPIOA_DRIVING_4, /*!< 0100 */ + FPIOA_DRIVING_5, /*!< 0101 */ + FPIOA_DRIVING_6, /*!< 0110 */ + FPIOA_DRIVING_7, /*!< 0111 */ + FPIOA_DRIVING_8, /*!< 1000 */ + FPIOA_DRIVING_9, /*!< 1001 */ + FPIOA_DRIVING_10, /*!< 1010 */ + FPIOA_DRIVING_11, /*!< 1011 */ + FPIOA_DRIVING_12, /*!< 1100 */ + FPIOA_DRIVING_13, /*!< 1101 */ + FPIOA_DRIVING_14, /*!< 1110 */ + FPIOA_DRIVING_15, /*!< 1111 */ + FPIOA_DRIVING_MAX /*!< Count of driving settings */ +}; +/* clang-format on */ + +/** + * @brief FPIOA IO + * + * FPIOA IO is the specific pin of the chip package. Every IO + * has a 32bit width register that can independently implement + * schmitt trigger, invert input, invert output, strong pull + * up, driving selector, static input and static output. And more, + * it can implement any pin of any peripheral devices. + * + * @note FPIOA IO's register bits Layout + * + * | Bits | Name |Description | + * |-----------|----------|---------------------------------------------------| + * | 31 | PAD_DI | Read current IO's data input. | + * | 30:24 | NA | Reserved bits. | + * | 23 | ST | Schmitt trigger. | + * | 22 | DI_INV | Invert Data input. | + * | 21 | IE_INV | Invert the input enable signal. | + * | 20 | IE_EN | Input enable. It can disable or enable IO input. | + * | 19 | SL | Slew rate control enable. | + * | 18 | SPU | Strong pull up. | + * | 17 | PD | Pull select: 0 for pull down, 1 for pull up. | + * | 16 | PU | Pull enable. | + * | 15 | DO_INV | Invert the result of data output select (DO_SEL). | + * | 14 | DO_SEL | Data output select: 0 for DO, 1 for OE. | + * | 13 | OE_INV | Invert the output enable signal. | + * | 12 | OE_EN | Output enable.It can disable or enable IO output. | + * | 11:8 | DS | Driving selector. | + * | 7:0 | CH_SEL | Channel select from 256 input. | + * + */ +struct fpioa_io_config_t +{ + uint32_t ch_sel : 8; + /*!< Channel select from 256 input. */ + uint32_t ds : 4; + /*!< Driving selector. */ + uint32_t oe_en : 1; + /*!< Static output enable, will AND with OE_INV. */ + uint32_t oe_inv : 1; + /*!< Invert output enable. */ + uint32_t do_sel : 1; + /*!< Data output select: 0 for DO, 1 for OE. */ + uint32_t do_inv : 1; + /*!< Invert the result of data output select (DO_SEL). */ + uint32_t pu : 1; + /*!< Pull up enable. 0 for nothing, 1 for pull up. */ + uint32_t pd : 1; + /*!< Pull down enable. 0 for nothing, 1 for pull down. */ + uint32_t resv0 : 1; + /*!< Reserved bits. */ + uint32_t sl : 1; + /*!< Slew rate control enable. */ + uint32_t ie_en : 1; + /*!< Static input enable, will AND with IE_INV. */ + uint32_t ie_inv : 1; + /*!< Invert input enable. */ + uint32_t di_inv : 1; + /*!< Invert Data input. */ + uint32_t st : 1; + /*!< Schmitt trigger. */ + uint32_t resv1 : 7; + /*!< Reserved bits. */ + uint32_t pad_di : 1; + /*!< Read current IO's data input. */ +} __attribute__((packed, aligned(4))); + +/** + * @brief FPIOA tie setting + * + * FPIOA Object have 48 IO pin object and 256 bit input tie bits. + * All SPI arbitration signal will tie high by default. + * + * @note FPIOA function tie bits RAM Layout + * + * | Address | Name |Description | + * |-----------|------------------|----------------------------------| + * | 0x000 | TIE_EN[31:0] | Input tie enable bits [31:0] | + * | 0x004 | TIE_EN[63:32] | Input tie enable bits [63:32] | + * | 0x008 | TIE_EN[95:64] | Input tie enable bits [95:64] | + * | 0x00C | TIE_EN[127:96] | Input tie enable bits [127:96] | + * | 0x010 | TIE_EN[159:128] | Input tie enable bits [159:128] | + * | 0x014 | TIE_EN[191:160] | Input tie enable bits [191:160] | + * | 0x018 | TIE_EN[223:192] | Input tie enable bits [223:192] | + * | 0x01C | TIE_EN[255:224] | Input tie enable bits [255:224] | + * | 0x020 | TIE_VAL[31:0] | Input tie value bits [31:0] | + * | 0x024 | TIE_VAL[63:32] | Input tie value bits [63:32] | + * | 0x028 | TIE_VAL[95:64] | Input tie value bits [95:64] | + * | 0x02C | TIE_VAL[127:96] | Input tie value bits [127:96] | + * | 0x030 | TIE_VAL[159:128] | Input tie value bits [159:128] | + * | 0x034 | TIE_VAL[191:160] | Input tie value bits [191:160] | + * | 0x038 | TIE_VAL[223:192] | Input tie value bits [223:192] | + * | 0x03C | TIE_VAL[255:224] | Input tie value bits [255:224] | + * + * @note Function which input tie high by default + * + * | Name |Description | + * |---------------|---------------------------------------| + * | SPI0_ARB | Arbitration function of SPI master 0 | + * | SPI1_ARB | Arbitration function of SPI master 1 | + * + * Tie high means the SPI Arbitration input is 1 + * + */ +struct fpioa_tie_t +{ + uint32_t en[FUNC_MAX / 32]; + /*!< FPIOA GPIO multiplexer tie enable array */ + uint32_t val[FUNC_MAX / 32]; + /*!< FPIOA GPIO multiplexer tie value array */ +} __attribute__((packed, aligned(4))); + +/** + * @brief FPIOA Object + * + * FPIOA Object have 48 IO pin object and 256 bit input tie bits. + * All SPI arbitration signal will tie high by default. + * + * @note FPIOA IO Pin RAM Layout + * + * | Address | Name |Description | + * |-----------|----------|--------------------------------| + * | 0x000 | PAD0 | FPIOA GPIO multiplexer io 0 | + * | 0x004 | PAD1 | FPIOA GPIO multiplexer io 1 | + * | 0x008 | PAD2 | FPIOA GPIO multiplexer io 2 | + * | 0x00C | PAD3 | FPIOA GPIO multiplexer io 3 | + * | 0x010 | PAD4 | FPIOA GPIO multiplexer io 4 | + * | 0x014 | PAD5 | FPIOA GPIO multiplexer io 5 | + * | 0x018 | PAD6 | FPIOA GPIO multiplexer io 6 | + * | 0x01C | PAD7 | FPIOA GPIO multiplexer io 7 | + * | 0x020 | PAD8 | FPIOA GPIO multiplexer io 8 | + * | 0x024 | PAD9 | FPIOA GPIO multiplexer io 9 | + * | 0x028 | PAD10 | FPIOA GPIO multiplexer io 10 | + * | 0x02C | PAD11 | FPIOA GPIO multiplexer io 11 | + * | 0x030 | PAD12 | FPIOA GPIO multiplexer io 12 | + * | 0x034 | PAD13 | FPIOA GPIO multiplexer io 13 | + * | 0x038 | PAD14 | FPIOA GPIO multiplexer io 14 | + * | 0x03C | PAD15 | FPIOA GPIO multiplexer io 15 | + * | 0x040 | PAD16 | FPIOA GPIO multiplexer io 16 | + * | 0x044 | PAD17 | FPIOA GPIO multiplexer io 17 | + * | 0x048 | PAD18 | FPIOA GPIO multiplexer io 18 | + * | 0x04C | PAD19 | FPIOA GPIO multiplexer io 19 | + * | 0x050 | PAD20 | FPIOA GPIO multiplexer io 20 | + * | 0x054 | PAD21 | FPIOA GPIO multiplexer io 21 | + * | 0x058 | PAD22 | FPIOA GPIO multiplexer io 22 | + * | 0x05C | PAD23 | FPIOA GPIO multiplexer io 23 | + * | 0x060 | PAD24 | FPIOA GPIO multiplexer io 24 | + * | 0x064 | PAD25 | FPIOA GPIO multiplexer io 25 | + * | 0x068 | PAD26 | FPIOA GPIO multiplexer io 26 | + * | 0x06C | PAD27 | FPIOA GPIO multiplexer io 27 | + * | 0x070 | PAD28 | FPIOA GPIO multiplexer io 28 | + * | 0x074 | PAD29 | FPIOA GPIO multiplexer io 29 | + * | 0x078 | PAD30 | FPIOA GPIO multiplexer io 30 | + * | 0x07C | PAD31 | FPIOA GPIO multiplexer io 31 | + * | 0x080 | PAD32 | FPIOA GPIO multiplexer io 32 | + * | 0x084 | PAD33 | FPIOA GPIO multiplexer io 33 | + * | 0x088 | PAD34 | FPIOA GPIO multiplexer io 34 | + * | 0x08C | PAD35 | FPIOA GPIO multiplexer io 35 | + * | 0x090 | PAD36 | FPIOA GPIO multiplexer io 36 | + * | 0x094 | PAD37 | FPIOA GPIO multiplexer io 37 | + * | 0x098 | PAD38 | FPIOA GPIO multiplexer io 38 | + * | 0x09C | PAD39 | FPIOA GPIO multiplexer io 39 | + * | 0x0A0 | PAD40 | FPIOA GPIO multiplexer io 40 | + * | 0x0A4 | PAD41 | FPIOA GPIO multiplexer io 41 | + * | 0x0A8 | PAD42 | FPIOA GPIO multiplexer io 42 | + * | 0x0AC | PAD43 | FPIOA GPIO multiplexer io 43 | + * | 0x0B0 | PAD44 | FPIOA GPIO multiplexer io 44 | + * | 0x0B4 | PAD45 | FPIOA GPIO multiplexer io 45 | + * | 0x0B8 | PAD46 | FPIOA GPIO multiplexer io 46 | + * | 0x0BC | PAD47 | FPIOA GPIO multiplexer io 47 | + * + */ +struct fpioa_t +{ + struct fpioa_io_config_t io[FPIOA_NUM_IO]; + /*!< FPIOA GPIO multiplexer io array */ + struct fpioa_tie_t tie; + /*!< FPIOA GPIO multiplexer tie */ +} __attribute__((packed, aligned(4))); + +/** + * @brief FPIOA object instanse + */ +extern volatile struct fpioa_t *const fpioa; + +/** + * @brief Initialize FPIOA user custom default settings + * + * @note This function will set all FPIOA pad registers to user-defined + * values from kconfig + * + * @return result + * - 0 Success + * - Other Fail + */ +int fpioa_init(void); + +/** + * @brief Get IO configuration + * + * @param[in] number The IO number + * @param cfg Pointer to struct of IO configuration for specified IO + * + * @return result + * - 0 Success + * - Other Fail + */ +int fpioa_get_io(int number, struct fpioa_io_config_t *cfg); + +/** + * @brief Set IO configuration + * + * @param[in] number The IO number + * @param[in] cfg Pointer to struct of IO configuration for specified IO + * + * @return result + * - 0 Success + * - Other Fail + */ +int fpioa_set_io(int number, struct fpioa_io_config_t *cfg); + +/** + * @brief Set IO configuration with function number + * + * @note The default IO configuration which bind to function number will + * set automatically + * + * @param[in] number The IO number + * @param[in] function The function enum number + * + * @return result + * - 0 Success + * - Other Fail + */ +int fpioa_set_function_raw(int number, enum fpioa_function_e function); + +/** + * @brief Set only IO configuration with function number + * + * @note The default IO configuration which bind to function number will + * set automatically + * + * @param[in] number The IO number + * @param[in] function The function enum number + * + * @return result + * - 0 Success + * - Other Fail + */ +int fpioa_set_function(int number, enum fpioa_function_e function); + +/** + * @brief Set tie enable to function + * + * @param[in] function The function enum number + * @param[in] enable Tie enable to set, 1 is enable, 0 is disable + * + * @return result + * - 0 Success + * - Other Fail + */ +int fpioa_set_tie_enable(enum fpioa_function_e function, int enable); + +/** + * @brief Set tie value to function + * + * @param[in] function The function enum number + * @param[in] value Tie value to set, 1 is HIGH, 0 is LOW + * + * @return result + * - 0 Success + * - Other Fail + */ +int fpioa_set_tie_value(enum fpioa_function_e function, int value); + +/** + * @brief Set IO pull function + * + * @param[in] number The IO number + * @param[in] pull The pull enum number + * + * @return result + * - 0 Success + * - Other Fail + */ +int fpioa_set_io_pull(int number, enum fpioa_pull_e pull); + +/** + * @brief Get IO pull function + * + * @param[in] number The IO number + * + * @return result + * - -1 Fail + * - Other The pull enum number + */ +int fpioa_get_io_pull(int number); + +/** + * @brief Set IO driving + * + * @param[in] number The IO number + * @param[in] driving The driving enum number + * + * @return result + * - 0 Success + * - Other Fail + */ +int fpioa_set_io_driving(int number, enum fpioa_driving_e driving); + +/** + * @brief Get IO driving + * + * @param[in] number The IO number + * + * @return result + * - -1 Fail + * - Other The driving enum number + */ +int fpioa_get_io_driving(int number); + +/** + * @brief Get IO by function + * + * @param[in] function The function enum number + * + * @return result + * - -1 Fail + * - Other The IO number + */ +int fpioa_get_io_by_func(enum fpioa_function_e function); + + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_FPIOA_H */ + diff --git a/lib/drivers/include/gpio.h b/lib/drivers/include/gpio.h new file mode 100644 index 0000000..a2adabc --- /dev/null +++ b/lib/drivers/include/gpio.h @@ -0,0 +1,176 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _DRIVER_GPIO_H +#define _DRIVER_GPIO_H + +#include "platform.h" +#include +#include +#include "gpio_common.h" +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Structure for accessing GPIO registers by individual bit + */ +typedef struct +{ + uint32_t b0 : 1; + uint32_t b1 : 1; + uint32_t b2 : 1; + uint32_t b3 : 1; + uint32_t b4 : 1; + uint32_t b5 : 1; + uint32_t b6 : 1; + uint32_t b7 : 1; + uint32_t b8 : 1; + uint32_t b9 : 1; + uint32_t b10 : 1; + uint32_t b11 : 1; + uint32_t b12 : 1; + uint32_t b13 : 1; + uint32_t b14 : 1; + uint32_t b15 : 1; + uint32_t b16 : 1; + uint32_t b17 : 1; + uint32_t b18 : 1; + uint32_t b19 : 1; + uint32_t b20 : 1; + uint32_t b21 : 1; + uint32_t b22 : 1; + uint32_t b23 : 1; + uint32_t b24 : 1; + uint32_t b25 : 1; + uint32_t b26 : 1; + uint32_t b27 : 1; + uint32_t b28 : 1; + uint32_t b29 : 1; + uint32_t b30 : 1; + uint32_t b31 : 1; +} __attribute__((packed, aligned(4))) gpio_bits_t; + +/** + * @brief Structure of templates for accessing GPIO registers + */ +typedef union +{ + /* 32x1 bit mode */ + uint32_t u32[1]; + /* 16x2 bit mode */ + uint16_t u16[2]; + /* 8x4 bit mode */ + uint8_t u8[4]; + /* 1 bit mode */ + gpio_bits_t bits; +} __attribute__((packed, aligned(4))) gpio_access_tp_t; + +/** + * @brief The GPIO address map + */ +typedef struct +{ + /* Offset 0x00: Data (output) registers */ + gpio_access_tp_t data_output; + /* Offset 0x04: Data direction registers */ + gpio_access_tp_t direction; + /* Offset 0x08: Data source registers */ + gpio_access_tp_t source; + /* Offset 0x10 - 0x2f: Unused registers, 9x4 bytes */ + uint32_t unused_0[9]; + /* Offset 0x30: Interrupt enable/disable registers */ + gpio_access_tp_t interrupt_enable; + /* Offset 0x34: Interrupt mask registers */ + gpio_access_tp_t interrupt_mask; + /* Offset 0x38: Interrupt level registers */ + gpio_access_tp_t interrupt_level; + /* Offset 0x3c: Interrupt polarity registers */ + gpio_access_tp_t interrupt_polarity; + /* Offset 0x40: Interrupt status registers */ + gpio_access_tp_t interrupt_status; + /* Offset 0x44: Raw interrupt status registers */ + gpio_access_tp_t interrupt_status_raw; + /* Offset 0x48: Interrupt debounce registers */ + gpio_access_tp_t interrupt_debounce; + /* Offset 0x4c: Registers for clearing interrupts */ + gpio_access_tp_t interrupt_clear; + /* Offset 0x50: External port (data input) registers */ + gpio_access_tp_t data_input; + /* Offset 0x54 - 0x5f: Unused registers, 3x4 bytes */ + uint32_t unused_1[3]; + /* Offset 0x60: Sync level registers */ + gpio_access_tp_t sync_level; + /* Offset 0x64: ID code */ + gpio_access_tp_t id_code; + /* Offset 0x68: Interrupt both edge type */ + gpio_access_tp_t interrupt_bothedge; + +} __attribute__((packed, aligned(4))) gpio_t; + +/** + * @brief Bus GPIO object instance + */ +extern volatile gpio_t *const gpio; + +/** + * @brief Gpio initialize + * + * @return Result + * - 0 Success + * - Other Fail + */ +int gpio_init(void); + +/** + * @brief Gpio pin initialize, map Pin number to Gpio function pin + * + * @param[in] pin_num Pin number + * @param[in] gpio_pin Gpio pin + */ +void gpio_pin_init(size_t pin_num, size_t gpio_pin); + +/** + * @brief Set Gpio drive mode + * + * @param[in] pin Gpio pin + * @param[in] mode Gpio pin drive mode + */ +void gpio_set_drive_mode(size_t pin, gpio_drive_mode mode); + +/** + * @brief Get Gpio pin value + * + * @param[in] pin Gpio pin + * @return Pin value + * + * - GPIO_PV_Low Gpio pin low + * - GPIO_PV_High Gpio pin high + */ +gpio_pin_value gpio_get_pin_value(size_t pin); + +/** + * @brief Set Gpio pin value + * + * @param[in] pin Gpio pin + * @param[in] value Gpio pin value + */ +void gpio_set_pin_value(size_t pin, gpio_pin_value value); + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_GPIO_H */ + diff --git a/lib/drivers/include/gpio_common.h b/lib/drivers/include/gpio_common.h new file mode 100644 index 0000000..4a01f08 --- /dev/null +++ b/lib/drivers/include/gpio_common.h @@ -0,0 +1,53 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _GPIO_COMMON_H +#define _GPIO_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum +{ + GPIO_DM_Input, + GPIO_DM_InputPullDown, + GPIO_DM_InputPullUp, + GPIO_DM_Output, + GPIO_DM_OutputOpenDrain, + GPIO_DM_OutputOpenDrainPullUp, + GPIO_DM_OutputOpenSource, + GPIO_DM_OutputOpenSourcePullDown +} gpio_drive_mode; + +typedef enum +{ + GPIO_PE_None, + GPIO_PE_Falling, + GPIO_PE_Rising, + GPIO_PE_Both +} gpio_pin_edge; + +typedef enum +{ + GPIO_PV_Low, + GPIO_PV_High +} gpio_pin_value; + +#ifdef __cplusplus +} +#endif + +#endif /* _GPIO_COMMON_H */ + diff --git a/lib/drivers/include/gpiohs.h b/lib/drivers/include/gpiohs.h new file mode 100644 index 0000000..d8df951 --- /dev/null +++ b/lib/drivers/include/gpiohs.h @@ -0,0 +1,267 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _DRIVER_GPIOHS_H +#define _DRIVER_GPIOHS_H + +#include +#include "platform.h" +#include +#include "gpio_common.h" +#include "plic.h" +#ifdef __cplusplus +extern "C" { +#endif + +/* clang-format off */ +/* Register address offsets */ +#define GPIOHS_INPUT_VAL (0x00) +#define GPIOHS_INPUT_EN (0x04) +#define GPIOHS_OUTPUT_EN (0x08) +#define GPIOHS_OUTPUT_VAL (0x0C) +#define GPIOHS_PULLUP_EN (0x10) +#define GPIOHS_DRIVE (0x14) +#define GPIOHS_RISE_IE (0x18) +#define GPIOHS_RISE_IP (0x1C) +#define GPIOHS_FALL_IE (0x20) +#define GPIOHS_FALL_IP (0x24) +#define GPIOHS_HIGH_IE (0x28) +#define GPIOHS_HIGH_IP (0x2C) +#define GPIOHS_LOW_IE (0x30) +#define GPIOHS_LOW_IP (0x34) +#define GPIOHS_IOF_EN (0x38) +#define GPIOHS_IOF_SEL (0x3C) +#define GPIOHS_OUTPUT_XOR (0x40) +/* clang-format on */ + +/** + * @brief GPIO bits raw object + */ +struct gpiohs_raw_t +{ + /* Address offset 0x00 */ + uint32_t input_val; + /* Address offset 0x04 */ + uint32_t input_en; + /* Address offset 0x08 */ + uint32_t output_en; + /* Address offset 0x0c */ + uint32_t output_val; + /* Address offset 0x10 */ + uint32_t pullup_en; + /* Address offset 0x14 */ + uint32_t drive; + /* Address offset 0x18 */ + uint32_t rise_ie; + /* Address offset 0x1c */ + uint32_t rise_ip; + /* Address offset 0x20 */ + uint32_t fall_ie; + /* Address offset 0x24 */ + uint32_t fall_ip; + /* Address offset 0x28 */ + uint32_t high_ie; + /* Address offset 0x2c */ + uint32_t high_ip; + /* Address offset 0x30 */ + uint32_t low_ie; + /* Address offset 0x34 */ + uint32_t low_ip; + /* Address offset 0x38 */ + uint32_t iof_en; + /* Address offset 0x3c */ + uint32_t iof_sel; + /* Address offset 0x40 */ + uint32_t output_xor; +} __attribute__((packed, aligned(4))); + +/** + * @brief GPIO bits object + */ +typedef struct +{ + uint32_t b0 : 1; + uint32_t b1 : 1; + uint32_t b2 : 1; + uint32_t b3 : 1; + uint32_t b4 : 1; + uint32_t b5 : 1; + uint32_t b6 : 1; + uint32_t b7 : 1; + uint32_t b8 : 1; + uint32_t b9 : 1; + uint32_t b10 : 1; + uint32_t b11 : 1; + uint32_t b12 : 1; + uint32_t b13 : 1; + uint32_t b14 : 1; + uint32_t b15 : 1; + uint32_t b16 : 1; + uint32_t b17 : 1; + uint32_t b18 : 1; + uint32_t b19 : 1; + uint32_t b20 : 1; + uint32_t b21 : 1; + uint32_t b22 : 1; + uint32_t b23 : 1; + uint32_t b24 : 1; + uint32_t b25 : 1; + uint32_t b26 : 1; + uint32_t b27 : 1; + uint32_t b28 : 1; + uint32_t b29 : 1; + uint32_t b30 : 1; + uint32_t b31 : 1; +} __attribute__((packed, aligned(4))) gpiohs_bits_t; + +/** + * @brief GPIO bits multi access union + */ +typedef union +{ + /* 32x1 bit mode */ + uint32_t u32[1]; + /* 16x2 bit mode */ + uint16_t u16[2]; + /* 8x4 bit mode */ + uint8_t u8[4]; + /* 1 bit mode */ + gpiohs_bits_t bits; +} __attribute__((packed, aligned(4))) gpiohs_u32_t; + +/** + * @brief GPIO object + * + * The GPIO controller is a peripheral device mapped in the + * internal memory map, discoverable in the Configuration String. + * It is responsible for low-level configuration of the actual + * GPIO pads on the device (direction, pull up-enable, and drive + * value), as well as selecting between various sources of the + * controls for these signals. The GPIO controller allows seperate + * configuration of each of N GPIO bits. + * + * Once the interrupt is pending, it will remain set until a 1 is + * written to the *_ip register at that bit. + */ + +typedef struct +{ + /* Address offset 0x00, Input Values */ + gpiohs_u32_t input_val; + /* Address offset 0x04, Input enable */ + gpiohs_u32_t input_en; + /* Address offset 0x08, Output enable */ + gpiohs_u32_t output_en; + /* Address offset 0x0c, Onput Values */ + gpiohs_u32_t output_val; + /* Address offset 0x10, Internal Pull-Ups enable */ + gpiohs_u32_t pullup_en; + /* Address offset 0x14, Drive Strength */ + gpiohs_u32_t drive; + /* Address offset 0x18, Rise interrupt enable */ + gpiohs_u32_t rise_ie; + /* Address offset 0x1c, Rise interrupt pending */ + gpiohs_u32_t rise_ip; + /* Address offset 0x20, Fall interrupt enable */ + gpiohs_u32_t fall_ie; + /* Address offset 0x24, Fall interrupt pending */ + gpiohs_u32_t fall_ip; + /* Address offset 0x28, High interrupt enable */ + gpiohs_u32_t high_ie; + /* Address offset 0x2c, High interrupt pending */ + gpiohs_u32_t high_ip; + /* Address offset 0x30, Low interrupt enable */ + gpiohs_u32_t low_ie; + /* Address offset 0x34, Low interrupt pending */ + gpiohs_u32_t low_ip; + /* Address offset 0x38, HW I/O Function enable */ + gpiohs_u32_t iof_en; + /* Address offset 0x3c, HW I/O Function select */ + gpiohs_u32_t iof_sel; + /* Address offset 0x40, Output XOR (invert) */ + gpiohs_u32_t output_xor; +} __attribute__((packed, aligned(4))) gpiohs_t; + +/** + * @brief GPIO High-speed object instanse + */ +extern volatile gpiohs_t *const gpiohs; + +/** + * @brief Gpiohs initialize + * + * @return Result + * - 0 Success + * - Other Fail + */ +int gpiohs_init(void); + +/** + * @brief Gpiohs pin initialize, map Pin number to Gpio function pin + * + * @param[in] pin_num Pin number + * @param[in] gpio_pin Gpiohs pin + */ +void gpiohs_pin_init(size_t pin_num, size_t gpio_pin); + +/** + * @brief Set Gpiohs drive mode + * + * @param[in] pin Gpiohs pin + * @param[in] mode Gpiohs pin drive mode + */ +void gpiohs_set_drive_mode(size_t pin, gpio_drive_mode mode); + +/** + * @brief Get Gpiohs pin value + * + * @param[in] pin Gpiohs pin + * @return Pin value + * + * - GPIO_PV_Low Gpiohs pin low + * - GPIO_PV_High Gpiohs pin high + */ +gpio_pin_value gpiohs_get_pin_value(size_t pin); + +/** + * @brief Set Gpiohs pin value + * + * @param[in] pin Gpiohs pin + * @param[in] value Gpiohs pin value + */ +void gpiohs_set_pin_value(size_t pin, gpio_pin_value value); + +/** + * @brief Set Gpiohs pin edge for interrupt + * + * @param[in] pin Gpiohs pin + * @param[in] edge Gpiohs pin edge type + */ +void gpiohs_set_pin_edge(size_t pin, gpio_pin_edge edge); + +/** + * @brief Set Gpiohs pin interrupt + * + * @param[in] pin Gpiohs pin + * @param[in] priority Gpiohs pin interrupt priority + * @param[in] func Gpiohs pin interrupt service routine + */ +void gpiohs_set_irq(size_t pin, uint32_t priority, void(*func)()); + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_GPIOHS_H */ + diff --git a/lib/drivers/include/hard_fft.h b/lib/drivers/include/hard_fft.h new file mode 100644 index 0000000..d5468ec --- /dev/null +++ b/lib/drivers/include/hard_fft.h @@ -0,0 +1,271 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _DRIVER_HARD_FFT_H +#define _DRIVER_HARD_FFT_H + +#include +#include "platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct complex +{ + float real; + float imag; +} complex; + +typedef struct +{ + int16_t I1; + int16_t R1; + int16_t I2; + int16_t R2; +} fft_data; + +typedef enum fft_point_e +{ + FFT_N512, + FFT_N256, + FFT_N128, + FFT_N64, +} fft_point_t; + +typedef enum fft_mode_e +{ + IFFT_MODE, + FFT_MODE, +} fft_mode_t; + + +/** + * @brief FFT algorithm accelerator register + * + * @note FFT algorithm accelerator register table + * + * | Offset | Name | Description | + * |-----------|----------------|-------------------------------------| + * | 0x00 | fft_input_fifo | input data fifo | + * | 0x08 | fft_ctrl | fft ctrl reg | + * | 0x10 | fifo_ctrl | fifo ctrl | + * | 0x18 | intr_mask | interrupt mask | + * | 0x20 | intr_clear | interrupt clear | + * | 0x28 | fft_status | fft status reg | + * | 0x30 | fft_status_raw | fft_status_raw | + * | 0x38 | fft_output_fifo| fft_output_fifo | + * + */ + + +/** + * @brief input data fifo + * + * No. 0 Register (0x00) + */ +typedef struct +{ + uint64_t fft_input_fifo : 64; +} __attribute__((packed, aligned(8))) fft_fft_input_fifo_t; + +/** + * @brief fft ctrl reg + * + * No. 1 Register (0x08) + */ +typedef struct +{ + uint64_t fft_point : 3; + uint64_t fft_mode : 1; + uint64_t fft_shift : 9; + uint64_t fft_enable : 1; + uint64_t dma_send : 1; + uint64_t fft_input_mode : 2; + uint64_t fft_data_mode : 1; + uint64_t reserved : 46; +} __attribute__((packed, aligned(8))) fft_fft_ctrl_t; + +/** + * @brief fifo ctrl + * + * No. 2 Register (0x10) + */ +typedef struct +{ + uint64_t resp_fifo_flush_n : 1; + uint64_t cmd_fifo_flush_n : 1; + uint64_t gs_fifo_flush_n : 1; + uint64_t reserved : 61; +} __attribute__((packed, aligned(8))) fft_fifo_ctrl_t; + +/** + * @brief interrupt mask + * + * No. 3 Register (0x18) + */ +typedef struct +{ + uint64_t fft_done_mask : 1; + uint64_t reserved : 63; +} __attribute__((packed, aligned(8))) fft_intr_mask_t; + +/** + * @brief interrupt clear + * + * No. 4 Register (0x20) + */ +typedef struct +{ + uint64_t fft_done_clear : 1; + uint64_t reserved1 : 63; +} __attribute__((packed, aligned(8))) fft_intr_clear_t; + +/** + * @brief fft status reg + * + * No. 5 Register (0x28) + */ +typedef struct +{ + uint64_t fft_done_status : 1; + uint64_t reserved1 : 63; +} __attribute__((packed, aligned(8))) fft_fft_status_t; + +/** + * @brief fft_status_raw + * + * No. 6 Register (0x30) + */ +typedef struct +{ + uint64_t fft_done_status_raw : 1; + uint64_t reserved : 63; +} __attribute__((packed, aligned(8))) fft_fft_status_raw_t; + +/** + * @brief fft_output_fifo + * + * No. 7 Register (0x38) + */ +typedef struct +{ + uint64_t fft_output_fifo : 64; +} __attribute__((packed, aligned(8))) fft_fft_output_fifo_t; + +/** + * @brief Fast Fourier transform (FFT) algorithm accelerator object + * + * A fast Fourier transform (FFT) algorithm computes the discrete + * Fourier transform (DFT) of a sequence, or its inverse (IFFT). + * Fourier analysis converts a signal from its original domain + * (often time or space) to a representation in the frequency + * domain and vice versa. An FFT rapidly computes such + * transformations by factorizing the DFT matrix into a product of + * sparse (mostly zero) factors. + */ +typedef struct +{ + /* No. 0 (0x00): input data fifo */ + fft_fft_input_fifo_t fft_input_fifo; + /* No. 1 (0x08): fft ctrl reg */ + fft_fft_ctrl_t fft_ctrl; + /* No. 2 (0x10): fifo ctrl */ + fft_fifo_ctrl_t fifo_ctrl; + /* No. 3 (0x18): interrupt mask */ + fft_intr_mask_t intr_mask; + /* No. 4 (0x20): interrupt clear */ + fft_intr_clear_t intr_clear; + /* No. 5 (0x28): fft status reg */ + fft_fft_status_t fft_status; + /* No. 6 (0x30): fft_status_raw */ + fft_fft_status_raw_t fft_status_raw; + /* No. 7 (0x38): fft_output_fifo */ + fft_fft_output_fifo_t fft_output_fifo; +} __attribute__((packed, aligned(8))) fft_t; + +/** + * @brief Fft initialize + * + * @param[in] point fft point, 0:512, 1:256, 2:128, 3:64 + * @param[in] mode fft or ifft, 1: fft, 0: ifft + * @param[in] shift fft shift + * @param[in] is_dma dma send flag + * @param[in] input_mode fft input mode + * @param[in] data_mode fft data mode + * + * @return Result + * 0 Success + * Other Fail + */ +int fft_init(uint8_t point, uint8_t mode, uint16_t shift, uint8_t is_dma, uint8_t input_mode, uint8_t data_mode); + +/** + * @brief Fft reset + * + */ +void fft_reset(void); + +/** + * @brief Enable fft done interrupt + * + */ +void fft_enable_int(void); + +/** + * @brief Fft input data(complex numbers) + * + * @param[in] x complex numbers real part + * @param[in] y complex numbers imaginary part + * @param[in] point fft point + */ +void fft_input_data(float *x, float *y, uint8_t point); + +/** + * @brief Fft input data(integer) + * + * @param[in] data integer + * @param[in] point fft point + */ +void fft_input_intdata(int16_t *data, uint8_t point); + +/** + * @brief Get fft finish flag + * + * @return Result + * 1 Fft finish + * Other Not complete + */ +uint8_t fft_get_finish_flag(void); + +/** + * @brief Get fft result + * + * @param[out] x complex numbers real part + * @param[out] y complex numbers imaginary part + * @param[in] point fft point + */ +void fft_get_result(float *x, float *y, uint8_t point); + +/** + * @brief Fast Fourier transform (FFT) algorithm accelerator object + */ +extern volatile fft_t *const fft; + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_FFT_H */ + diff --git a/lib/drivers/include/i2c.h b/lib/drivers/include/i2c.h new file mode 100644 index 0000000..188ed05 --- /dev/null +++ b/lib/drivers/include/i2c.h @@ -0,0 +1,434 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _DRIVER_I2C_H +#define _DRIVER_I2C_H + +#include +#include +#include "dmac.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define I2C_MAX_NUM 3 + +/* clang-format off */ +struct i2c_t +{ + /* I2C Control Register (0x00) */ + volatile uint32_t con; + /* I2C Target Address Register (0x04) */ + volatile uint32_t tar; + /* I2C Slave Address Register (0x08) */ + volatile uint32_t sar; + /* reserved (0x0c) */ + volatile uint32_t resv1; + /* I2C Data Buffer and Command Register (0x10) */ + volatile uint32_t data_cmd; + /* I2C Standard Speed Clock SCL High Count Register (0x14) */ + volatile uint32_t ss_scl_hcnt; + /* I2C Standard Speed Clock SCL Low Count Register (0x18) */ + volatile uint32_t ss_scl_lcnt; + /* reserverd (0x1c-0x28) */ + volatile uint32_t resv2[4]; + /* I2C Interrupt Status Register (0x2c) */ + volatile uint32_t intr_stat; + /* I2C Interrupt Mask Register (0x30) */ + volatile uint32_t intr_mask; + /* I2C Raw Interrupt Status Register (0x34) */ + volatile uint32_t raw_intr_stat; + /* I2C Receive FIFO Threshold Register (0x38) */ + volatile uint32_t rx_tl; + /* I2C Transmit FIFO Threshold Register (0x3c) */ + volatile uint32_t tx_tl; + /* I2C Clear Combined and Individual Interrupt Register (0x40) */ + volatile uint32_t clr_intr; + /* I2C Clear RX_UNDER Interrupt Register (0x44) */ + volatile uint32_t clr_rx_under; + /* I2C Clear RX_OVER Interrupt Register (0x48) */ + volatile uint32_t clr_rx_over; + /* I2C Clear TX_OVER Interrupt Register (0x4c) */ + volatile uint32_t clr_tx_over; + /* I2C Clear RD_REQ Interrupt Register (0x50) */ + volatile uint32_t clr_rd_req; + /* I2C Clear TX_ABRT Interrupt Register (0x54) */ + volatile uint32_t clr_tx_abrt; + /* I2C Clear RX_DONE Interrupt Register (0x58) */ + volatile uint32_t clr_rx_done; + /* I2C Clear ACTIVITY Interrupt Register (0x5c) */ + volatile uint32_t clr_activity; + /* I2C Clear STOP_DET Interrupt Register (0x60) */ + volatile uint32_t clr_stop_det; + /* I2C Clear START_DET Interrupt Register (0x64) */ + volatile uint32_t clr_start_det; + /* I2C Clear GEN_CALL Interrupt Register (0x68) */ + volatile uint32_t clr_gen_call; + /* I2C Enable Register (0x6c) */ + volatile uint32_t enable; + /* I2C Status Register (0x70) */ + volatile uint32_t status; + /* I2C Transmit FIFO Level Register (0x74) */ + volatile uint32_t txflr; + /* I2C Receive FIFO Level Register (0x78) */ + volatile uint32_t rxflr; + /* I2C SDA Hold Time Length Register (0x7c) */ + volatile uint32_t sda_hold; + /* I2C Transmit Abort Source Register (0x80) */ + volatile uint32_t tx_abrt_source; + /* reserved (0x84) */ + volatile uint32_t resv3; + /* I2C DMA Control Register (0x88) */ + volatile uint32_t dma_cr; + /* I2C DMA Transmit Data Level Register (0x8c) */ + volatile uint32_t dma_tdlr; + /* I2C DMA Receive Data Level Register (0x90) */ + volatile uint32_t dma_rdlr; + /* I2C SDA Setup Register (0x94) */ + volatile uint32_t sda_setup; + /* I2C ACK General Call Register (0x98) */ + volatile uint32_t general_call; + /* I2C Enable Status Register (0x9c) */ + volatile uint32_t enable_status; + /* I2C SS, FS or FM+ spike suppression limit (0xa0) */ + volatile uint32_t fs_spklen; + /* reserved (0xa4-0xf0) */ + volatile uint32_t resv4[20]; + /* I2C Component Parameter Register 1 (0xf4) */ + volatile uint32_t comp_param_1; + /* I2C Component Version Register (0xf8) */ + volatile uint32_t comp_version; + /* I2C Component Type Register (0xfc) */ + volatile uint32_t comp_type; +} __attribute__((packed, aligned(4))); + +/* I2C Control Register*/ +#define I2C_CON_MASTER_MODE 0x00000001U +#define I2C_CON_SPEED_MASK 0x00000006U +#define I2C_CON_SPEED(x) ((x) << 1) +#define I2C_CON_10BITADDR_SLAVE 0x00000008U +#define I2C_CON_RESTART_EN 0x00000020U +#define I2C_CON_SLAVE_DISABLE 0x00000040U +#define I2C_CON_STOP_DET_IFADDRESSED 0x00000080U +#define I2C_CON_TX_EMPTY_CTRL 0x00000100U + +/* I2C Target Address Register*/ +#define I2C_TAR_ADDRESS_MASK 0x000003FFU +#define I2C_TAR_ADDRESS(x) ((x) << 0) +#define I2C_TAR_GC_OR_START 0x00000400U +#define I2C_TAR_SPECIAL 0x00000800U +#define I2C_TAR_10BITADDR_MASTER 0x00001000U + +/* I2C Slave Address Register*/ +#define I2C_SAR_ADDRESS_MASK 0x000003FFU +#define I2C_SAR_ADDRESS(x) ((x) << 0) + +/* I2C Rx/Tx Data Buffer and Command Register*/ +#define I2C_DATA_CMD_CMD 0x00000100U +#define I2C_DATA_CMD_DATA_MASK 0x000000FFU +#define I2C_DATA_CMD_DATA(x) ((x) << 0) + +/* Standard Speed I2C Clock SCL High Count Register*/ +#define I2C_SS_SCL_HCNT_COUNT_MASK 0x0000FFFFU +#define I2C_SS_SCL_HCNT_COUNT(x) ((x) << 0) + +/* Standard Speed I2C Clock SCL Low Count Register*/ +#define I2C_SS_SCL_LCNT_COUNT_MASK 0x0000FFFFU +#define I2C_SS_SCL_LCNT_COUNT(x) ((x) << 0) + +/* I2C Interrupt Status Register*/ +#define I2C_INTR_STAT_RX_UNDER 0x00000001U +#define I2C_INTR_STAT_RX_OVER 0x00000002U +#define I2C_INTR_STAT_RX_FULL 0x00000004U +#define I2C_INTR_STAT_TX_OVER 0x00000008U +#define I2C_INTR_STAT_TX_EMPTY 0x00000010U +#define I2C_INTR_STAT_RD_REQ 0x00000020U +#define I2C_INTR_STAT_TX_ABRT 0x00000040U +#define I2C_INTR_STAT_RX_DONE 0x00000080U +#define I2C_INTR_STAT_ACTIVITY 0x00000100U +#define I2C_INTR_STAT_STOP_DET 0x00000200U +#define I2C_INTR_STAT_START_DET 0x00000400U +#define I2C_INTR_STAT_GEN_CALL 0x00000800U + +/* I2C Interrupt Mask Register*/ +#define I2C_INTR_MASK_RX_UNDER 0x00000001U +#define I2C_INTR_MASK_RX_OVER 0x00000002U +#define I2C_INTR_MASK_RX_FULL 0x00000004U +#define I2C_INTR_MASK_TX_OVER 0x00000008U +#define I2C_INTR_MASK_TX_EMPTY 0x00000010U +#define I2C_INTR_MASK_RD_REQ 0x00000020U +#define I2C_INTR_MASK_TX_ABRT 0x00000040U +#define I2C_INTR_MASK_RX_DONE 0x00000080U +#define I2C_INTR_MASK_ACTIVITY 0x00000100U +#define I2C_INTR_MASK_STOP_DET 0x00000200U +#define I2C_INTR_MASK_START_DET 0x00000400U +#define I2C_INTR_MASK_GEN_CALL 0x00000800U + +/* I2C Raw Interrupt Status Register*/ +#define I2C_RAW_INTR_MASK_RX_UNDER 0x00000001U +#define I2C_RAW_INTR_MASK_RX_OVER 0x00000002U +#define I2C_RAW_INTR_MASK_RX_FULL 0x00000004U +#define I2C_RAW_INTR_MASK_TX_OVER 0x00000008U +#define I2C_RAW_INTR_MASK_TX_EMPTY 0x00000010U +#define I2C_RAW_INTR_MASK_RD_REQ 0x00000020U +#define I2C_RAW_INTR_MASK_TX_ABRT 0x00000040U +#define I2C_RAW_INTR_MASK_RX_DONE 0x00000080U +#define I2C_RAW_INTR_MASK_ACTIVITY 0x00000100U +#define I2C_RAW_INTR_MASK_STOP_DET 0x00000200U +#define I2C_RAW_INTR_MASK_START_DET 0x00000400U +#define I2C_RAW_INTR_MASK_GEN_CALL 0x00000800U + +/* I2C Receive FIFO Threshold Register*/ +#define I2C_RX_TL_VALUE_MASK 0x00000007U +#define I2C_RX_TL_VALUE(x) ((x) << 0) + +/* I2C Transmit FIFO Threshold Register*/ +#define I2C_TX_TL_VALUE_MASK 0x00000007U +#define I2C_TX_TL_VALUE(x) ((x) << 0) + +/* Clear Combined and Individual Interrupt Register*/ +#define I2C_CLR_INTR_CLR 0x00000001U + +/* Clear RX_UNDER Interrupt Register*/ +#define I2C_CLR_RX_UNDER_CLR 0x00000001U + +/* Clear RX_OVER Interrupt Register*/ +#define I2C_CLR_RX_OVER_CLR 0x00000001U + +/* Clear TX_OVER Interrupt Register*/ +#define I2C_CLR_TX_OVER_CLR 0x00000001U + +/* Clear RD_REQ Interrupt Register*/ +#define I2C_CLR_RD_REQ_CLR 0x00000001U + +/* Clear TX_ABRT Interrupt Register*/ +#define I2C_CLR_TX_ABRT_CLR 0x00000001U + +/* Clear RX_DONE Interrupt Register*/ +#define I2C_CLR_RX_DONE_CLR 0x00000001U + +/* Clear ACTIVITY Interrupt Register*/ +#define I2C_CLR_ACTIVITY_CLR 0x00000001U + +/* Clear STOP_DET Interrupt Register*/ +#define I2C_CLR_STOP_DET_CLR 0x00000001U + +/* Clear START_DET Interrupt Register*/ +#define I2C_CLR_START_DET_CLR 0x00000001U + +/* Clear GEN_CALL Interrupt Register*/ +#define I2C_CLR_GEN_CALL_CLR 0x00000001U + +/* I2C Enable Register*/ +#define I2C_ENABLE_ENABLE 0x00000001U +#define I2C_ENABLE_ABORT 0x00000002U +#define I2C_ENABLE_TX_CMD_BLOCK 0x00000004U + +/* I2C Status Register*/ +#define I2C_STATUS_ACTIVITY 0x00000001U +#define I2C_STATUS_TFNF 0x00000002U +#define I2C_STATUS_TFE 0x00000004U +#define I2C_STATUS_RFNE 0x00000008U +#define I2C_STATUS_RFF 0x00000010U +#define I2C_STATUS_MST_ACTIVITY 0x00000020U +#define I2C_STATUS_SLV_ACTIVITY 0x00000040U + +/* I2C Transmit FIFO Level Register*/ +#define I2C_TXFLR_VALUE_MASK 0x00000007U +#define I2C_TXFLR_VALUE(x) ((x) << 0) + +/* I2C Receive FIFO Level Register*/ +#define I2C_RXFLR_VALUE_MASK 0x00000007U +#define I2C_RXFLR_VALUE(x) ((x) << 0) + +/* I2C SDA Hold Time Length Register*/ +#define I2C_SDA_HOLD_TX_MASK 0x0000FFFFU +#define I2C_SDA_HOLD_TX(x) ((x) << 0) +#define I2C_SDA_HOLD_RX_MASK 0x00FF0000U +#define I2C_SDA_HOLD_RX(x) ((x) << 16) + +/* I2C Transmit Abort Source Register*/ +#define I2C_TX_ABRT_SOURCE_7B_ADDR_NOACK 0x00000001U +#define I2C_TX_ABRT_SOURCE_10B_ADDR1_NOACK 0x00000002U +#define I2C_TX_ABRT_SOURCE_10B_ADDR2_NOACK 0x00000004U +#define I2C_TX_ABRT_SOURCE_TXDATA_NOACK 0x00000008U +#define I2C_TX_ABRT_SOURCE_GCALL_NOACK 0x00000010U +#define I2C_TX_ABRT_SOURCE_GCALL_READ 0x00000020U +#define I2C_TX_ABRT_SOURCE_HS_ACKDET 0x00000040U +#define I2C_TX_ABRT_SOURCE_SBYTE_ACKDET 0x00000080U +#define I2C_TX_ABRT_SOURCE_HS_NORSTRT 0x00000100U +#define I2C_TX_ABRT_SOURCE_SBYTE_NORSTRT 0x00000200U +#define I2C_TX_ABRT_SOURCE_10B_RD_NORSTRT 0x00000400U +#define I2C_TX_ABRT_SOURCE_MASTER_DIS 0x00000800U +#define I2C_TX_ABRT_SOURCE_MST_ARBLOST 0x00001000U +#define I2C_TX_ABRT_SOURCE_SLVFLUSH_TXFIFO 0x00002000U +#define I2C_TX_ABRT_SOURCE_SLV_ARBLOST 0x00004000U +#define I2C_TX_ABRT_SOURCE_SLVRD_INTX 0x00008000U +#define I2C_TX_ABRT_SOURCE_USER_ABRT 0x00010000U + +/* DMA Control Register*/ +#define I2C_DMA_CR_RDMAE 0x00000001U +#define I2C_DMA_CR_TDMAE 0x00000002U + +/* DMA Transmit Data Level Register*/ +#define I2C_DMA_TDLR_VALUE_MASK 0x00000007U +#define I2C_DMA_TDLR_VALUE(x) ((x) << 0) + +/* DMA Receive Data Level Register*/ +#define I2C_DMA_RDLR_VALUE_MASK 0x00000007U +#define I2C_DMA_RDLR_VALUE(x) ((x) << 0) + +/* I2C SDA Setup Register*/ +#define I2C_SDA_SETUP_VALUE_MASK 0x000000FFU +#define I2C_SDA_SETUP_VALUE(x) ((x) << 0) + +/* I2C ACK General Call Register*/ +#define I2C_ACK_GENERAL_CALL_ENABLE 0x00000001U + +/* I2C Enable Status Register*/ +#define I2C_ENABLE_STATUS_IC_ENABLE 0x00000001U +#define I2C_ENABLE_STATUS_SLV_DIS_BUSY 0x00000002U +#define I2C_ENABLE_STATUS_SLV_RX_DATA_LOST 0x00000004U + +/* I2C SS, FS or FM+ spike suppression limit*/ +#define I2C_FS_SPKLEN_VALUE_MASK 0x000000FFU +#define I2C_FS_SPKLEN_VALUE(x) ((x) << 0) + +/* Component Parameter Register 1*/ +#define I2C_COMP_PARAM1_APB_DATA_WIDTH 0x00000003U +#define I2C_COMP_PARAM1_MAX_SPEED_MODE 0x0000000CU +#define I2C_COMP_PARAM1_HC_COUNT_VALUES 0x00000010U +#define I2C_COMP_PARAM1_INTR_IO 0x00000020U +#define I2C_COMP_PARAM1_HAS_DMA 0x00000040U +#define I2C_COMP_PARAM1_ENCODED_PARAMS 0x00000080U +#define I2C_COMP_PARAM1_RX_BUFFER_DEPTH 0x0000FF00U +#define I2C_COMP_PARAM1_TX_BUFFER_DEPTH 0x00FF0000U + +/* I2C Component Version Register*/ +#define I2C_COMP_VERSION_VALUE 0xFFFFFFFFU + +/* I2C Component Type Register*/ +#define I2C_COMP_TYPE_VALUE 0xFFFFFFFFU +/* clang-format on */ + +extern volatile struct i2c_t *const i2c[3]; + +typedef enum +{ + I2C_BS_STANDARD, + I2C_BS_FAST, + I2C_BS_HIGHSPEED +} i2c_bus_speed_mode; + +/** + * @brief I2c init + * + * @param[in] sel i2c bus + * @param[in] clk_pin i2c clk pin + * @param[in] data_pin i2c data pin + */ +void i2c_init(uint8_t sel, int clk_pin, int data_pin); + +/** + * @brief I2c pin init + * + * @param[in] sel i2c bus + * @param[in] clk_pin i2c clk pin + * @param[in] data_pin i2c data pin + */ +void i2c_pin_init(uint8_t sel, int clk_pin, int data_pin); + +/** + * @brief I2c clk init + * + * @param[in] sel i2c bus + */ +void i2c_clk_init(uint8_t sel); + +/** + * @brief I2c set param + * + * @param[in] sel i2c bus + * @param[in] slaveAddress i2c slave address + * @param[in] address_width address width 7bit or 10bit + * @param[in] bus_speed_mode i2c rate + */ +void i2c_config(uint8_t sel, size_t slaveAddress, size_t address_width, + i2c_bus_speed_mode bus_speed_mode); + +/** + * @brief I2c send data + * + * @param[in] sel i2c bus + * @param[in] reg i2c slave reg address + * @param[in] data_buf send data + * @param[in] length send length + * + * @return result + * - 0 Success + * - Other Fail + */ +int i2c_write_reg(uint8_t sel, uint8_t reg, uint8_t *data_buf, uint8_t length); + + /** + * @brief I2c receive data + * + * @param[in] sel i2c bus + * @param[in] reg i2c slave reg address + * @param[in] data_buf receive data + * @param[in] length receive length + * + * @return result + * - 0 Success + * - Other Fail + */ +int i2c_read_reg(uint8_t sel, uint8_t reg, uint8_t *data_buf, uint8_t length); + +/** + * @brief I2c send data by dma + * + * @param[in] channel_num dma channel + * @param[in] sel i2c bus + * @param[in] reg i2c slave reg address + * @param[in] data_buf send data + * @param[in] length send length + * + * @return result + * - 0 Success + * - Other Fail + */ +int i2c_write_reg_dma(dmac_channel_number channel_num, uint8_t sel, uint8_t reg, uint8_t *data_buf, uint8_t length); + +/** + * @brief I2c receive data + * + * @param[in] channel_num dma channel + * @param[in] sel i2c bus + * @param[in] reg i2c slave reg address + * @param[in] data_buf receive data + * @param[in] length receive length + * + * @return result + * - 0 Success + * - Other Fail +*/ +int i2c_read_reg_dma(dmac_channel_number w_channel_num, dmac_channel_number r_channel_num, + uint8_t sel, uint8_t reg, uint8_t *data_buf, uint8_t length); + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_I2C_H */ diff --git a/lib/drivers/include/i2s.h b/lib/drivers/include/i2s.h new file mode 100644 index 0000000..35f39c3 --- /dev/null +++ b/lib/drivers/include/i2s.h @@ -0,0 +1,1009 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _DRIVER_I2S_H +#define _DRIVER_I2S_H + +#include +#include "platform.h" +#include "io.h" +#include "dmac.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#define I2S0_IN_D0 90 +#define I2S0_SCLK 88 +#define I2S0_WS 89 + +enum i2s_device_num_t +{ + I2S_DEVICE_0 = 0, + I2S_DEVICE_1 = 1, + I2S_DEVICE_2 = 2, + I2S_DEVICE_MAX +}; + +enum i2s_channel_num_t +{ + CHANNEL_0 = 0, + CHANNEL_1 = 1, + CHANNEL_2 = 2, + CHANNEL_3 = 3 +}; + +enum i2s_transmit_t +{ + TRANSMITTER = 0, + RECEIVER = 1 +}; + +enum i2s_work_mode_t +{ + STANDARD_MODE = 1, + RIGHT_JUSTIFYING_MODE = 2, + LEFT_JUSTIFYING_MODE = 4 +}; + +enum sclk_gating_cycles_t +{ + /* Clock gating is diable */ + NO_CLOCK_GATING = 0x0, + /* Gating after 12 sclk cycles */ + CLOCK_CYCLES_12 = 0x1, + /* Gating after 16 sclk cycles */ + CLOCK_CYCLES_16 = 0x2, + /* Gating after 20 sclk cycles */ + CLOCK_CYCLES_20 = 0x3, + /* Gating after 24 sclk cycles */ + CLOCK_CYCLES_24 = 0x4 +}; + +enum word_select_cycles_t +{ + /* 16 sclk cycles */ + SCLK_CYCLES_16 = 0x0, + /* 24 sclk cycles */ + SCLK_CYCLES_24 = 0x1, + /* 32 sclk cycles */ + SCLK_CYCLES_32 = 0x2 + +}; + +enum word_length_t +{ + /* Ignore the word length */ + IGNORE_WORD_LENGTH = 0x0, + /* 12-bit data resolution of the receiver */ + RESOLUTION_12_BIT = 0x1, + /* 16-bit data resolution of the receiver */ + RESOLUTION_16_BIT = 0x2, + /* 20-bit data resolution of the receiver */ + RESOLUTION_20_BIT = 0x3, + /* 24-bit data resolution of the receiver */ + RESOLUTION_24_BIT = 0x4, + /* 32-bit data resolution of the receiver */ + RESOLUTION_32_BIT = 0x5 +}; + +enum fifo_threshold_t +{ + /* Interrupt trigger when FIFO level is 1 */ + TRIGGER_LEVEL_1 = 0x0, + /* Interrupt trigger when FIFO level is 2 */ + TRIGGER_LEVEL_2 = 0x1, + /* Interrupt trigger when FIFO level is 3 */ + TRIGGER_LEVEL_3 = 0x2, + /* Interrupt trigger when FIFO level is 4 */ + TRIGGER_LEVEL_4 = 0x3, + /* Interrupt trigger when FIFO level is 5 */ + TRIGGER_LEVEL_5 = 0x4, + /* Interrupt trigger when FIFO level is 6 */ + TRIGGER_LEVEL_6 = 0x5, + /* Interrupt trigger when FIFO level is 7 */ + TRIGGER_LEVEL_7 = 0x6, + /* Interrupt trigger when FIFO level is 8 */ + TRIGGER_LEVEL_8 = 0x7, + /* Interrupt trigger when FIFO level is 9 */ + TRIGGER_LEVEL_9 = 0x8, + /* Interrupt trigger when FIFO level is 10 */ + TRIGGER_LEVEL_10 = 0x9, + /* Interrupt trigger when FIFO level is 11 */ + TRIGGER_LEVEL_11 = 0xa, + /* Interrupt trigger when FIFO level is 12 */ + TRIGGER_LEVEL_12 = 0xb, + /* Interrupt trigger when FIFO level is 13 */ + TRIGGER_LEVEL_13 = 0xc, + /* Interrupt trigger when FIFO level is 14 */ + TRIGGER_LEVEL_14 = 0xd, + /* Interrupt trigger when FIFO level is 15 */ + TRIGGER_LEVEL_15 = 0xe, + /* Interrupt trigger when FIFO level is 16 */ + TRIGGER_LEVEL_16 = 0xf +}; + + +struct i2s_ier_t +{ + /* Bit 0 is ien, 0 for disable i2s and 1 for enable i2s */ + uint32_t ien : 1; + /* Bits [31:1] is reserved */ + uint32_t resv : 31; +} __attribute__((packed, aligned(4))); + +union ier_u +{ + struct i2s_ier_t ier; + uint32_t reg_data; +}; + +struct i2s_irer_t +{ + /* Bit 0 is receiver block enable, + * 0 for receiver disable + * 1 for receiver enable + */ + uint32_t rxen : 1; + /* Bits [31:1] is reserved */ + uint32_t resv : 31; +} __attribute__((packed, aligned(4))); + +union irer_u +{ + struct i2s_irer_t irer; + uint32_t reg_data; +}; + +struct i2s_iter_t +{ + uint32_t txen : 1; + /* Bit 0 is transmitter block enable, + * 0 for transmitter disable + * 1 for transmitter enable + */ + uint32_t resv : 31; + /* Bits [31:1] is reserved */ +} __attribute__((packed, aligned(4))); + +union iter_u +{ + struct i2s_iter_t iter; + uint32_t reg_data; +}; + +struct i2s_cer_t +{ + uint32_t clken : 1; + /* Bit 0 is clock generation enable/disable, + * 0 for clock generation disable, + * 1 for clock generation enable + */ + uint32_t resv : 31; + /* Bits [31:1] is reserved */ +} __attribute__((packed, aligned(4))); + +union cer_u +{ + struct i2s_cer_t cer; + uint32_t reg_data; +}; + +struct i2s_ccr_t +{ + /* Bits [2:0] is used to program the gating of sclk, + * 0x0 for clock gating is diable, + * 0x1 for gating after 12 sclk cycles + * 0x2 for gating after 16 sclk cycles + * 0x3 for gating after 20 sclk cycles + * 0x4 for gating after 24 sclk cycles + */ + uint32_t clk_gate : 3; + /* Bits [4:3] used program the number of sclk cycles for which the + * word select line stayd in the left aligned or right aligned mode. + * 0x0 for 16sclk cycles, 0x1 for 24 sclk cycles 0x2 for 32 sclk + * cycles + */ + uint32_t clk_word_size : 2; + /* Bit[5:7] is alignment mode setting. + * 0x1 for standard i2s format + * 0x2 for right aligned format + * 0x4 for left aligned format + */ + uint32_t align_mode : 3; + /* Bit[8] is DMA transmit enable control */ + uint32_t dma_tx_en : 1; + /* Bit[9] is DMA receive enable control */ + uint32_t dma_rx_en : 1; + uint32_t dma_divide_16 : 1; + /* Bit[10] split 32bit data to two 16 bit data and filled in left + * and right channel. Used with dma_tx_en or dma_rx_en + */ + uint32_t sign_expand_en : 1; + uint32_t resv : 20; + /* Bits [31:11] is reseved */ +} __attribute__((packed, aligned(4))); + +union ccr_u +{ + struct i2s_ccr_t ccr; + uint32_t reg_data; +}; + +struct i2s_rxffr_t +{ + uint32_t rxffr : 1; + /* Bit 0 is receiver FIFO reset, + * 0 for does not flush RX FIFO, 1 for flush RX FIFO + */ + uint32_t resv : 31; + /* Bits [31:1] is reserved */ +} __attribute__((packed, aligned(4))); + +union rxffr_u +{ + struct i2s_rxffr_t rxffr; + uint32_t reg_data; +}; + +struct i2s_lrbrthr +{ + uint32_t fifo : 16; + /* Bits [15:0] if used data receive or transmit */ + uint32_t resv : 16; +}; + +union lrbthr_u +{ + struct i2s_lrbrthr buffer; + uint32_t reg_data; +}; + +struct i2s_rthr_t +{ + /* Bits [15:0] is right stereo data transmitted serially + * from transmit channel input + */ + uint32_t rthrx : 16; + /* Bits [31:16] is reserved */ + uint32_t resv : 16; +} __attribute__((packed, aligned(4))); + +union rthr_u +{ + struct i2s_rthr_t rthr; + uint32_t reg_data; +}; + +struct i2s_rer_t +{ + /* Bit 0 is receive channel enable/disable, 0 for receive channel disable, + *1 for receive channel enable + */ + uint32_t rxchenx : 1; + /* Bits [31:1] is reseved */ + uint32_t resv : 31; +} __attribute__((packed, aligned(4))); + +union rer_u +{ + struct i2s_rer_t rer; + uint32_t reg_data; +}; + +struct i2s_ter_t +{ + /* Bit 0 is transmit channel enable/disable, 0 for transmit channel disable, + * 1 for transmit channel enable + */ + uint32_t txchenx : 1; + /* Bits [31:1] is reseved */ + uint32_t resv : 31; +} __attribute__((packed, aligned(4))); + +union ter_u +{ + struct i2s_ter_t ter; + uint32_t reg_data; +}; + +struct i2s_rcr_tcr_t +{ + /* Bits [2:0] is used to program desired data resolution of + * receiver/transmitter, + * 0x0 for ignore the word length + * 0x1 for 12-bit data resolution of the receiver/transmitter, + * 0x2 for 16-bit data resolution of the receiver/transmitter, + * 0x3 for 20-bit data resolution of the receiver/transmitter, + * 0x4 for 24-bit data resolution of the receiver/transmitter, + * 0x5 for 32-bit data resolution of the receiver/transmitter + */ + uint32_t wlen : 3; + /* Bits [31:3] is reseved */ + uint32_t resv : 29; +} __attribute__((packed, aligned(4))); + +union rcr_tcr_u { + struct i2s_rcr_tcr_t rcr_tcr; + uint32_t reg_data; +}; + +struct i2s_isr_t { + /* Bit 0 is status of receiver data avaliable interrupt + * 0x0 for RX FIFO trigger level not reached + * 0x1 for RX FIFO trigger level is reached + */ + uint32_t rxda : 1; + /* Bit 1 is status of data overrun interrupt for rx channel + * 0x0 for RX FIFO write valid + * 0x1 for RX FIFO write overrun + */ + uint32_t rxfo : 1; + /* Bits [3:2] is reserved */ + uint32_t resv1 : 2; + /* Bit 4 is status of transmit empty triger interrupt + * 0x0 for TX FIFO triiger level is reach + * 0x1 for TX FIFO trigger level is not reached + */ + uint32_t txfe : 1; + /* BIt 5 is status of data overrun interrupt for the TX channel + * 0x0 for TX FIFO write valid + * 0x1 for TX FIFO write overrun + */ + uint32_t txfo : 1; + /* BIts [31:6] is reserved */ + uint32_t resv2 : 26; +} __attribute__((packed, aligned(4))); + +union isr_u { + struct i2s_isr_t isr; + uint32_t reg_data; +}; + +struct i2s_imr_t +{ + /* Bit 0 is mask RX FIFO data available interrupt + * 0x0 for unmask RX FIFO data available interrupt + * 0x1 for mask RX FIFO data available interrupt + */ + uint32_t rxdam : 1; + /* Bit 1 is mask RX FIFO overrun interrupt + * 0x0 for unmask RX FIFO overrun interrupt + * 0x1 for mask RX FIFO overrun interrupt + */ + uint32_t rxfom : 1; + /* Bits [3:2] is reserved */ + uint32_t resv1 : 2; + /* Bit 4 is mask TX FIFO empty interrupt, + * 0x0 for unmask TX FIFO empty interrupt, + * 0x1 for mask TX FIFO empty interrupt + */ + uint32_t txfem : 1; + /* BIt 5 is mask TX FIFO overrun interrupt + * 0x0 for mask TX FIFO overrun interrupt + * 0x1 for unmash TX FIFO overrun interrupt + */ + uint32_t txfom : 1; + /* Bits [31:6] is reserved */ + uint32_t resv2 : 26; +} __attribute__((packed, aligned(4))); + +union imr_u +{ + struct i2s_imr_t imr; + uint32_t reg_data; +}; + +struct i2s_ror_t +{ + /* Bit 0 is read this bit to clear RX FIFO data overrun interrupt + * 0x0 for RX FIFO write valid, + *0x1 for RX FIFO write overrun + */ + uint32_t rxcho : 1; + /* Bits [31:1] is reserved */ + uint32_t resv : 31; +} __attribute__((packed, aligned(4))); + +union ror_u +{ + struct i2s_ror_t ror; + uint32_t reg_data; +}; + +struct i2s_tor_t +{ + /* Bit 0 is read this bit to clear TX FIFO data overrun interrupt + * 0x0 for TX FIFO write valid, + *0x1 for TX FIFO write overrun + */ + uint32_t txcho : 1; + /* Bits [31:1] is reserved */ + uint32_t resv : 31; +} __attribute__((packed, aligned(4))); + +union tor_u +{ + struct i2s_tor_t tor; + uint32_t reg_data; +}; + +struct i2s_rfcr_t +{ + /* Bits [3:0] is used program the trigger level in the RX FIFO at + * which the receiver data available interrupt generate, + * 0x0 for interrupt trigger when FIFO level is 1, + * 0x2 for interrupt trigger when FIFO level is 2, + * 0x3 for interrupt trigger when FIFO level is 4, + * 0x4 for interrupt trigger when FIFO level is 5, + * 0x5 for interrupt trigger when FIFO level is 6, + * 0x6 for interrupt trigger when FIFO level is 7, + * 0x7 for interrupt trigger when FIFO level is 8, + * 0x8 for interrupt trigger when FIFO level is 9, + * 0x9 for interrupt trigger when FIFO level is 10, + * 0xa for interrupt trigger when FIFO level is 11, + * 0xb for interrupt trigger when FIFO level is 12, + * 0xc for interrupt trigger when FIFO level is 13, + * 0xd for interrupt trigger when FIFO level is 14, + * 0xe for interrupt trigger when FIFO level is 15, + * 0xf for interrupt trigger when FIFO level is 16 + */ + uint32_t rxchdt : 4; + /* Bits [31:4] is reserved */ + uint32_t rsvd_rfcrx : 28; +} __attribute__((packed, aligned(4))); + +union rfcr_u +{ + struct i2s_rfcr_t rfcr; + uint32_t reg_data; +}; + +struct i2s_tfcr_t +{ + /* Bits [3:0] is used program the trigger level in the TX FIFO at + * which the receiver data available interrupt generate, + * 0x0 for interrupt trigger when FIFO level is 1, + * 0x2 for interrupt trigger when FIFO level is 2, + * 0x3 for interrupt trigger when FIFO level is 4, + * 0x4 for interrupt trigger when FIFO level is 5, + * 0x5 for interrupt trigger when FIFO level is 6, + * 0x6 for interrupt trigger when FIFO level is 7, + * 0x7 for interrupt trigger when FIFO level is 8, + * 0x8 for interrupt trigger when FIFO level is 9, + * 0x9 for interrupt trigger when FIFO level is 10, + * 0xa for interrupt trigger when FIFO level is 11, + * 0xb for interrupt trigger when FIFO level is 12, + * 0xc for interrupt trigger when FIFO level is 13, + * 0xd for interrupt trigger when FIFO level is 14, + * 0xe for interrupt trigger when FIFO level is 15, + * 0xf for interrupt trigger when FIFO level is 16 + */ + uint32_t txchet : 4; + /* Bits [31:4] is reserved */ + uint32_t rsvd_tfcrx : 28; +} __attribute__((packed, aligned(4))); + +union tfcr_u +{ + struct i2s_tfcr_t tfcr; + uint32_t reg_data; +}; + +struct i2s_rff_t +{ + /* Bit 0 is receiver channel FIFO reset, + * 0x0 for does not flush an individual RX FIFO, + * 0x1 for flush an indiviadual RX FIFO + */ + uint32_t rxchfr : 1; + /*< Bits [31:1] is reserved ,write only */ + uint32_t rsvd_rffx : 31; +} __attribute__((packed, aligned(4))); + +union rff_u +{ + struct i2s_rff_t rff; + uint32_t reg_data; +}; + +struct i2s_tff_t +{ + /* Bit 0 is transmit channel FIFO reset, + * 0x0 for does not flush an individual TX FIFO, + * 0x1 for flush an indiviadual TX FIFO + */ + uint32_t rtxchfr : 1; + /*< Bits [31:1] is reserved ,write only */ + uint32_t rsvd_rffx : 31; +} __attribute__((packed, aligned(4))); + +union tff_u +{ + struct i2s_tff_t tff; + uint32_t reg_data; +}; + +struct i2s_channel_t +{ + /* Left Receive or Left Transmit Register (0x20) */ + volatile uint32_t left_rxtx; + /* Right Receive or Right Transmit Register (0x24) */ + volatile uint32_t right_rxtx; + /* Receive Enable Register (0x28) */ + volatile uint32_t rer; + /* Transmit Enable Register (0x2c) */ + volatile uint32_t ter; + /* Receive Configuration Register (0x30) */ + volatile uint32_t rcr; + /* Transmit Configuration Register (0x34) */ + volatile uint32_t tcr; + /* Interrupt Status Register (0x38) */ + volatile uint32_t isr; + /* Interrupt Mask Register (0x3c) */ + volatile uint32_t imr; + /* Receive Overrun Register (0x40) */ + volatile uint32_t ror; + /* Transmit Overrun Register (0x44) */ + volatile uint32_t tor; + /* Receive FIFO Configuration Register (0x48) */ + volatile uint32_t rfcr; + /* Transmit FIFO Configuration Register (0x4c) */ + volatile uint32_t tfcr; + /* Receive FIFO Flush Register (0x50) */ + volatile uint32_t rff; + /* Transmit FIFO Flush Register (0x54) */ + volatile uint32_t tff; + /* reserved (0x58-0x5c) */ + volatile uint32_t reserved1[2]; +} __attribute__((packed, aligned(4))); + +/****is* i2s.api/dw_i2s_portmap + * NAME + * i2s_t + * DESCRIPTION + * This is the structure used for accessing the i2s register + * portmap. + * EXAMPLE + * struct i2s_t *portmap; + * portmap = (struct dw_i2s_portmap *) DW_APB_I2S_BASE; + * SOURCE + */ +struct i2s_t +{ + /* I2S Enable Register (0x00) */ + volatile uint32_t ier; + /* I2S Receiver Block Enable Register (0x04) */ + volatile uint32_t irer; + /* I2S Transmitter Block Enable Register (0x08) */ + volatile uint32_t iter; + /* Clock Enable Register (0x0c) */ + volatile uint32_t cer; + /* Clock Configuration Register (0x10) */ + volatile uint32_t ccr; + /* Receiver Block FIFO Reset Register (0x04) */ + volatile uint32_t rxffr; + /* Transmitter Block FIFO Reset Register (0x18) */ + volatile uint32_t txffr; + /* reserved (0x1c) */ + volatile uint32_t reserved1; + volatile struct i2s_channel_t channel[4]; + /* reserved (0x118-0x1bc) */ + volatile uint32_t reserved2[40]; + /* Receiver Block DMA Register (0x1c0) */ + volatile uint32_t rxdma; + /* Reset Receiver Block DMA Register (0x1c4) */ + volatile uint32_t rrxdma; + /* Transmitter Block DMA Register (0x1c8) */ + volatile uint32_t txdma; + /* Reset Transmitter Block DMA Register (0x1cc) */ + volatile uint32_t rtxdma; + /* reserved (0x1d0-0x1ec) */ + volatile uint32_t reserved3[8]; + /* Component Parameter Register 2 (0x1f0) */ + volatile uint32_t i2s_comp_param_2; + /* Component Parameter Register 1 (0x1f4) */ + volatile uint32_t i2s_comp_param_1; + /* I2S Component Version Register (0x1f8) */ + volatile uint32_t i2s_comp_version_1; + /* I2S Component Type Register (0x1fc) */ + volatile uint32_t i2s_comp_type; +} __attribute__((packed, aligned(4))); + +/** + * @brief I2S object instance + */ +extern volatile struct i2s_t *const i2s[3]; + +/** + * @brief i2s device + * + * @param[in] device_num the device of i2s + * + */ +void i2s_device_enable(enum i2s_device_num_t device_num); + +/** + * @brief Enable or disable i2s device + * + * @param[in] device_num The device of i2s + * @param[in] enable Enable flag 0:disable, 1:enable + */ +void i2s_dev_enable(enum i2s_device_num_t device_num, uint32_t enable); + +/** + * @brief Set I2S recive channel enable or disable + * + * @param[in] device_num which of device + * @param[in] channel_num The channel number + * @param[in] enable The enable or disable + * + * @return result + * - 0 Success + * - Other Fail + */ +int i2s_receive_channel_enable(enum i2s_device_num_t device_num, + enum i2s_channel_num_t channel_num, uint32_t enable); + +/** + * @brief Set I2S transmit channel enable or disable + * + * @param[in] device_num which of device + * @param[in] channel_num The channel number + * @param[in] enable The enable or disable + * + * @return result + * - 0 Success + * - Other Fail + */ +int i2s_transmit_channel_enable(enum i2s_device_num_t device_num, + enum i2s_channel_num_t channel_num, uint32_t enable); + +/** + * @brief Read pcm data from channel_num channel + * + * @param[in] device_num which of device + * @param[in] channel_num The channel number + * @param[in] buf save read data + * @param[in] length the length to read form i2s + * + * @return result + * - 0 Success + * - Other Fail + */ +int32_t i2s_receive_data(enum i2s_device_num_t device_num, + enum i2s_channel_num_t channel_num, uint64_t *buf, + uint32_t length); + +/** + * @brief Read pcm data from dma + * + * @param[in] device_num which of device + * @param[in] buf save read data + * @param[in] length the length to read form i2s + * @param[in] channel_num The dma channel number + * + * @return result + * - 0 Success + * - Other Fail + */ +int32_t i2s_receive_data_dma(enum i2s_device_num_t device_num, uint32_t *buf, + uint32_t length, dmac_channel_number channel_num); + +/** + * @brief Read pcm data from dma + * + * @param[in] device_num which of device + * @param[in] buf save read data + * @param[in] length the length to read form i2s + * @param[in] channel_num The dma channel number + * + * @return result + * - 0 Success + * - Other Fail + */ +int32_t i2s_recv_dma(enum i2s_device_num_t device_num, uint32_t *buf, + uint32_t length, dmac_channel_number channel_num); + +/** + * @brief Mask or unmask interrupt + * + * @param[in] channel_num The channel number + * @param[in] rx_available The receive available interrupt + * @param[in] rx_overrun_int The receive overrun interrupt + * @param[in] tx_empty_int The transmit empty interrupt + * @param[in] tx_overrun_int The transmit overrun interrupt + * @param[in] device_num which of device + * + * @return result + * - 0 Success + * - Other Fail + */ +int i2s_set_mask_interrupt(enum i2s_device_num_t device_num, + enum i2s_channel_num_t channel_num, + uint32_t rx_available, uint32_t rx_overrun_int, + uint32_t tx_empty_int, uint32_t tx_overrun_int); +/** + * @brief Set transmit threshold + * + * @param[in] threshold The threshold data + * @param[in] channel_num The channel number + * @param[in] device_num which of device + * + * @return result + * - 0 Success + * - Other Fail + */ +int i2s_set_tx_threshold(enum i2s_device_num_t device_num, + enum fifo_threshold_t threshold, + enum i2s_channel_num_t channel_num); + +/** + * @brief Set receive threshold + * + * @param[in] threshold The threshold data + * @param[in] channel_num The channel number + * @param[in] device_num which of device + * + * @return result + * - 0 Success + * - Other Fail + */ +int i2s_set_rx_threshold(enum i2s_device_num_t device_num, + enum fifo_threshold_t threshold, + enum i2s_channel_num_t channel_num); + +/** + * @brief Configure I2s master mode word select size and clock gating param + * + * @param[in] device_num which of device + * @param[in] word_select_size clock cycle + * @param[in] gating_cycles The sclk gating cycles + + * @param[in] word_mode work mode standard,left justify, + * + * @return result + * - 0 Success + * - Other Fail + */ +int i2s_master_configure(enum i2s_device_num_t device_num, + enum word_select_cycles_t word_select_size, + enum sclk_gating_cycles_t gating_cycles, + enum i2s_work_mode_t word_mode); +/** + * @brief Set rx fifo word length + * + * @param[in] device_num which of device + * @param[in] word_length word length + * @param[in] channel_num The channel number + * + * @return result + * - 0 Success + * - Other Fail + */ +int i2s_set_rx_word_length(enum i2s_device_num_t device_num, + enum word_length_t word_length, + enum i2s_channel_num_t channel_num); + +/** + * @brief set tx fifo word length + * + * @param[in] device_num which of device + * @param[in] word_length word length + * @param[in] channel_num The channel number + * + * @return result + * - 0 Success + * - Other Fail + */ +int i2s_set_tx_word_length(enum i2s_device_num_t device_num, + enum word_length_t word_length, + enum i2s_channel_num_t channel_num); + +/** + * @brief i2s fpioa set and clock configure + * + * @return result + * - 0 Success + * - Other Fail + */ +int i2s_fpioa_sysctl(void); + +/** + * @brief i2s receive enable + * + * @param[in] device_num The device number + * @param[in] channel_num The channel number + */ +void i2s_receive_enable(enum i2s_device_num_t device_num, + enum i2s_channel_num_t channel_num); + +/** + * @brief i2s transimit enable + * + * @param[in] device_num The device number + * @param[in] channel_num The channel number + */ +void i2s_transimit_enable(enum i2s_device_num_t device_num, + enum i2s_channel_num_t channel_num); + +/** + * @brief I2S receive channel configure + * + * @param[in] device_num The device number + * @param[in] channel_num The channel number + * @param[in] word_length The word length + * @param[in] word_select_size The word select size + * @param[in] trigger_level The trigger level + */ +void i2s_rx_channel_configure(enum i2s_device_num_t device_num, + enum i2s_channel_num_t channel_num, + enum word_length_t word_length, + enum word_select_cycles_t word_select_size, + enum fifo_threshold_t trigger_level, + enum i2s_work_mode_t word_mode); + +/** + * @brief I2S transmit channel enable + * + * @param[in] device_num The device number + * @param[in] channel_num The channel number + * @param[in] word_length The word length + * @param[in] word_select_size The word select size + * @param[in] trigger_level The trigger level + */ +void i2s_tx_channel_configure(enum i2s_device_num_t device_num, + enum i2s_channel_num_t channel_num, + enum word_length_t word_length, + enum word_select_cycles_t word_select_size, + enum fifo_threshold_t trigger_level, + enum i2s_work_mode_t word_mode); + +/** + * @brief disable block + * + * @param[in] device_num The device number + * @param[in] rxtx_mode The rxtx mode + */ +void i2s_disable_block(enum i2s_device_num_t device_num, + enum i2s_transmit_t rxtx_mode); + +/** + * @brief Enable I2S transmit DMA + * + * @param[in] device_num The device number + * @param[in] enable The enable + * + * @return result + * 0 Success + * Other Fail + */ +int i2s_transmit_dma_enable(enum i2s_device_num_t device_num, uint32_t enable); + +/** + * @brief Enable I2S receive DMA + * + * @param[in] device_num The device number + * @param[in] enable The enable + * + * @return result + * - 0 Success + * - Other Fail + */ +int i2s_receive_dma_enable(enum i2s_device_num_t device_num, uint32_t enable); + +/** + * @brief Split I2S transmit DMA from 32bit to two 16bit left and right + * + * @param[in] device_num The device number + * @param[in] enable The enable + * + * @return result + * - 0 Success + * - Other Fail + */ +int i2s_transmit_dma_divide(enum i2s_device_num_t device_num, uint32_t enable); + +/** + * @brief Write pcm data to channel_num channel + * + * @param[in] device_num The i2s number + * @param[in] channel_num The channel number + * @param[in] pcm 32bit (16 bits left and 16bits right)pcm data + * @param[in] device_num which of device + * + * @return result + * - 0 Success + * - Other Fail + */ +int i2s_transmit_data(enum i2s_device_num_t device_num, + enum i2s_channel_num_t channel_num, uint8_t *pcm, uint32_t length, uint8_t single_length); + +/** + * @brief I2s init + * + * @param[in] device_num The device number + * @param[in] rxtx_mode I2s work mode + * @param[in] channel_mask Channel mask to which channel work + * + */ +void i2s_init(enum i2s_device_num_t device_num, enum i2s_transmit_t rxtx_mode, uint32_t channel_mask); + +/** + * @brief Write pcm data to channel_num channel by dma + * + * @param[in] device_num which of device + * @param[in] pcm Send data + * @param[in] length Send data length + * @param[in] single_length Send data width + * @param[in] channel_num dmac channel + * + * @return result + * - 0 Success + * - Other Fail + */ +int i2s_transmit_data_dma(enum i2s_device_num_t device_num, + void *pcm, uint32_t length, uint8_t single_length, dmac_channel_number channel_num); + +/** + * @brief Write pcm data to channel_num channel by dma, first wait dmac done + * + * @param[in] device_num which of device + * @param[in] pcm Send data + * @param[in] length Send data length + * @param[in] channel_num dmac channel + * + */ +void i2s_send_data_dma(enum i2s_device_num_t device_num, + void *pcm, uint32_t length, dmac_channel_number channel_num); + +/** + * @brief Write pcm data to channel_num channel by dma + * + * @param[in] device_num which of device + * @param[in] channel_num which of device + * @param[in] buf Send data + * @param[in] length Send data length + * @param[in] frame I2s frame number + * @param[in] bits_per_sample I2s sample bits + * @param[in] track_num track num + * + * @return result + * - 0 Success + * - Other Fail + */ +int i2s_play(enum i2s_device_num_t device_num,dmac_channel_number channel_num, + uint8_t *buf, size_t length, uint32_t frame, uint32_t bits_per_sample, uint8_t track_num); + +/** + * @brief Write pcm data by dma from i2s to i2s + * + * @param[in] device_src_num I2s receive + * @param[in] device_dest_num I2s transfer + * @param[in] length Data length + * @param[in] channel_num Dmac channel + * + * @return result + * - 0 Success + * - Other Fail + */ +int32_t i2s_special_dma(enum i2s_device_num_t device_src_num, enum i2s_device_num_t device_dest_num, + uint32_t length, dmac_channel_number channel_num); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/drivers/include/io.h b/lib/drivers/include/io.h new file mode 100644 index 0000000..190263f --- /dev/null +++ b/lib/drivers/include/io.h @@ -0,0 +1,50 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _DRIVER_IO_H +#define _DRIVER_IO_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define readb(addr) (*(volatile uint8_t *)(addr)) +#define readw(addr) (*(volatile uint16_t *)(addr)) +#define readl(addr) (*(volatile uint32_t *)(addr)) +#define readq(addr) (*(volatile uint64_t *)(addr)) + +#define writeb(v, addr) \ + { \ + (*(volatile uint8_t *)(addr)) = (v); \ + } +#define writew(v, addr) \ + { \ + (*(volatile uint16_t *)(addr)) = (v); \ + } +#define writel(v, addr) \ + { \ + (*(volatile uint32_t *)(addr)) = (v); \ + } +#define writeq(v, addr) \ + { \ + (*(volatile uint64_t *)(addr)) = (v); \ + } + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_IO_H */ diff --git a/lib/drivers/include/otp.h b/lib/drivers/include/otp.h new file mode 100644 index 0000000..1597207 --- /dev/null +++ b/lib/drivers/include/otp.h @@ -0,0 +1,361 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _DRIVER_OTP_H +#define _DRIVER_OTP_H + +#include + +/* clang-format off */ +#define OTP_COMMON_DATA_ADDR 0x00000000U +#define OTP_SYSTEM_DATA_ADDR 0x00003AD0U +#define OTP_BISR_DATA_ADDR 0x00003DD0U +#define OTP_BLOCK_CTL_ADDR 0x00003FD0U +#define OTP_WIRED_REG_ADDR 0x00003FE0U +#define OTP_AES_KEY_ADDR 0x00003FF0U + +#define OTP_BUSY_FLAG 0x00000001U +#define OTP_BYPASS_FLAG 0x00000002U +#define OTP_TEST_FLAG 0x00000004U +/* clang-format on */ + +enum otp_status_t +{ + OTP_OK = 0, + OTP_ERROR_TIMEOUT, /* operation timeout*/ + OTP_ERROR_ADDRESS, /* invalid address*/ + OTP_ERROR_WRITE, /* write error*/ + OTP_ERROR_BLANK, /* blank check error*/ + OTP_ERROR_BISR, /* bisr error*/ + OTP_ERROR_TESTDEC, /* testdec error*/ + OTP_ERROR_WRTEST, /* wrtest error*/ + OTP_ERROR_KEYCOMP, /* key is wrong*/ + OTP_ERROR_PARAM, /* param error*/ + OTP_ERROR_NULL, /* undefine error*/ + OTP_BLOCK_NORMAL, /* block can be written*/ + OTP_BLOCK_PROTECTED,/* block can not be written*/ + OTP_FUNC_ENABLE, /* function available*/ + OTP_FUNC_DISABLE, /* function unavailable*/ + OTP_FLAG_SET, /* flag set*/ + OTP_FLAG_UNSET, /* flag unset*/ +}; + +enum otp_data_block_t +{ + COMMON_DATA_BLOCK1 = 0, + COMMON_DATA_BLOCK2, + COMMON_DATA_BLOCK3, + COMMON_DATA_BLOCK4, + COMMON_DATA_BLOCK5, + COMMON_DATA_BLOCK6, + COMMON_DATA_BLOCK7, + COMMON_DATA_BLOCK8, + COMMON_DATA_BLOCK9, + COMMON_DATA_BLOCK10, + COMMON_DATA_BLOCK11, + COMMON_DATA_BLOCK12, + COMMON_DATA_BLOCK13, + COMMON_DATA_BLOCK14, + COMMON_DATA_BLOCK15, + DATA_BLOCK_RESERVE, + SYSTEM_DATA_BLOCK1, + SYSTEM_DATA_BLOCK2, + SYSTEM_DATA_BLOCK3, + SYSTEM_DATA_BLOCK4, + SYSTEM_DATA_BLOCK5, + SYSTEM_DATA_BLOCK6, + SYSTEM_DATA_BLOCK7, + SYSTEM_DATA_BLOCK8, + SYSTEM_DATA_BLOCK9, + SYSTEM_DATA_BLOCK10, + SYSTEM_DATA_BLOCK11, + SYSTEM_DATA_BLOCK12, + SYSTEM_DATA_BLOCK13, + SYSTEM_DATA_BLOCK14, + SYSTEM_DATA_BLOCK15, + SYSTEM_DATA_BLOCK16, + SYSTEM_DATA_BLOCK17, + SYSTEM_DATA_BLOCK18, + SYSTEM_DATA_BLOCK19, + SYSTEM_DATA_BLOCK20, + SYSTEM_DATA_BLOCK21, + SYSTEM_DATA_BLOCK22, + SYSTEM_DATA_BLOCK23, + SYSTEM_DATA_BLOCK24, + SYSTEM_DATA_BLOCK25, + SYSTEM_DATA_BLOCK26, + SYSTEM_DATA_BLOCK27, + SYSTEM_DATA_BLOCK28, + SYSTEM_DATA_BLOCK29, + SYSTEM_DATA_BLOCK30, + SYSTEM_DATA_BLOCK31, + SYSTEM_DATA_BLOCK32, + SYSTEM_DATA_BLOCK33, + SYSTEM_DATA_BLOCK34, + SYSTEM_DATA_BLOCK35, + SYSTEM_DATA_BLOCK36, + SYSTEM_DATA_BLOCK37, + SYSTEM_DATA_BLOCK38, + SYSTEM_DATA_BLOCK39, + SYSTEM_DATA_BLOCK40, + SYSTEM_DATA_BLOCK41, + SYSTEM_DATA_BLOCK42, + SYSTEM_DATA_BLOCK43, + SYSTEM_DATA_BLOCK44, + SYSTEM_DATA_BLOCK45, + SYSTEM_DATA_BLOCK46, + SYSTEM_DATA_BLOCK47, + SYSTEM_DATA_BLOCK48, + DATA_BLOCK_MAX = 64, +}; + +enum otp_func_reg_t +{ + BLANK_TEST_DISABLE = 0, + RAM_BISR_DISABLE, + AES_WRITE_DISABLE, + AES_VERIFY_DISABLE, + JTAG_DISABLE, + TEST_EN_DISABLE = 6, + ISP_DISABLE, + OTP_FUNC_FIRMWARE_CIPHER_DISABLE, + FUNC_REG_MAX = 64, +}; + +struct otp_t +{ + volatile uint32_t otp_ceb; + volatile uint32_t otp_test_mode; + volatile uint32_t otp_mode; + volatile uint32_t gb_otp_en; + volatile uint32_t dat_in_finish; + volatile uint32_t otp_bisr_fail; + volatile uint32_t test_step; + volatile uint32_t otp_pwrrdy; + volatile uint32_t otp_last_dat; + volatile uint32_t otp_data; + volatile uint32_t otp_pwr_mode; + volatile uint32_t otp_in_dat; + volatile uint32_t otp_apb_adr; + volatile uint32_t td_result; + volatile uint32_t data_acp_flag; + volatile uint32_t otp_adr_in_flag; + volatile uint32_t wr_result; + volatile uint32_t otp_thershold; + volatile uint32_t bisr_finish; + volatile uint32_t key_cmp_result; + volatile uint32_t otp_cmp_key; + volatile uint32_t cmp_result_rdy; + volatile uint32_t otp_cle; + volatile uint32_t data_blk_ctrl; + volatile uint32_t otp_wrg_adr_flag; + volatile uint32_t pro_wrong; + volatile uint32_t otp_status; + volatile uint32_t otp_pro_adr; + volatile uint32_t blank_finish; + volatile uint32_t bisr2otp_en; + volatile uint32_t otp_cpu_ctrl; + volatile uint32_t otp_web_cpu; + volatile uint32_t otp_rstb_cpu; + volatile uint32_t otp_seltm_cpu; + volatile uint32_t otp_readen_cpu; + volatile uint32_t otp_pgmen_cpu; + volatile uint32_t otp_dle_cpu; + volatile uint32_t otp_din_cpu; + volatile uint32_t otp_cpumpen_cpu; + volatile uint32_t otp_cle_cpu; + volatile uint32_t otp_ceb_cpu; + volatile uint32_t otp_adr_cpu; + volatile uint32_t otp_dat_cpu; + volatile uint32_t otp_data_rdy; + volatile uint32_t block_flag_high; + volatile uint32_t block_flag_low; + volatile uint32_t reg_flag_high; + volatile uint32_t reg_flag_low; +} __attribute__((packed, aligned(4))); + +/** + * @brief Init OTP + * + * @note The otp clock frequency is 12.5M by default + * + * @param[in] div bus_clk / otp_clk + */ +void otp_init(uint8_t div); + +/** + * @brief Enable otp test mode + */ +void otp_test_enable(void); + +/** + * @brief Disable otp test mode + */ +void otp_test_disable(void); + +/** + * @brief Enable key output to aes + */ +void otp_key_output_enable(void); + +/** + * @brief Disable key output to aes + */ +void otp_key_output_disable(void); + +/** + * @brief Get the wrong address when programming fails + * + * @return The wrong address + */ +uint32_t otp_wrong_address_get(void); + +/** + * @brief Get OTP status + * + * @param[in] flag status flag + * + * @return Results of the operation + */ +enum otp_status_t otp_status_get(uint32_t flag); + +/** + * @brief Perform the blank check operation + * + * @return Results of the operation + */ +enum otp_status_t otp_blank_check(void); + +/** + * @brief Perform the testdec operation + * + * @return Results of the operation + */ +enum otp_status_t otp_testdec(void); + +/** + * @brief Perform the wrtest operation + * + * @return Results of the operation + */ +enum otp_status_t otp_wrtest(void); + +/** + * @brief Write data + * + * @param[in] addr Start programming address(bit) + * @param[in] data_buf Need to write the data point + * @param[in] length Need to write the data length(bit) + * + * @return Results of the operation + */ +enum otp_status_t otp_write_data(uint32_t addr, uint8_t *data_buf, uint32_t length); + +/** + * @brief Read data + * + * @param[in] addr Start read address(bit). + * @param[in] data_buf Need to read the data point + * @param[in] length Need to read the data length(bit) + * + * @return Results of the operation + */ +enum otp_status_t otp_read_data(uint32_t addr, uint8_t *data_buf, uint32_t length); + +/** + * @brief Write the key + * + * @param[in] data_buf The key data,length is 128 bits(4 words) + * + * @return Results of the operation + */ +enum otp_status_t otp_key_write(uint8_t *data_buf); + +/** + * @brief Compare the key + * + * @param[in] data_buf The key data,length is 128 bits(4 words) + * + * @return Results of the operation + */ +enum otp_status_t otp_key_compare(uint8_t *data_buf); + +/** + * @brief Data block write protect + * + * @param[in] block Need to write a protected data block + * + * @return Results of the operation + */ +enum otp_status_t otp_data_block_protect_set(enum otp_data_block_t block); + +/** + * @brief Disable the specified function + * + * @param[in] reg Need to disable the function + * + * @return Results of the operation + */ +enum otp_status_t otp_func_reg_disable_set(enum otp_func_reg_t func); + +/** + * @brief Get the data block status + * + * @param[in] block The specified data block + * + * @return Results of the operation + */ +enum otp_status_t otp_data_block_protect_get(enum otp_data_block_t block); + +/** + * @brief Get the function status + * + * @param[in] reg The specified function + * + * @return Results of the operation + */ +enum otp_status_t otp_func_reg_disable_get(enum otp_func_reg_t func); + +/** + * @brief Refresh the data block status + * + * @param[in] block The specified data block + * + * @return Results of the operation + */ +enum otp_status_t otp_data_block_protect_refresh(enum otp_data_block_t block); + +/** + * @brief Write data(bypass mode) + * + * @param[in] addr Start programming address(bit) + * @param[in] data_buf Need to write the data point + * @param[in] length Need to write the data length(bit) + * + * @return Results of the operation + */ +enum otp_status_t otp_soft_write(uint32_t addr, uint8_t *data_buf, uint32_t length); + +/** + * @brief Read data(bypass mode) + * + * @param[in] addr Start read address(bit).Be sure to align 16 bits + * @param[in] data_buf Need to read the data point + * @param[in] length Need to read the data length(half word/16bits) + * + * @return Results of the operation + */ +enum otp_status_t otp_soft_read(uint32_t addr, uint8_t *data_buf, uint32_t length); + +#endif diff --git a/lib/drivers/include/plic.h b/lib/drivers/include/plic.h new file mode 100644 index 0000000..ace6bbc --- /dev/null +++ b/lib/drivers/include/plic.h @@ -0,0 +1,462 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file + * @brief The PLIC complies with the RISC-V Privileged Architecture + * specification, and can support a maximum of 1023 external + * interrupt sources targeting up to 15,872 hart contexts. + * + * @note PLIC RAM Layout + * + * | Address | Description | + * |-----------|---------------------------------| + * |0x0C000000 | Reserved | + * |0x0C000004 | source 1 priority | + * |0x0C000008 | source 2 priority | + * |... | ... | + * |0x0C000FFC | source 1023 priority | + * | | | + * |0x0C001000 | Start of pending array | + * |... | (read-only) | + * |0x0C00107C | End of pending array | + * |0x0C001080 | Reserved | + * |... | ... | + * |0x0C001FFF | Reserved | + * | | | + * |0x0C002000 | target 0 enables | + * |0x0C002080 | target 1 enables | + * |... | ... | + * |0x0C1F1F80 | target 15871 enables | + * |0x0C1F2000 | Reserved | + * |... | ... | + * |0x0C1FFFFC | Reserved | + * | | | + * |0x0C200000 | target 0 priority threshold | + * |0x0C200004 | target 0 claim/complete | + * |... | ... | + * |0x0C201000 | target 1 priority threshold | + * |0x0C201004 | target 1 claim/complete | + * |... | ... | + * |0x0FFFF000 | target 15871 priority threshold | + * |0x0FFFF004 | target 15871 claim/complete | + * + */ + +#ifndef _DRIVER_PLIC_H +#define _DRIVER_PLIC_H + +#include +#include "env/encoding.h" +#include "platform.h" + +/* For c++ compatibility */ +#ifdef __cplusplus +extern "C" { +#endif + +/* clang-format off */ +/* IRQ number settings */ +#define PLIC_NUM_SOURCES (IRQN_MAX - 1) +#define PLIC_NUM_PRIORITIES (7) + +/* Real number of cores */ +#define PLIC_NUM_HARTS (2) +/* clang-format on */ + +/** + * @brief PLIC External Interrupt Numbers + * + * @note PLIC interrupt sources + * + * | Source | Name | Description | + * |--------|--------------------------|------------------------------------| + * | 0 | IRQN_NO_INTERRUPT | The non-existent interrupt | + * | 1 | IRQN_SPI0_INTERRUPT | SPI0 interrupt | + * | 2 | IRQN_SPI1_INTERRUPT | SPI1 interrupt | + * | 3 | IRQN_SPI_SLAVE_INTERRUPT | SPI_SLAVE interrupt | + * | 4 | IRQN_SPI3_INTERRUPT | SPI3 interrupt | + * | 5 | IRQN_I2S0_INTERRUPT | I2S0 interrupt | + * | 6 | IRQN_I2S1_INTERRUPT | I2S1 interrupt | + * | 7 | IRQN_I2S2_INTERRUPT | I2S2 interrupt | + * | 8 | IRQN_I2C0_INTERRUPT | I2C0 interrupt | + * | 9 | IRQN_I2C1_INTERRUPT | I2C1 interrupt | + * | 10 | IRQN_I2C2_INTERRUPT | I2C2 interrupt | + * | 11 | IRQN_UART1_INTERRUPT | UART1 interrupt | + * | 12 | IRQN_UART2_INTERRUPT | UART2 interrupt | + * | 13 | IRQN_UART3_INTERRUPT | UART3 interrupt | + * | 14 | IRQN_TIMER0A_INTERRUPT | TIMER0 channel 0 or 1 interrupt | + * | 15 | IRQN_TIMER0B_INTERRUPT | TIMER0 channel 2 or 3 interrupt | + * | 16 | IRQN_TIMER1A_INTERRUPT | TIMER1 channel 0 or 1 interrupt | + * | 17 | IRQN_TIMER1B_INTERRUPT | TIMER1 channel 2 or 3 interrupt | + * | 18 | IRQN_TIMER2A_INTERRUPT | TIMER2 channel 0 or 1 interrupt | + * | 19 | IRQN_TIMER2B_INTERRUPT | TIMER2 channel 2 or 3 interrupt | + * | 20 | IRQN_RTC_INTERRUPT | RTC tick and alarm interrupt | + * | 21 | IRQN_WDT0_INTERRUPT | Watching dog timer0 interrupt | + * | 22 | IRQN_WDT1_INTERRUPT | Watching dog timer1 interrupt | + * | 23 | IRQN_APB_GPIO_INTERRUPT | APB GPIO interrupt | + * | 24 | IRQN_DVP_INTERRUPT | Digital video port interrupt | + * | 25 | IRQN_AI_INTERRUPT | AI accelerator interrupt | + * | 26 | IRQN_FFT_INTERRUPT | FFT accelerator interrupt | + * | 27 | IRQN_DMA0_INTERRUPT | DMA channel0 interrupt | + * | 28 | IRQN_DMA1_INTERRUPT | DMA channel1 interrupt | + * | 29 | IRQN_DMA2_INTERRUPT | DMA channel2 interrupt | + * | 30 | IRQN_DMA3_INTERRUPT | DMA channel3 interrupt | + * | 31 | IRQN_DMA4_INTERRUPT | DMA channel4 interrupt | + * | 32 | IRQN_DMA5_INTERRUPT | DMA channel5 interrupt | + * | 33 | IRQN_UARTHS_INTERRUPT | Hi-speed UART0 interrupt | + * | 34 | IRQN_GPIOHS0_INTERRUPT | Hi-speed GPIO0 interrupt | + * | 35 | IRQN_GPIOHS1_INTERRUPT | Hi-speed GPIO1 interrupt | + * | 36 | IRQN_GPIOHS2_INTERRUPT | Hi-speed GPIO2 interrupt | + * | 37 | IRQN_GPIOHS3_INTERRUPT | Hi-speed GPIO3 interrupt | + * | 38 | IRQN_GPIOHS4_INTERRUPT | Hi-speed GPIO4 interrupt | + * | 39 | IRQN_GPIOHS5_INTERRUPT | Hi-speed GPIO5 interrupt | + * | 40 | IRQN_GPIOHS6_INTERRUPT | Hi-speed GPIO6 interrupt | + * | 41 | IRQN_GPIOHS7_INTERRUPT | Hi-speed GPIO7 interrupt | + * | 42 | IRQN_GPIOHS8_INTERRUPT | Hi-speed GPIO8 interrupt | + * | 43 | IRQN_GPIOHS9_INTERRUPT | Hi-speed GPIO9 interrupt | + * | 44 | IRQN_GPIOHS10_INTERRUPT | Hi-speed GPIO10 interrupt | + * | 45 | IRQN_GPIOHS11_INTERRUPT | Hi-speed GPIO11 interrupt | + * | 46 | IRQN_GPIOHS12_INTERRUPT | Hi-speed GPIO12 interrupt | + * | 47 | IRQN_GPIOHS13_INTERRUPT | Hi-speed GPIO13 interrupt | + * | 48 | IRQN_GPIOHS14_INTERRUPT | Hi-speed GPIO14 interrupt | + * | 49 | IRQN_GPIOHS15_INTERRUPT | Hi-speed GPIO15 interrupt | + * | 50 | IRQN_GPIOHS16_INTERRUPT | Hi-speed GPIO16 interrupt | + * | 51 | IRQN_GPIOHS17_INTERRUPT | Hi-speed GPIO17 interrupt | + * | 52 | IRQN_GPIOHS18_INTERRUPT | Hi-speed GPIO18 interrupt | + * | 53 | IRQN_GPIOHS19_INTERRUPT | Hi-speed GPIO19 interrupt | + * | 54 | IRQN_GPIOHS20_INTERRUPT | Hi-speed GPIO20 interrupt | + * | 55 | IRQN_GPIOHS21_INTERRUPT | Hi-speed GPIO21 interrupt | + * | 56 | IRQN_GPIOHS22_INTERRUPT | Hi-speed GPIO22 interrupt | + * | 57 | IRQN_GPIOHS23_INTERRUPT | Hi-speed GPIO23 interrupt | + * | 58 | IRQN_GPIOHS24_INTERRUPT | Hi-speed GPIO24 interrupt | + * | 59 | IRQN_GPIOHS25_INTERRUPT | Hi-speed GPIO25 interrupt | + * | 60 | IRQN_GPIOHS26_INTERRUPT | Hi-speed GPIO26 interrupt | + * | 61 | IRQN_GPIOHS27_INTERRUPT | Hi-speed GPIO27 interrupt | + * | 62 | IRQN_GPIOHS28_INTERRUPT | Hi-speed GPIO28 interrupt | + * | 63 | IRQN_GPIOHS29_INTERRUPT | Hi-speed GPIO29 interrupt | + * | 64 | IRQN_GPIOHS30_INTERRUPT | Hi-speed GPIO30 interrupt | + * | 65 | IRQN_GPIOHS31_INTERRUPT | Hi-speed GPIO31 interrupt | + * + */ +/* clang-format off */ +typedef enum plic_irq_t +{ + IRQN_NO_INTERRUPT = 0, /*!< The non-existent interrupt */ + IRQN_SPI0_INTERRUPT = 1, /*!< SPI0 interrupt */ + IRQN_SPI1_INTERRUPT = 2, /*!< SPI1 interrupt */ + IRQN_SPI_SLAVE_INTERRUPT = 3, /*!< SPI_SLAVE interrupt */ + IRQN_SPI3_INTERRUPT = 4, /*!< SPI3 interrupt */ + IRQN_I2S0_INTERRUPT = 5, /*!< I2S0 interrupt */ + IRQN_I2S1_INTERRUPT = 6, /*!< I2S1 interrupt */ + IRQN_I2S2_INTERRUPT = 7, /*!< I2S2 interrupt */ + IRQN_I2C0_INTERRUPT = 8, /*!< I2C0 interrupt */ + IRQN_I2C1_INTERRUPT = 9, /*!< I2C1 interrupt */ + IRQN_I2C2_INTERRUPT = 10, /*!< I2C2 interrupt */ + IRQN_UART1_INTERRUPT = 11, /*!< UART1 interrupt */ + IRQN_UART2_INTERRUPT = 12, /*!< UART2 interrupt */ + IRQN_UART3_INTERRUPT = 13, /*!< UART3 interrupt */ + IRQN_TIMER0A_INTERRUPT = 14, /*!< TIMER0 channel 0 or 1 interrupt */ + IRQN_TIMER0B_INTERRUPT = 15, /*!< TIMER0 channel 2 or 3 interrupt */ + IRQN_TIMER1A_INTERRUPT = 16, /*!< TIMER1 channel 0 or 1 interrupt */ + IRQN_TIMER1B_INTERRUPT = 17, /*!< TIMER1 channel 2 or 3 interrupt */ + IRQN_TIMER2A_INTERRUPT = 18, /*!< TIMER2 channel 0 or 1 interrupt */ + IRQN_TIMER2B_INTERRUPT = 19, /*!< TIMER2 channel 2 or 3 interrupt */ + IRQN_RTC_INTERRUPT = 20, /*!< RTC tick and alarm interrupt */ + IRQN_WDT0_INTERRUPT = 21, /*!< Watching dog timer0 interrupt */ + IRQN_WDT1_INTERRUPT = 22, /*!< Watching dog timer1 interrupt */ + IRQN_APB_GPIO_INTERRUPT = 23, /*!< APB GPIO interrupt */ + IRQN_DVP_INTERRUPT = 24, /*!< Digital video port interrupt */ + IRQN_AI_INTERRUPT = 25, /*!< AI accelerator interrupt */ + IRQN_FFT_INTERRUPT = 26, /*!< FFT accelerator interrupt */ + IRQN_DMA0_INTERRUPT = 27, /*!< DMA channel0 interrupt */ + IRQN_DMA1_INTERRUPT = 28, /*!< DMA channel1 interrupt */ + IRQN_DMA2_INTERRUPT = 29, /*!< DMA channel2 interrupt */ + IRQN_DMA3_INTERRUPT = 30, /*!< DMA channel3 interrupt */ + IRQN_DMA4_INTERRUPT = 31, /*!< DMA channel4 interrupt */ + IRQN_DMA5_INTERRUPT = 32, /*!< DMA channel5 interrupt */ + IRQN_UARTHS_INTERRUPT = 33, /*!< Hi-speed UART0 interrupt */ + IRQN_GPIOHS0_INTERRUPT = 34, /*!< Hi-speed GPIO0 interrupt */ + IRQN_GPIOHS1_INTERRUPT = 35, /*!< Hi-speed GPIO1 interrupt */ + IRQN_GPIOHS2_INTERRUPT = 36, /*!< Hi-speed GPIO2 interrupt */ + IRQN_GPIOHS3_INTERRUPT = 37, /*!< Hi-speed GPIO3 interrupt */ + IRQN_GPIOHS4_INTERRUPT = 38, /*!< Hi-speed GPIO4 interrupt */ + IRQN_GPIOHS5_INTERRUPT = 39, /*!< Hi-speed GPIO5 interrupt */ + IRQN_GPIOHS6_INTERRUPT = 40, /*!< Hi-speed GPIO6 interrupt */ + IRQN_GPIOHS7_INTERRUPT = 41, /*!< Hi-speed GPIO7 interrupt */ + IRQN_GPIOHS8_INTERRUPT = 42, /*!< Hi-speed GPIO8 interrupt */ + IRQN_GPIOHS9_INTERRUPT = 43, /*!< Hi-speed GPIO9 interrupt */ + IRQN_GPIOHS10_INTERRUPT = 44, /*!< Hi-speed GPIO10 interrupt */ + IRQN_GPIOHS11_INTERRUPT = 45, /*!< Hi-speed GPIO11 interrupt */ + IRQN_GPIOHS12_INTERRUPT = 46, /*!< Hi-speed GPIO12 interrupt */ + IRQN_GPIOHS13_INTERRUPT = 47, /*!< Hi-speed GPIO13 interrupt */ + IRQN_GPIOHS14_INTERRUPT = 48, /*!< Hi-speed GPIO14 interrupt */ + IRQN_GPIOHS15_INTERRUPT = 49, /*!< Hi-speed GPIO15 interrupt */ + IRQN_GPIOHS16_INTERRUPT = 50, /*!< Hi-speed GPIO16 interrupt */ + IRQN_GPIOHS17_INTERRUPT = 51, /*!< Hi-speed GPIO17 interrupt */ + IRQN_GPIOHS18_INTERRUPT = 52, /*!< Hi-speed GPIO18 interrupt */ + IRQN_GPIOHS19_INTERRUPT = 53, /*!< Hi-speed GPIO19 interrupt */ + IRQN_GPIOHS20_INTERRUPT = 54, /*!< Hi-speed GPIO20 interrupt */ + IRQN_GPIOHS21_INTERRUPT = 55, /*!< Hi-speed GPIO21 interrupt */ + IRQN_GPIOHS22_INTERRUPT = 56, /*!< Hi-speed GPIO22 interrupt */ + IRQN_GPIOHS23_INTERRUPT = 57, /*!< Hi-speed GPIO23 interrupt */ + IRQN_GPIOHS24_INTERRUPT = 58, /*!< Hi-speed GPIO24 interrupt */ + IRQN_GPIOHS25_INTERRUPT = 59, /*!< Hi-speed GPIO25 interrupt */ + IRQN_GPIOHS26_INTERRUPT = 60, /*!< Hi-speed GPIO26 interrupt */ + IRQN_GPIOHS27_INTERRUPT = 61, /*!< Hi-speed GPIO27 interrupt */ + IRQN_GPIOHS28_INTERRUPT = 62, /*!< Hi-speed GPIO28 interrupt */ + IRQN_GPIOHS29_INTERRUPT = 63, /*!< Hi-speed GPIO29 interrupt */ + IRQN_GPIOHS30_INTERRUPT = 64, /*!< Hi-speed GPIO30 interrupt */ + IRQN_GPIOHS31_INTERRUPT = 65, /*!< Hi-speed GPIO31 interrupt */ + IRQN_MAX +} plic_irq_t; +/* clang-format on */ + +/** + * @brief Interrupt Source Priorities + * + * Each external interrupt source can be assigned a priority by + * writing to its 32-bit memory-mapped priority register. The + * number and value of supported priority levels can vary by + * implementa- tion, with the simplest implementations having all + * devices hardwired at priority 1, in which case, interrupts with + * the lowest ID have the highest effective priority. The priority + * registers are all WARL. + */ +struct plic_source_priorities_t +{ + /* 0x0C000000: Reserved, 0x0C000004-0x0C000FFC: 1-1023 priorities */ + uint32_t priority[1024]; +} __attribute__((packed, aligned(4))); + +/** + * @brief Interrupt Pending Bits + * + * The current status of the interrupt source pending bits in the + * PLIC core can be read from the pending array, organized as 32 + * words of 32 bits. The pending bit for interrupt ID N is stored + * in bit (N mod 32) of word (N/32). Bit 0 of word 0, which + * represents the non-existent interrupt source 0, is always + * hardwired to zero. The pending bits are read-only. A pending + * bit in the PLIC core can be cleared by setting enable bits to + * only enable the desired interrupt, then performing a claim. A + * pending bit can be set by instructing the associated gateway to + * send an interrupt service request. + */ +struct plic_pending_bits_t { + /* 0x0C001000-0x0C00107C: Bit 0 is zero, Bits 1-1023 is pending bits */ + uint32_t u32[32]; + /* 0x0C001080-0x0C001FFF: Reserved */ + uint8_t resv[0xF80]; +} __attribute__((packed, aligned(4))); + +/** + * @brief Target Interrupt Enables + * + * For each interrupt target, each device’s interrupt can be + * enabled by setting the corresponding bit in that target’s + * enables registers. The enables for a target are accessed as a + * contiguous array of 32×32-bit words, packed the same way as the + * pending bits. For each target, bit 0 of enable word 0 + * represents the non-existent interrupt ID 0 and is hardwired to + * 0. Unused interrupt IDs are also hardwired to zero. The enables + * arrays for different targets are packed contiguously in the + * address space. Only 32-bit word accesses are supported by the + * enables array in RV32 systems. Implementations can trap on + * accesses to enables for non-existent targets, but must allow + * access to the full enables array for any extant target, + * treating all non-existent interrupt source’s enables as + * hardwired to zero. + */ +struct plic_target_enables_t +{ + /* 0x0C002000-0x0C1F1F80: target 0-15871 enables */ + struct + { + uint32_t enable[32];/* Offset 0x00-0x7C: Bit 0 is zero, Bits 1-1023 is bits*/ + } target[15872]; + + /* 0x0C1F2000-0x0C1FFFFC: Reserved, size 0xE000 */ + uint8_t resv[0xE000]; +} __attribute__((packed, aligned(4))); + +/** + * @brief PLIC Targets + * + * Target Priority Thresholds The threshold for a pending + * interrupt priority that can interrupt each target can be set in + * the target’s threshold register. The threshold is a WARL field, + * where different implementations can support different numbers + * of thresholds. The simplest implementation has a threshold + * hardwired to zero. + * + * Target Claim Each target can perform a claim by reading the + * claim/complete register, which returns the ID of the highest + * priority pending interrupt or zero if there is no pending + * interrupt for the target. A successful claim will also + * atomically clear the corresponding pending bit on the interrupt + * source. A target can perform a claim at any time, even if the + * EIP is not set. The claim operation is not affected by the + * setting of the target’s priority threshold register. + * + * Target Completion A target signals it has completed running a + * handler by writing the interrupt ID it received from the claim + * to the claim/complete register. This is routed to the + * corresponding interrupt gateway, which can now send another + * interrupt request to the PLIC. The PLIC does not check whether + * the completion ID is the same as the last claim ID for that + * target. If the completion ID does not match an interrupt source + * that is currently enabled for the target, the completion is + * silently ignored. + */ +struct plic_target_t +{ + /* 0x0C200000-0x0FFFF004: target 0-15871 */ + struct { + uint32_t priority_threshold;/* Offset 0x000 */ + uint32_t claim_complete; /* Offset 0x004 */ + uint8_t resv[0xFF8]; /* Offset 0x008, Size 0xFF8 */ + } target[15872]; +} __attribute__((packed, aligned(4))); + +/** + * @brief Platform-Level Interrupt Controller + * + * PLIC is Platform-Level Interrupt Controller. The PLIC complies + * with the RISC-V Privileged Architecture specification, and can + * support a maximum of 1023 external interrupt sources targeting + * up to 15,872 hart contexts. + */ +struct plic_t +{ + /* 0x0C000000-0x0C000FFC */ + struct plic_source_priorities_t source_priorities; + /* 0x0C001000-0x0C001FFF */ + const struct plic_pending_bits_t pending_bits; + /* 0x0C002000-0x0C1FFFFC */ + struct plic_target_enables_t target_enables; + /* 0x0C200000-0x0FFFF004 */ + struct plic_target_t targets; +} __attribute__((packed, aligned(4))); + +extern volatile struct plic_t *const plic; + +/** + * @brief Definitions for the interrupt callbacks + */ +typedef int (*plic_irq_callback_t)(void *ctx); + +/** + * @brief Initialize PLIC external interrupt + * + * @note This function will set MIP_MEIP. The MSTATUS_MIE must set by user. + * + * @return result + * - 0 Success + * - Other Fail + */ +int plic_init(void); + +/** + * @brief Enable PLIC external interrupt + * + * @param[in] irq_number external interrupt number + * + * @return result + * - 0 Success + * - Other Fail + */ + +int plic_irq_enable(plic_irq_t irq_number); + +/** + * @brief Disable PLIC external interrupt + * + * @param[in] irq_number The external interrupt number + * + * @return result + * - 0 Success + * - Other Fail + */ +int plic_irq_disable(plic_irq_t irq_number); + +/** + * @brief Set IRQ priority + * + * @param[in] irq_number The external interrupt number + * @param[in] priority The priority of external interrupt number + * + * @return result + * - 0 Success + * - Other Fail + */ +int plic_set_priority(plic_irq_t irq_number, uint32_t priority); + +/** + * @brief Get IRQ priority + * + * @param[in] irq_number The external interrupt number + * + * @return The priority of external interrupt number + */ +uint32_t plic_get_priority(plic_irq_t irq_number); + +/** + * @brief Claim an IRQ + * + * @return The current IRQ number + */ +uint32_t plic_irq_claim(void); + +/** + * @brief Complete an IRQ + * + * @param[in] source The source IRQ number to complete + * + * @return result + * - 0 Success + * - Other Fail + */ +int plic_irq_complete(uint32_t source); + +/** + * @brief Register user callback function by IRQ number + * + * @param[in] irq The irq + * @param[in] callback The callback + * @param ctx The context + * + * @return result + * - 0 Success + * - Other Fail + */ +int plic_irq_register(plic_irq_t irq, plic_irq_callback_t callback, void *ctx); + +/** + * @brief Deegister user callback function by IRQ number + * + * @param[in] irq The irq + * + * @return result + * - 0 Success + * - Other Fail + */ +int plic_irq_deregister(plic_irq_t irq); + +/* For c++ compatibility */ +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_PLIC_H */ diff --git a/lib/drivers/include/rtc.h b/lib/drivers/include/rtc.h new file mode 100644 index 0000000..00a1f99 --- /dev/null +++ b/lib/drivers/include/rtc.h @@ -0,0 +1,603 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file + * @brief A real-time clock (RTC) is a computer clock that keeps track of + * the current time. + */ + +#ifndef _DRIVER_RTC_H +#define _DRIVER_RTC_H + +#include +#include +#include "platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief RTC timer mode + * + * Timer mode selector + * | Mode | Description | + * |------|------------------------| + * | 0 | Timer pause | + * | 1 | Timer time running | + * | 2 | Timer time setting | + */ +typedef enum _rtc_timer_mode_e +{ + /* 0: Timer pause */ + RTC_TIMER_PAUSE, + /* 1: Timer time running */ + RTC_TIMER_RUNNING, + /* 2: Timer time setting */ + RTC_TIMER_SETTING, + /* Max count of this enum*/ + RTC_TIMER_MAX +}rtc_timer_mode_e; + +/* + * @brief RTC tick interrupt mode + * + * Tick interrupt mode selector + * | Mode | Description | + * |------|------------------------| + * | 0 | Interrupt every second | + * | 1 | Interrupt every minute | + * | 2 | Interrupt every hour | + * | 3 | Interrupt every day | + */ +typedef enum _rtc_tick_interrupt_mode_e +{ + /* 0: Interrupt every second */ + RTC_INT_SECOND, + /* 1: Interrupt every minute */ + RTC_INT_MINUTE, + /* 2: Interrupt every hour */ + RTC_INT_HOUR, + /* 3: Interrupt every day */ + RTC_INT_DAY, + /* Max count of this enum*/ + RTC_INT_MAX +}rtc_tick_interrupt_mode_e; + +/** + * @brief RTC mask structure + * + * RTC mask structure for common use + */ +struct rtc_mask_t { + /* Reserved */ + uint32_t resv : 1; + /* Second mask */ + uint32_t second : 1; + /* Minute mask */ + uint32_t minute : 1; + /* Hour mask */ + uint32_t hour : 1; + /* Week mask */ + uint32_t week : 1; + /* Day mask */ + uint32_t day : 1; + /* Month mask */ + uint32_t month : 1; + /* Year mask */ + uint32_t year : 1; +} __attribute__((packed, aligned(1))); + +/** + * @brief RTC register + * + * @note RTC register table + * + * | Offset | Name | Description | + * |-----------|----------------|-------------------------------------| + * | 0x00 | date | Timer date information | + * | 0x04 | time | Timer time information | + * | 0x08 | alarm_date | Alarm date information | + * | 0x0c | alarm_time | Alarm time information | + * | 0x10 | initial_count | Timer counter initial value | + * | 0x14 | current_count | Timer counter current value | + * | 0x18 | interrupt_ctrl | RTC interrupt settings | + * | 0x1c | register_ctrl | RTC register settings | + * | 0x20 | reserved0 | Reserved | + * | 0x24 | reserved1 | Reserved | + * | 0x28 | extended | Timer extended information | + * + */ + + +/** + * @brief Timer date information + * + * No. 0 Register (0x00) + */ +struct rtc_date_t +{ + /* Week. Range [0,6]. 0 is Sunday. */ + uint32_t week : 3; + /* Reserved */ + uint32_t resv0 : 5; + /* Day. Range [1,31] or [1,30] or [1,29] or [1,28] */ + uint32_t day : 5; + /* Reserved */ + uint32_t resv1 : 3; + /* Month. Range [1,12] */ + uint32_t month : 4; + /* Year. Range [0,99] */ + uint32_t year : 12; +} __attribute__((packed, aligned(4))); + +/** + * @brief Timer time information + * + * No. 1 Register (0x04) + */ +struct rtc_time_t +{ + /* Reserved */ + uint32_t resv0 : 10; + /* Second. Range [0,59] */ + uint32_t second : 6; + /* Minute. Range [0,59] */ + uint32_t minute : 6; + /* Reserved */ + uint32_t resv1 : 2; + /* Hour. Range [0,23] */ + uint32_t hour : 5; + /* Reserved */ + uint32_t resv2 : 3; +} __attribute__((packed, aligned(4))); + +/** + * @brief Alarm date information + * + * No. 2 Register (0x08) + */ +struct rtc_alarm_date_t +{ + /* Alarm Week. Range [0,6]. 0 is Sunday. */ + uint32_t week : 3; + /* Reserved */ + uint32_t resv0 : 5; + /* Alarm Day. Range [1,31] or [1,30] or [1,29] or [1,28] */ + uint32_t day : 5; + /* Reserved */ + uint32_t resv1 : 3; + /* Alarm Month. Range [1,12] */ + uint32_t month : 4; + /* Alarm Year. Range [0,99] */ + uint32_t year : 12; +} __attribute__((packed, aligned(4))); + +/** + * @brief Alarm time information + * + * No. 3 Register (0x0c) + */ +struct rtc_alarm_time_t +{ + /* Reserved */ + uint32_t resv0 : 10; + /* Alarm Second. Range [0,59] */ + uint32_t second : 6; + /* Alarm Minute. Range [0,59] */ + uint32_t minute : 6; + /* Reserved */ + uint32_t resv1 : 2; + /* Alarm Hour. Range [0,23] */ + uint32_t hour : 5; + /* Reserved */ + uint32_t resv2 : 3; +} __attribute__((packed, aligned(4))); + +/** + * @brief Timer counter initial value + * + * No. 4 Register (0x10) + */ +struct rtc_initial_count_t +{ + /* RTC counter initial value */ + uint32_t count : 32; +} __attribute__((packed, aligned(4))); + +/** + * @brief Timer counter current value + * + * No. 5 Register (0x14) + */ +struct rtc_current_count_t +{ + /* RTC counter current value */ + uint32_t count : 32; +} __attribute__((packed, aligned(4))); + +/** + * @brief RTC interrupt settings + * + * No. 6 Register (0x18) + */ +struct rtc_interrupt_ctrl_t +{ + /* Reserved */ + uint32_t tick_enable : 1; + /* Alarm interrupt enable */ + uint32_t alarm_enable : 1; + /* Tick interrupt enable */ + uint32_t tick_int_mode : 2; + /* Reserved */ + uint32_t resv : 20; + /* Alarm compare mask for interrupt */ + uint32_t alarm_compare_mask : 8; +} __attribute__((packed, aligned(4))); + +/** + * @brief RTC register settings + * + * No. 7 Register (0x1c) + */ +struct rtc_register_ctrl_t +{ + /* RTC timer read enable */ + uint32_t read_enable : 1; + /* RTC timer write enable */ + uint32_t write_enable : 1; + /* Reserved */ + uint32_t resv0 : 11; + /* RTC timer mask */ + uint32_t timer_mask : 8; + /* RTC alarm mask */ + uint32_t alarm_mask : 8; + /* RTC counter initial count value mask */ + uint32_t initial_count_mask : 1; + /* RTC interrupt register mask */ + uint32_t interrupt_register_mask : 1; + /* Reserved */ + uint32_t resv1 : 1; +} __attribute__((packed, aligned(4))); + +/** + * @brief Reserved + * + * No. 8 Register (0x20) + */ +struct rtc_reserved0_t +{ + /* Reserved */ + uint32_t resv : 32; +} __attribute__((packed, aligned(4))); + +/** + * @brief Reserved + * + * No. 9 Register (0x24) + */ +struct rtc_reserved1_t +{ + /* Reserved */ + uint32_t resv : 32; +} __attribute__((packed, aligned(4))); + +/** + * @brief Timer extended information + * + * No. 10 Register (0x28) + */ +struct rtc_extended_t +{ + /* Century. Range [0,31] */ + uint32_t century : 5; + /* Is leap year. 1 is leap year, 0 is not leap year */ + uint32_t leap_year : 1; + /* Reserved */ + uint32_t resv : 26; +} __attribute__((packed, aligned(4))); + + +/** + * @brief Real-time clock struct + * + * A real-time clock (RTC) is a computer clock that keeps track of + * the current time. + */ +struct rtc_t +{ + /* No. 0 (0x00): Timer date information */ + struct rtc_date_t date; + /* No. 1 (0x04): Timer time information */ + struct rtc_time_t time; + /* No. 2 (0x08): Alarm date information */ + struct rtc_alarm_date_t alarm_date; + /* No. 3 (0x0c): Alarm time information */ + struct rtc_alarm_time_t alarm_time; + /* No. 4 (0x10): Timer counter initial value */ + struct rtc_initial_count_t initial_count; + /* No. 5 (0x14): Timer counter current value */ + struct rtc_current_count_t current_count; + /* No. 6 (0x18): RTC interrupt settings */ + struct rtc_interrupt_ctrl_t interrupt_ctrl; + /* No. 7 (0x1c): RTC register settings */ + struct rtc_register_ctrl_t register_ctrl; + /* No. 8 (0x20): Reserved */ + struct rtc_reserved0_t reserved0; + /* No. 9 (0x24): Reserved */ + struct rtc_reserved1_t reserved1; + /* No. 10 (0x28): Timer extended information */ + struct rtc_extended_t extended; +} __attribute__((packed, aligned(4))); + + +/** + * @brief Real-time clock object + */ +extern volatile struct rtc_t *const rtc; +extern volatile uint32_t *const rtc_base; +/** + * @brief Set RTC timer mode + * + * @param[in] timer_mode The timer mode + * + * @return result + * - 0 Success + * - Other Fail + */ +int rtc_timer_mode_set(rtc_timer_mode_e timer_mode); + +/** + * @brief Get RTC timer mode + * + * @return The timer mode + */ +rtc_timer_mode_e rtc_timer_get_mode(void); + +/** + * @brief Set date time to RTC + * + * @param[in] tm The Broken-down date time + * + * @return result + * - 0 Success + * - Other Fail + */ +int rtc_timer_set_tm(const struct tm *tm); + +/** + * @brief Get date time from RTC + * + * @return The Broken-down date time + */ +struct tm *rtc_timer_get_tm(void); + +/** + * @brief Set date time to Alarm + * + * @param[in] tm The Broken-down date time + * + * @return result + * - 0 Success + * - Other Fail + */ +int rtc_timer_set_alarm_tm(const struct tm *tm); + +/** + * @brief Get date time from Alarm + * + * @return The Broken-down date time + */ +struct tm *rtc_timer_get_alarm_tm(void); + +/** + * @brief Check if it is a leap year + * + * @param[in] year The year + * + * @return result + * - 0 Success + * - Other Fail + */ +int rtc_year_is_leap(int year); + +/** + * @brief Get day of year from date + * + * @param[in] year The year + * @param[in] month The month + * @param[in] day The day + * + * @return The day of year from date + */ +int rtc_get_yday(int year, int month, int day); + +/** + * @brief Get the day of the week from date + * + * @param[in] year The year + * @param[in] month The month + * @param[in] day The day + * + * @return The day of the week. + * Where Sunday = 0, Monday = 1, Tuesday = 2, Wednesday = 3, + * Thursday = 4, Friday = 5, Saturday = 6. + */ +int rtc_get_wday(int year, int month, int day); + +/** + * @brief Set date time to RTC + * + * @param[in] year The year + * @param[in] month The month + * @param[in] day The day + * @param[in] hour The hour + * @param[in] minute The minute + * @param[in] second The second + * + * @return result + * - 0 Success + * - Other Fail + */ +int rtc_timer_set(int year, int month, int day, int hour, int minute, int second); + +/** + * @brief Get date time from RTC + * + * @param year The year + * @param month The month + * @param day The day + * @param hour The hour + * @param minute The minute + * @param second The second + * + * @return result + * - 0 Success + * - Other Fail + */ +int rtc_timer_get(int *year, int *month, int *day, int *hour, int *minute, int *second); + +/** + * @brief Set date time to Alarm + * + * @param[in] year The year + * @param[in] month The month + * @param[in] day The day + * @param[in] hour The hour + * @param[in] minute The minute + * @param[in] second The second + * + * @return result + * - 0 Success + * - Other Fail + */ +int rtc_timer_set_alarm(int year, int month, int day, int hour, int minute, int second); + +/** + * @brief Get date time from Alarm + * + * @param year The year + * @param month The month + * @param day The day + * @param hour The hour + * @param minute The minute + * @param second The second + * + * @return result + * - 0 Success + * - Other Fail + */ +int rtc_timer_get_alarm(int *year, int *month, int *day, int *hour, int *minute, int *second); + +/** + * @brief Set rtc tick interrupt + * + * @param enable enable or disale rtc interrupt + * + * @return Result + * - 0 Success + * - Other Fail + */ +int rtc_tick_interrupt_set(int enable); + +/** + * @brief Get tick interrupt + * + * + * @return Result + * - 0 Disable + * - 1 Enable + */ +int rtc_tick_interrupt_get(void); + +/** + * @brief Set tick interrupt mode + * + * @param mode The mode interrumpted + * + * @return Result + * - 0 Success + * - Other Fail + */ +int rtc_tick_interrupt_mode_set(rtc_tick_interrupt_mode_e mode); + +/** + * @brief Get tick interrupt mode + * + * @return Tick interrupt mode + */ +rtc_tick_interrupt_mode_e rtc_tick_interrupt_mode_get(void); + +/** + * @brief Enable alarm interrupt + * + * @param enable Enable or disable alarm interrupt + * + * @return Result + * - 0 Success + * - Other Fail + */ +int rtc_alarm_interrupt_set(int enable); + +/** + * @brief Get alarm interrupt status + * + * @return Alarm interrupt status + */ +int rtc_alarm_interrupt_get(void); + +/** + * @brief Set alarm interrupt mask + * + * @param mask Alarm interrupt mask + * + * @return Result + * - 0 Success + * - Other Fail + */ +int rtc_alarm_interrupt_mask_set(struct rtc_mask_t mask); + +/** + * @brief Get alarm interrupt mask + * + * @return Alarm interrupt mask + */ +struct rtc_mask_t rtc_alarm_interrupt_mask_get(void); + +/** + * @brief Initialize RTC + * + * @return Result + * - 0 Success + * - Other Fail + */ +int rtc_init(void); + +/** + * @brief RTC timer set mode + * + * @param timer_mode timer mode + * + * @return Result + * - 0 Success + * - Other Fail + */ +int rtc_timer_set_mode(rtc_timer_mode_e timer_mode); + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_RTC_H */ diff --git a/lib/drivers/include/sha256.h b/lib/drivers/include/sha256.h new file mode 100644 index 0000000..537b2bf --- /dev/null +++ b/lib/drivers/include/sha256.h @@ -0,0 +1,94 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _SHA256_H +#define _SHA256_H + +#include +#include "env/encoding.h" +#include "platform.h" + +#define DISABLE_SHA_DMA 0 +#define ENABLE_SHA_DMA 1 + +/** + * @brief AES + * + */ +struct sha256_t +{ + uint32_t sha_result[8]; + uint32_t sha_data_in1; + uint32_t sha_data_in2; + uint32_t sha_data_num; /*1 unit represents 64 bytes*/ + uint32_t sha_status; + uint32_t reserved0; + uint32_t sha_input_ctrl; +} __attribute__((packed, aligned(4))); + +#define SHA256_HASH_SIZE 32 + +/* Hash size in 32-bit words */ +#define SHA256_HASH_WORDS 8 + +struct _SHA256Context +{ + uint64_t totalLength; + uint32_t hash[SHA256_HASH_WORDS]; + uint32_t bufferLength; + union + { + uint32_t words[16]; + uint8_t bytes[64]; + } buffer; +#ifdef RUNTIME_ENDIAN + int littleEndian; +#endif /* RUNTIME_ENDIAN */ +}; + +typedef struct _SHA256Context SHA256Context; + +/** + * @brief Sha256 initialize + * + * @param[in] dma_en Dma enable flag + * @param[in] input_size Input size + * @param[in] sc Sha256 Context point + * + * @return Result + * - 0 Success + * - Other Fail + */ +int sha256_init(uint8_t dma_en, uint32_t input_size, SHA256Context *sc); + +/** + * @brief Sha256 update + * + * @param[in] sc Sha256 Context point + * @param[in] data Input data point + * @param[in] len Input data size + * + */ +void sha256_update(SHA256Context *sc, const void *data, uint32_t len); + +/** + * @brief Sha256 final + * + * @param[in] sc Sha256 Context point + * @param[out] hash Sha256 result + * + */ +void sha256_final(SHA256Context *sc, uint8_t hash[SHA256_HASH_SIZE]); + +#endif diff --git a/lib/drivers/include/spi.h b/lib/drivers/include/spi.h new file mode 100644 index 0000000..61f6546 --- /dev/null +++ b/lib/drivers/include/spi.h @@ -0,0 +1,449 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _DRIVER_SPI_H +#define _DRIVER_SPI_H + +#include +#include +#include "dmac.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* clang-format off */ +struct spi_t { + /* SPI Control Register 0 (0x00)*/ + volatile uint32_t ctrlr0; + /* SPI Control Register 1 (0x04)*/ + volatile uint32_t ctrlr1; + /* SPI Enable Register (0x08)*/ + volatile uint32_t ssienr; + /* SPI Microwire Control Register (0x0c)*/ + volatile uint32_t mwcr; + /* SPI Slave Enable Register (0x10)*/ + volatile uint32_t ser; + /* SPI Baud Rate Select (0x14)*/ + volatile uint32_t baudr; + /* SPI Transmit FIFO Threshold Level (0x18)*/ + volatile uint32_t txftlr; + /* SPI Receive FIFO Threshold Level (0x1c)*/ + volatile uint32_t rxftlr; + /* SPI Transmit FIFO Level Register (0x20)*/ + volatile uint32_t txflr; + /* SPI Receive FIFO Level Register (0x24)*/ + volatile uint32_t rxflr; + /* SPI Status Register (0x28)*/ + volatile uint32_t sr; + /* SPI Interrupt Mask Register (0x2c)*/ + volatile uint32_t imr; + /* SPI Interrupt Status Register (0x30)*/ + volatile uint32_t isr; + /* SPI Raw Interrupt Status Register (0x34)*/ + volatile uint32_t risr; + /* SPI Transmit FIFO Overflow Interrupt Clear Register (0x38)*/ + volatile uint32_t txoicr; + /* SPI Receive FIFO Overflow Interrupt Clear Register (0x3c)*/ + volatile uint32_t rxoicr; + /* SPI Receive FIFO Underflow Interrupt Clear Register (0x40)*/ + volatile uint32_t rxuicr; + /* SPI Multi-Master Interrupt Clear Register (0x44)*/ + volatile uint32_t msticr; + /* SPI Interrupt Clear Register (0x48)*/ + volatile uint32_t icr; + /* SPI DMA Control Register (0x4c)*/ + volatile uint32_t dmacr; + /* SPI DMA Transmit Data Level (0x50)*/ + volatile uint32_t dmatdlr; + /* SPI DMA Receive Data Level (0x54)*/ + volatile uint32_t dmardlr; + /* SPI Identification Register (0x58)*/ + volatile uint32_t idr; + /* SPI DWC_ssi component version (0x5c)*/ + volatile uint32_t ssic_version_id; + /* SPI Data Register 0-36 (0x60 -- 0xec)*/ + volatile uint32_t dr[36]; + /* SPI RX Sample Delay Register (0xf0)*/ + volatile uint32_t rx_sample_delay; + /* SPI SPI Control Register (0xf4)*/ + volatile uint32_t spi_ctrlr0; + /* reserved (0xf8)*/ + volatile uint32_t resv; + /* SPI XIP Mode bits (0xfc)*/ + volatile uint32_t xip_mode_bits; + /* SPI XIP INCR transfer opcode (0x100)*/ + volatile uint32_t xip_incr_inst; + /* SPI XIP WRAP transfer opcode (0x104)*/ + volatile uint32_t xip_wrap_inst; + /* SPI XIP Control Register (0x108)*/ + volatile uint32_t xip_ctrl; + /* SPI XIP Slave Enable Register (0x10c)*/ + volatile uint32_t xip_ser; + /* SPI XIP Receive FIFO Overflow Interrupt Clear Register (0x110)*/ + volatile uint32_t xrxoicr; + /* SPI XIP time out register for continuous transfers (0x114)*/ + volatile uint32_t xip_cnt_time_out; + volatile uint32_t endian; +} __attribute__((packed, aligned(4))); +/* clang-format on */ + + +typedef enum +{ + SPI_MODE_0, + SPI_MODE_1, + SPI_MODE_2, + SPI_MODE_3, +} spi_mode; + +typedef enum +{ + SPI_FF_STANDARD, + SPI_FF_DUAL, + SPI_FF_QUAD, + SPI_FF_OCTAL +} spi_frame_format; + +typedef enum +{ + SPI_AITM_STANDARD, + SPI_AITM_ADDR_STANDARD, + SPI_AITM_AS_FRAME_FORMAT +} spi_addr_inst_trans_mode; + +typedef enum +{ + SPI_TMOD_TRANS_RECV, + SPI_TMOD_TRANS, + SPI_TMOD_RECV, + SPI_TMOD_EEROM +}spi_transfer_mode; + + +typedef enum _spi_transfer_width +{ + SPI_TRANS_CHAR = 0x0, + SPI_TRANS_SHORT = 0x1, + SPI_TRANS_INT = 0x2, +}spi_transfer_width; + + +extern volatile struct spi_t *const spi[4]; + + +/** + * @brief Spi initialize + * + * @param[in] spi_bus Spi bus number + * + * @return Result + * - 0 Success + * - Other Fail + */ +int spi_init(uint8_t spi_bus); + +/** + * @brief Spi master mode configuration + * + * @param[in] spi_bus Spi bus number + * @param[in] mode Spi mode + * @param[in] frame_format Spi frame format + * @param[in] data_bit_length Spi data bit length + * + * @return Result + * - 0 Success + * - Other Fail + */ +int spi_master_config(uint8_t spi_bus, spi_mode mode, spi_frame_format frame_format, + size_t data_bit_length); + +/** + * @brief Spi transmit configuration + * + * @param[in] spi_bus Spi bus number + * @param[in] instruction_length Instruction length + * @param[in] address_length Address length + * @param[in] wait_cycles Wait cycles + * @param[in] trans_mode Spi transfer mode + * + */ +void spi_trans_config(uint8_t spi_bus, size_t instruction_length, size_t address_length, + size_t wait_cycles, spi_addr_inst_trans_mode trans_mode); + +/** + * @brief Spi send data + * + * @param[in] spi_bus Spi bus number + * @param[in] chip_sel Spi chip select + * @param[in] cmd_buff Spi command buffer point + * @param[in] cmd_len Spi command length + * @param[in] tx_buff Spi transmit buffer point + * @param[in] tx_len Spi transmit buffer length + * + * @return Result + * - 0 Success + * - Other Fail + */ +int spi_send_data(uint8_t spi_bus, uint32_t chip_sel, uint8_t *cmd_buff, + uint8_t cmd_len, uint8_t *tx_buff, uint32_t tx_len); + + +/** + * @brief Spi receive data + * + * @param[in] spi_bus Spi bus number + * @param[in] chip_sel Spi chip select + * @param[in] cmd_buff Spi command buffer point + * @param[in] cmd_len Spi command length + * @param[in] rx_buff Spi receive buffer point + * @param[in] rx_len Spi receive buffer length + * + * @return Result + * - 0 Success + * - Other Fail + */ +int spi_receive_data(uint8_t spi_bus, uint32_t chip_sel, uint8_t *cmd_buff, + uint8_t cmd_len, uint8_t *rx_buff, uint32_t rx_len); + + +/** + * @brief Spi special receive data + * + * @param[in] spi_bus Spi bus number + * @param[in] chip_sel Spi chip select + * @param[in] cmd_buff Spi command buffer point + * @param[in] cmd_len Spi command length + * @param[in] rx_buff Spi receive buffer point + * @param[in] rx_len Spi receive buffer length + * + * @return Result + * - 0 Success + * - Other Fail + */ +int spi_special_receive_data(uint8_t spi_bus, uint32_t chip_sel, uint32_t *cmd_buff, + uint8_t cmd_len, uint8_t *rx_buff, uint32_t rx_len); + +/** + * @brief Spi special send data + * + * @param[in] spi_bus Spi bus number + * @param[in] chip_sel Spi chip select + * @param[in] cmd_buff Spi command buffer point + * @param[in] cmd_len Spi command length + * @param[in] tx_buff Spi transmit buffer point + * @param[in] tx_len Spi transmit buffer length + * + * @return Result + * - 0 Success + * - Other Fail + */ +int spi_special_send_data(uint8_t spi_bus, uint32_t chip_sel, uint32_t *cmd_buff, + uint8_t cmd_len, uint8_t *tx_buff, uint32_t tx_len); + +/** + * @brief Spi set transfer mode + * + * @param[in] spi_bus Spi bus number + * @param[in] tmod Spi tmod + * + */ +void spi_set_tmod(uint8_t spi_bus, uint32_t tmod); + +/** + * @brief Spi set frame format + * + * @param[in] spi_bus Spi bus number + * @param[in] spi_frf Spi frame format + * + */ +void spi_set_frame_format(uint8_t spi_bus, uint32_t spi_frf); + +/** + * @brief Spi get frame format + * + * @param[in] spi_bus Spi bus number + * + * @return frame foramt + */ +int spi_get_frame_format(uint8_t spi_bus); + +/** + * @brief Spi set work mode + * + * @param[in] spi_bus Spi bus number + * @param[in] mode Spi work mode + * + */ +void spi_set_work_mode(uint8_t spi_bus, spi_mode mode); + +/** + * @brief Spi set frame size + * + * @param[in] spi_bus Spi bus number + * @param[in] dfs Spi frame size + * + */ +void spi_set_frame_size(uint8_t spi_bus, uint32_t dfs); + +/** + * @brief Spi set wait cycles + * + * @param[in] spi_bus Spi bus number + * @param[in] wcycles Spi wait cycles + * + */ +void spi_set_wait_cycles(uint8_t spi_bus, uint32_t wcycles); + +/** + * @brief Spi set instruction length + * + * @param[in] spi_bus Spi bus number + * @param[in] instruction_length Spi instruction length + * + */ +void spi_set_inst_length(uint8_t spi_bus, uint32_t instruction_length); + +/** + * @brief Spi set address length + * + * @param[in] spi_bus Spi bus number + * @param[in] address_length Spi address length + * + */ +void spi_set_address_length(uint8_t spi_bus, uint32_t address_length); + +/** + * @brief Spi set transfer mode + * + * @param[in] spi_bus Spi bus number + * @param[in] trans_mode Spi tansfer mode + * + */ +void spi_set_trans_mode(uint8_t spi_bus, spi_addr_inst_trans_mode trans_mode); + +/** + * @brief Spi send data by dma + * + * @param[in] channel_num Dmac channel number + * @param[in] spi_bus Spi bus number + * @param[in] chip_sel Spi chip select + * @param[in] cmd_buff Spi command buffer point + * @param[in] cmd_len Spi command length + * @param[in] tx_buff Spi transmit buffer point + * @param[in] tx_len Spi transmit buffer length + * + * @return Result + * - 0 Success + * - Other Fail + */ +int spi_send_data_dma(dmac_channel_number channel_num, uint8_t spi_bus, uint32_t chip_sel, + uint8_t *cmd_buff, uint8_t cmd_len, uint8_t *tx_buff, uint32_t tx_len); + + +/** + * @brief Spi receive data by dma + * + * @param[in] w_channel_num Dmac write channel number + * @param[in] r_channel_num Dmac read channel number + * @param[in] spi_bus Spi bus number + * @param[in] chip_sel Spi chip select + * @param[in] cmd_buff Spi command buffer point + * @param[in] cmd_len Spi command length + * @param[in] rx_buff Spi receive buffer point + * @param[in] rx_len Spi receive buffer length + * + * @return Result + * - 0 Success + * - Other Fail + */ +int spi_receive_data_dma(dmac_channel_number w_channel_num, dmac_channel_number r_channel_num, + uint8_t spi_bus, uint32_t chip_sel, uint8_t *cmd_buff, uint8_t cmd_len, uint8_t *rx_buff, uint32_t rx_len); + + +/** + * @brief Spi special send data by dma + * + * @param[in] channel_num Dmac channel number + * @param[in] spi_bus Spi bus number + * @param[in] chip_sel Spi chip select + * @param[in] cmd_buff Spi command buffer point + * @param[in] cmd_len Spi command length + * @param[in] tx_buff Spi transmit buffer point + * @param[in] tx_len Spi transmit buffer length + * + * @return Result + * - 0 Success + * - Other Fail + */ +int spi_special_send_data_dma(dmac_channel_number channel_num,uint8_t spi_bus, uint32_t chip_sel, + uint32_t *cmd_buff, uint8_t cmd_len, uint8_t *tx_buff, uint32_t tx_len); + +/** + * @brief Spi special receive data by dma + * + * @param[in] w_channel_num Dmac write channel number + * @param[in] r_channel_num Dmac read channel number + * @param[in] spi_bus Spi bus number + * @param[in] chip_sel Spi chip select + * @param[in] cmd_buff Spi command buffer point + * @param[in] cmd_len Spi command length + * @param[in] rx_buff Spi receive buffer point + * @param[in] rx_len Spi receive buffer length + * + * @return Result + * - 0 Success + * - Other Fail + */ +int spi_special_receive_data_dma(dmac_channel_number w_channel_num, dmac_channel_number r_channel_num, + uint8_t spi_bus, uint32_t chip_sel, uint32_t *cmd_buff, uint8_t cmd_len, uint8_t *rx_buff, uint32_t rx_len); + +/** + * @brief Spi fill dma + * + * @param[in] channel_num Dmac channel number + * @param[in] spi_bus Spi bus number + * @param[in] chip_sel Spi chip select + * @param[in] cmd_buff Spi command buffer point + * @param[in] cmd_len Spi command length + * + * @return Result + * - 0 Success + * - Other Fail + */ +int spi_fill_dma(dmac_channel_number channel_num,uint8_t spi_bus, uint32_t chip_sel, + uint32_t *cmd_buff, uint32_t cmd_len); + +/** + * @brief Spi normal send by dma + * + * @param[in] channel_num Dmac channel number + * @param[in] spi_bus Spi bus number + * @param[in] chip_sel Spi chip select + * @param[in] tx_buff Spi transmit buffer point + * @param[in] tx_len Spi transmit buffer length + * @param[in] stw Spi transfer width + * + * @return Result + * - 0 Success + * - Other Fail + */ +int spi_normal_send_dma(dmac_channel_number channel_num, uint8_t spi_bus, uint32_t chip_sel, + void *tx_buff, uint32_t tx_len, spi_transfer_width stw); + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_SPI_H */ diff --git a/lib/drivers/include/sysclock.h b/lib/drivers/include/sysclock.h new file mode 100644 index 0000000..b2734a2 --- /dev/null +++ b/lib/drivers/include/sysclock.h @@ -0,0 +1,43 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _SYS_CLOCK_H +#define _SYS_CLOCK_H +#include "stdint.h" + +#define PLL0_OUTPUT_FREQ 320000000UL +#define PLL1_OUTPUT_FREQ 160000000UL +#define PLL2_OUTPUT_FREQ 45158400UL +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Init PLL freqency + */ +void sys_clock_init(); + +/** + * @brief Set frequency of CPU + * @param[in] frequency The desired frequency in Hz + * + * @return The actual frequency of CPU after set + */ +uint32_t system_set_cpu_frequency(uint32_t frequency); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/drivers/include/sysctl.h b/lib/drivers/include/sysctl.h new file mode 100644 index 0000000..d7d93bc --- /dev/null +++ b/lib/drivers/include/sysctl.h @@ -0,0 +1,1016 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _DRIVER_SYSCTL_H +#define _DRIVER_SYSCTL_H + +#include +#include "platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief System controller register + * + * @note System controller register table + * + * | Offset | Name | Description | + * |-----------|----------------|-------------------------------------| + * | 0x00 | git_id | Git short commit id | + * | 0x04 | clk_freq | System clock base frequency | + * | 0x08 | pll0 | PLL0 controller | + * | 0x0c | pll1 | PLL1 controller | + * | 0x10 | pll2 | PLL2 controller | + * | 0x14 | resv5 | Reserved | + * | 0x18 | pll_lock | PLL lock tester | + * | 0x1c | rom_error | AXI ROM detector | + * | 0x20 | clk_sel0 | Clock select controller0 | + * | 0x24 | clk_sel1 | Clock select controller1 | + * | 0x28 | clk_en_cent | Central clock enable | + * | 0x2c | clk_en_peri | Peripheral clock enable | + * | 0x30 | soft_reset | Soft reset ctrl | + * | 0x34 | peri_reset | Peripheral reset controller | + * | 0x38 | clk_th0 | Clock threshold controller 0 | + * | 0x3c | clk_th1 | Clock threshold controller 1 | + * | 0x40 | clk_th2 | Clock threshold controller 2 | + * | 0x44 | clk_th3 | Clock threshold controller 3 | + * | 0x48 | clk_th4 | Clock threshold controller 4 | + * | 0x4c | clk_th5 | Clock threshold controller 5 | + * | 0x50 | clk_th6 | Clock threshold controller 6 | + * | 0x54 | misc | Miscellaneous controller | + * | 0x58 | peri | Peripheral controller | + * | 0x5c | spi_sleep | SPI sleep controller | + * | 0x60 | reset_status | Reset source status | + * | 0x64 | dma_sel0 | DMA handshake selector | + * | 0x68 | dma_sel1 | DMA handshake selector | + * | 0x6c | power_sel | IO Power Mode Select controller | + * | 0x70 | resv28 | Reserved | + * | 0x74 | resv29 | Reserved | + * | 0x78 | resv30 | Reserved | + * | 0x7c | resv31 | Reserved | + * + */ + +enum sysctl_pll_e +{ + SYSCTL_PLL0, + SYSCTL_PLL1, + SYSCTL_PLL2, + SYSCTL_PLL_MAX +}; + +enum sysctl_clock_source_e +{ + SYSCTL_SOURCE_IN0, + SYSCTL_SOURCE_PLL0, + SYSCTL_SOURCE_PLL1, + SYSCTL_SOURCE_PLL2, + SYSCTL_SOURCE_ACLK, + SYSCTL_SOURCE_MAX +}; + +enum sysctl_dma_channel_e +{ + SYSCTL_DMA_CHANNEL_0, + SYSCTL_DMA_CHANNEL_1, + SYSCTL_DMA_CHANNEL_2, + SYSCTL_DMA_CHANNEL_3, + SYSCTL_DMA_CHANNEL_4, + SYSCTL_DMA_CHANNEL_5, + SYSCTL_DMA_CHANNEL_MAX +}; + +enum sysctl_dma_select_e +{ + SYSCTL_DMA_SELECT_SSI0_RX_REQ, + SYSCTL_DMA_SELECT_SSI0_TX_REQ, + SYSCTL_DMA_SELECT_SSI1_RX_REQ, + SYSCTL_DMA_SELECT_SSI1_TX_REQ, + SYSCTL_DMA_SELECT_SSI2_RX_REQ, + SYSCTL_DMA_SELECT_SSI2_TX_REQ, + SYSCTL_DMA_SELECT_SSI3_RX_REQ, + SYSCTL_DMA_SELECT_SSI3_TX_REQ, + SYSCTL_DMA_SELECT_I2C0_RX_REQ, + SYSCTL_DMA_SELECT_I2C0_TX_REQ, + SYSCTL_DMA_SELECT_I2C1_RX_REQ, + SYSCTL_DMA_SELECT_I2C1_TX_REQ, + SYSCTL_DMA_SELECT_I2C2_RX_REQ, + SYSCTL_DMA_SELECT_I2C2_TX_REQ, + SYSCTL_DMA_SELECT_UART1_RX_REQ, + SYSCTL_DMA_SELECT_UART1_TX_REQ, + SYSCTL_DMA_SELECT_UART2_RX_REQ, + SYSCTL_DMA_SELECT_UART2_TX_REQ, + SYSCTL_DMA_SELECT_UART3_RX_REQ, + SYSCTL_DMA_SELECT_UART3_TX_REQ, + SYSCTL_DMA_SELECT_AES_REQ, + SYSCTL_DMA_SELECT_SHA_RX_REQ, + SYSCTL_DMA_SELECT_AI_RX_REQ, + SYSCTL_DMA_SELECT_FFT_RX_REQ, + SYSCTL_DMA_SELECT_FFT_TX_REQ, + SYSCTL_DMA_SELECT_I2S0_TX_REQ, + SYSCTL_DMA_SELECT_I2S0_RX_REQ, + SYSCTL_DMA_SELECT_I2S1_TX_REQ, + SYSCTL_DMA_SELECT_I2S1_RX_REQ, + SYSCTL_DMA_SELECT_I2S2_TX_REQ, + SYSCTL_DMA_SELECT_I2S2_RX_REQ, + SYSCTL_DMA_SELECT_I2S0_BF_DIR_REQ, + SYSCTL_DMA_SELECT_I2S0_BF_VOICE_REQ, + SYSCTL_DMA_SELECT_MAX +}; + +/** + * @brief System controller clock id + */ +enum sysctl_clock_e +{ + SYSCTL_CLOCK_PLL0, + SYSCTL_CLOCK_PLL1, + SYSCTL_CLOCK_PLL2, + SYSCTL_CLOCK_CPU, + SYSCTL_CLOCK_SRAM0, + SYSCTL_CLOCK_SRAM1, + SYSCTL_CLOCK_APB0, + SYSCTL_CLOCK_APB1, + SYSCTL_CLOCK_APB2, + SYSCTL_CLOCK_ROM, + SYSCTL_CLOCK_DMA, + SYSCTL_CLOCK_AI, + SYSCTL_CLOCK_DVP, + SYSCTL_CLOCK_FFT, + SYSCTL_CLOCK_GPIO, + SYSCTL_CLOCK_SPI0, + SYSCTL_CLOCK_SPI1, + SYSCTL_CLOCK_SPI2, + SYSCTL_CLOCK_SPI3, + SYSCTL_CLOCK_I2S0, + SYSCTL_CLOCK_I2S1, + SYSCTL_CLOCK_I2S2, + SYSCTL_CLOCK_I2C0, + SYSCTL_CLOCK_I2C1, + SYSCTL_CLOCK_I2C2, + SYSCTL_CLOCK_UART1, + SYSCTL_CLOCK_UART2, + SYSCTL_CLOCK_UART3, + SYSCTL_CLOCK_AES, + SYSCTL_CLOCK_FPIOA, + SYSCTL_CLOCK_TIMER0, + SYSCTL_CLOCK_TIMER1, + SYSCTL_CLOCK_TIMER2, + SYSCTL_CLOCK_WDT0, + SYSCTL_CLOCK_WDT1, + SYSCTL_CLOCK_SHA, + SYSCTL_CLOCK_OTP, + SYSCTL_CLOCK_RTC, + SYSCTL_CLOCK_ACLK = 40, + SYSCTL_CLOCK_HCLK, + SYSCTL_CLOCK_MAX +}; + +/** + * @brief System controller clock select id + */ +enum sysctl_clock_select_e +{ + SYSCTL_CLOCK_SELECT_PLL0_BYPASS, + SYSCTL_CLOCK_SELECT_PLL1_BYPASS, + SYSCTL_CLOCK_SELECT_PLL3_BYPASS, + SYSCTL_CLOCK_SELECT_PLL2, + SYSCTL_CLOCK_SELECT_ACLK, + SYSCTL_CLOCK_SELECT_SPI3, + SYSCTL_CLOCK_SELECT_TIMER0, + SYSCTL_CLOCK_SELECT_TIMER1, + SYSCTL_CLOCK_SELECT_TIMER2, + SYSCTL_CLOCK_SELECT_SPI3_SAMPLE, + SYSCTL_CLOCK_SELECT_MAX = 11 +}; + +/** + * @brief System controller clock threshold id + */ +enum sysctl_threshold_e +{ + SYSCTL_THRESHOLD_ACLK, + SYSCTL_THRESHOLD_APB0, + SYSCTL_THRESHOLD_APB1, + SYSCTL_THRESHOLD_APB2, + SYSCTL_THRESHOLD_SRAM0, + SYSCTL_THRESHOLD_SRAM1, + SYSCTL_THRESHOLD_AI, + SYSCTL_THRESHOLD_DVP, + SYSCTL_THRESHOLD_ROM, + SYSCTL_THRESHOLD_SPI0, + SYSCTL_THRESHOLD_SPI1, + SYSCTL_THRESHOLD_SPI2, + SYSCTL_THRESHOLD_SPI3, + SYSCTL_THRESHOLD_TIMER0, + SYSCTL_THRESHOLD_TIMER1, + SYSCTL_THRESHOLD_TIMER2, + SYSCTL_THRESHOLD_I2S0, + SYSCTL_THRESHOLD_I2S1, + SYSCTL_THRESHOLD_I2S2, + SYSCTL_THRESHOLD_I2S0_M, + SYSCTL_THRESHOLD_I2S1_M, + SYSCTL_THRESHOLD_I2S2_M, + SYSCTL_THRESHOLD_I2C0, + SYSCTL_THRESHOLD_I2C1, + SYSCTL_THRESHOLD_I2C2, + SYSCTL_THRESHOLD_WDT0, + SYSCTL_THRESHOLD_WDT1, + SYSCTL_THRESHOLD_MAX = 28 +}; + +/** + * @brief System controller reset control id + */ +enum sysctl_reset_e +{ + SYSCTL_RESET_SOC, + SYSCTL_RESET_ROM, + SYSCTL_RESET_DMA, + SYSCTL_RESET_AI, + SYSCTL_RESET_DVP, + SYSCTL_RESET_FFT, + SYSCTL_RESET_GPIO, + SYSCTL_RESET_SPI0, + SYSCTL_RESET_SPI1, + SYSCTL_RESET_SPI2, + SYSCTL_RESET_SPI3, + SYSCTL_RESET_I2S0, + SYSCTL_RESET_I2S1, + SYSCTL_RESET_I2S2, + SYSCTL_RESET_I2C0, + SYSCTL_RESET_I2C1, + SYSCTL_RESET_I2C2, + SYSCTL_RESET_UART1, + SYSCTL_RESET_UART2, + SYSCTL_RESET_UART3, + SYSCTL_RESET_AES, + SYSCTL_RESET_FPIOA, + SYSCTL_RESET_TIMER0, + SYSCTL_RESET_TIMER1, + SYSCTL_RESET_TIMER2, + SYSCTL_RESET_WDT0, + SYSCTL_RESET_WDT1, + SYSCTL_RESET_SHA, + SYSCTL_RESET_RTC, + SYSCTL_RESET_MAX = 31 +}; + +/** + * @brief Git short commit id + * + * No. 0 Register (0x00) + */ +struct sysctl_git_id_t +{ + uint32_t git_id : 32; +} __attribute__((packed, aligned(4))); + +/** + * @brief System clock base frequency + * + * No. 1 Register (0x04) + */ +struct sysctl_clk_freq_t +{ + uint32_t clk_freq : 32; +} __attribute__((packed, aligned(4))); + +/** + * @brief PLL0 controller + * + * No. 2 Register (0x08) + */ +struct sysctl_pll0_t +{ + uint32_t clkr0 : 4; + uint32_t clkf0 : 6; + uint32_t clkod0 : 4; + uint32_t bwadj0 : 6; + uint32_t pll_reset0 : 1; + uint32_t pll_pwrd0 : 1; + uint32_t pll_intfb0 : 1; + uint32_t pll_bypass0 : 1; + uint32_t pll_test0 : 1; + uint32_t pll_out_en0 : 1; + uint32_t pll_test_en : 1; + uint32_t reserved : 5; +} __attribute__((packed, aligned(4))); + +/** + * @brief PLL1 controller + * + * No. 3 Register (0x0c) + */ +struct sysctl_pll1_t +{ + uint32_t clkr1 : 4; + uint32_t clkf1 : 6; + uint32_t clkod1 : 4; + uint32_t bwadj1 : 6; + uint32_t pll_reset1 : 1; + uint32_t pll_pwrd1 : 1; + uint32_t pll_intfb1 : 1; + uint32_t pll_bypass1 : 1; + uint32_t pll_test1 : 1; + uint32_t pll_out_en1 : 1; + uint32_t reserved : 6; +} __attribute__((packed, aligned(4))); + +/** + * @brief PLL2 controller + * + * No. 4 Register (0x10) + */ +struct sysctl_pll2_t +{ + uint32_t clkr2 : 4; + uint32_t clkf2 : 6; + uint32_t clkod2 : 4; + uint32_t bwadj2 : 6; + uint32_t pll_reset2 : 1; + uint32_t pll_pwrd2 : 1; + uint32_t pll_intfb2 : 1; + uint32_t pll_bypass2 : 1; + uint32_t pll_test2 : 1; + uint32_t pll_out_en2 : 1; + uint32_t pll_ckin_sel2 : 2; + uint32_t reserved : 4; +} __attribute__((packed, aligned(4))); + +/** + * @brief PLL lock tester + * + * No. 6 Register (0x18) + */ +struct sysctl_pll_lock_t +{ + uint32_t pll_lock0 : 2; + uint32_t pll_slip_clear0 : 1; + uint32_t test_clk_out0 : 1; + uint32_t reserved0 : 4; + uint32_t pll_lock1 : 2; + uint32_t pll_slip_clear1 : 1; + uint32_t test_clk_out1 : 1; + uint32_t reserved1 : 4; + uint32_t pll_lock2 : 2; + uint32_t pll_slip_clear2 : 1; + uint32_t test_clk_out2 : 1; + uint32_t reserved2 : 12; +} __attribute__((packed, aligned(4))); + +/** + * @brief AXI ROM detector + * + * No. 7 Register (0x1c) + */ +struct sysctl_rom_error_t +{ + uint32_t rom_mul_error : 1; + uint32_t rom_one_error : 1; + uint32_t reserved : 30; +} __attribute__((packed, aligned(4))); + +/** + * @brief Clock select controller0 + * + * No. 8 Register (0x20) + */ +struct sysctl_clk_sel0_t +{ + uint32_t aclk_sel : 1; + uint32_t aclk_divider_sel : 2; + uint32_t apb0_clk_sel : 3; + uint32_t apb1_clk_sel : 3; + uint32_t apb2_clk_sel : 3; + uint32_t spi3_clk_sel : 1; + uint32_t timer0_clk_sel : 1; + uint32_t timer1_clk_sel : 1; + uint32_t timer2_clk_sel : 1; + uint32_t reserved : 16; +} __attribute__((packed, aligned(4))); + +/** + * @brief Clock select controller1 + * + * No. 9 Register (0x24) + */ +struct sysctl_clk_sel1_t +{ + uint32_t spi3_sample_clk_sel : 1; + uint32_t reserved0 : 30; + uint32_t reserved1 : 1; +} __attribute__((packed, aligned(4))); + +/** + * @brief Central clock enable + * + * No. 10 Register (0x28) + */ +struct sysctl_clk_en_cent_t +{ + uint32_t cpu_clk_en : 1; + uint32_t sram0_clk_en : 1; + uint32_t sram1_clk_en : 1; + uint32_t apb0_clk_en : 1; + uint32_t apb1_clk_en : 1; + uint32_t apb2_clk_en : 1; + uint32_t reserved : 26; +} __attribute__((packed, aligned(4))); + +/** + * @brief Peripheral clock enable + * + * No. 11 Register (0x2c) + */ +struct sysctl_clk_en_peri_t +{ + uint32_t rom_clk_en : 1; + uint32_t dma_clk_en : 1; + uint32_t ai_clk_en : 1; + uint32_t dvp_clk_en : 1; + uint32_t fft_clk_en : 1; + uint32_t gpio_clk_en : 1; + uint32_t spi0_clk_en : 1; + uint32_t spi1_clk_en : 1; + uint32_t spi2_clk_en : 1; + uint32_t spi3_clk_en : 1; + uint32_t i2s0_clk_en : 1; + uint32_t i2s1_clk_en : 1; + uint32_t i2s2_clk_en : 1; + uint32_t i2c0_clk_en : 1; + uint32_t i2c1_clk_en : 1; + uint32_t i2c2_clk_en : 1; + uint32_t uart1_clk_en : 1; + uint32_t uart2_clk_en : 1; + uint32_t uart3_clk_en : 1; + uint32_t aes_clk_en : 1; + uint32_t fpioa_clk_en : 1; + uint32_t timer0_clk_en : 1; + uint32_t timer1_clk_en : 1; + uint32_t timer2_clk_en : 1; + uint32_t wdt0_clk_en : 1; + uint32_t wdt1_clk_en : 1; + uint32_t sha_clk_en : 1; + uint32_t otp_clk_en : 1; + uint32_t reserved : 1; + uint32_t rtc_clk_en : 1; + uint32_t reserved0 : 2; +} __attribute__((packed, aligned(4))); + +/** + * @brief Soft reset ctrl + * + * No. 12 Register (0x30) + */ +struct sysctl_soft_reset_t +{ + uint32_t soft_reset : 1; + uint32_t reserved : 31; +} __attribute__((packed, aligned(4))); + +/** + * @brief Peripheral reset controller + * + * No. 13 Register (0x34) + */ +struct sysctl_peri_reset_t +{ + uint32_t rom_reset : 1; + uint32_t dma_reset : 1; + uint32_t ai_reset : 1; + uint32_t dvp_reset : 1; + uint32_t fft_reset : 1; + uint32_t gpio_reset : 1; + uint32_t spi0_reset : 1; + uint32_t spi1_reset : 1; + uint32_t spi2_reset : 1; + uint32_t spi3_reset : 1; + uint32_t i2s0_reset : 1; + uint32_t i2s1_reset : 1; + uint32_t i2s2_reset : 1; + uint32_t i2c0_reset : 1; + uint32_t i2c1_reset : 1; + uint32_t i2c2_reset : 1; + uint32_t uart1_reset : 1; + uint32_t uart2_reset : 1; + uint32_t uart3_reset : 1; + uint32_t aes_reset : 1; + uint32_t fpioa_reset : 1; + uint32_t timer0_reset : 1; + uint32_t timer1_reset : 1; + uint32_t timer2_reset : 1; + uint32_t wdt0_reset : 1; + uint32_t wdt1_reset : 1; + uint32_t sha_reset : 1; + uint32_t reserved : 2; + uint32_t rtc_reset : 1; + uint32_t reserved0 : 2; +} __attribute__((packed, aligned(4))); + +/** + * @brief Clock threshold controller 0 + * + * No. 14 Register (0x38) + */ +struct sysctl_clk_th0_t +{ + uint32_t sram0_gclk_threshold : 4; + uint32_t sram1_gclk_threshold : 4; + uint32_t ai_gclk_threshold : 4; + uint32_t dvp_gclk_threshold : 4; + uint32_t rom_gclk_threshold : 4; + uint32_t reserved : 12; +} __attribute__((packed, aligned(4))); + +/** + * @brief Clock threshold controller 1 + * + * No. 15 Register (0x3c) + */ +struct sysctl_clk_th1_t +{ + uint32_t spi0_clk_threshold : 8; + uint32_t spi1_clk_threshold : 8; + uint32_t spi2_clk_threshold : 8; + uint32_t spi3_clk_threshold : 8; +} __attribute__((packed, aligned(4))); + +/** + * @brief Clock threshold controller 2 + * + * No. 16 Register (0x40) + */ +struct sysctl_clk_th2_t +{ + uint32_t timer0_clk_threshold : 8; + uint32_t timer1_clk_threshold : 8; + uint32_t timer2_clk_threshold : 8; + uint32_t reserved : 8; +} __attribute__((packed, aligned(4))); + +/** + * @brief Clock threshold controller 3 + * + * No. 17 Register (0x44) + */ +struct sysctl_clk_th3_t +{ + uint32_t i2s0_clk_threshold : 16; + uint32_t i2s1_clk_threshold : 16; +} __attribute__((packed, aligned(4))); + +/** + * @brief Clock threshold controller 4 + * + * No. 18 Register (0x48) + */ +struct sysctl_clk_th4_t +{ + uint32_t i2s2_clk_threshold : 16; + uint32_t i2s0_mclk_threshold : 8; + uint32_t i2s1_mclk_threshold : 8; +} __attribute__((packed, aligned(4))); + +/** + * @brief Clock threshold controller 5 + * + * No. 19 Register (0x4c) + */ +struct sysctl_clk_th5_t +{ + uint32_t i2s2_mclk_threshold : 8; + uint32_t i2c0_clk_threshold : 8; + uint32_t i2c1_clk_threshold : 8; + uint32_t i2c2_clk_threshold : 8; +} __attribute__((packed, aligned(4))); + +/** + * @brief Clock threshold controller 6 + * + * No. 20 Register (0x50) + */ +struct sysctl_clk_th6_t +{ + uint32_t wdt0_clk_threshold : 8; + uint32_t wdt1_clk_threshold : 8; + uint32_t reserved0 : 8; + uint32_t reserved1 : 8; +} __attribute__((packed, aligned(4))); + +/** + * @brief Miscellaneous controller + * + * No. 21 Register (0x54) + */ +struct sysctl_misc_t +{ + uint32_t debug_sel : 6; + uint32_t reserved0 : 5; + uint32_t reserved1 : 21; +} __attribute__((packed, aligned(4))); + +/** + * @brief Peripheral controller + * + * No. 22 Register (0x58) + */ +struct sysctl_peri_t +{ + uint32_t timer0_pause : 1; + uint32_t timer1_pause : 1; + uint32_t timer2_pause : 1; + uint32_t timer3_pause : 1; + uint32_t timer4_pause : 1; + uint32_t timer5_pause : 1; + uint32_t timer6_pause : 1; + uint32_t timer7_pause : 1; + uint32_t timer8_pause : 1; + uint32_t timer9_pause : 1; + uint32_t timer10_pause : 1; + uint32_t timer11_pause : 1; + uint32_t spi0_xip_en : 1; + uint32_t spi1_xip_en : 1; + uint32_t spi2_xip_en : 1; + uint32_t spi3_xip_en : 1; + uint32_t spi0_clk_bypass : 1; + uint32_t spi1_clk_bypass : 1; + uint32_t spi2_clk_bypass : 1; + uint32_t i2s0_clk_bypass : 1; + uint32_t i2s1_clk_bypass : 1; + uint32_t i2s2_clk_bypass : 1; + uint32_t jtag_clk_bypass : 1; + uint32_t dvp_clk_bypass : 1; + uint32_t debug_clk_bypass : 1; + uint32_t reserved0 : 1; + uint32_t reserved1 : 6; +} __attribute__((packed, aligned(4))); + +/** + * @brief SPI sleep controller + * + * No. 23 Register (0x5c) + */ +struct sysctl_spi_sleep_t +{ + uint32_t ssi0_sleep : 1; + uint32_t ssi1_sleep : 1; + uint32_t ssi2_sleep : 1; + uint32_t ssi3_sleep : 1; + uint32_t reserved : 28; +} __attribute__((packed, aligned(4))); + +/** + * @brief Reset source status + * + * No. 24 Register (0x60) + */ +struct sysctl_reset_status_t +{ + uint32_t reset_sts_clr : 1; + uint32_t pin_reset_sts : 1; + uint32_t wdt0_reset_sts : 1; + uint32_t wdt1_reset_sts : 1; + uint32_t soft_reset_sts : 1; + uint32_t reserved : 27; +} __attribute__((packed, aligned(4))); + +/** + * @brief DMA handshake selector + * + * No. 25 Register (0x64) + */ +struct sysctl_dma_sel0_t +{ + uint32_t dma_sel0 : 6; + uint32_t dma_sel1 : 6; + uint32_t dma_sel2 : 6; + uint32_t dma_sel3 : 6; + uint32_t dma_sel4 : 6; + uint32_t reserved : 2; +} __attribute__((packed, aligned(4))); + +/** + * @brief DMA handshake selector + * + * No. 26 Register (0x68) + */ +struct sysctl_dma_sel1_t +{ + uint32_t dma_sel5 : 6; + uint32_t reserved : 26; +} __attribute__((packed, aligned(4))); + +/** + * @brief IO Power Mode Select controller + * + * No. 27 Register (0x6c) + */ +struct sysctl_power_sel_t +{ + uint32_t power_mode_sel0 : 1; + uint32_t power_mode_sel1 : 1; + uint32_t power_mode_sel2 : 1; + uint32_t power_mode_sel3 : 1; + uint32_t power_mode_sel4 : 1; + uint32_t power_mode_sel5 : 1; + uint32_t power_mode_sel6 : 1; + uint32_t power_mode_sel7 : 1; + uint32_t reserved : 24; +} __attribute__((packed, aligned(4))); + + +/** + * @brief System controller object + * + * The System controller is a peripheral device mapped in the + * internal memory map, discoverable in the Configuration String. + * It is responsible for low-level configuration of all system + * related peripheral device. It contain PLL controller, clock + * controller, reset controller, DMA handshake controller, SPI + * controller, timer controller, WDT controller and sleep + * controller. + */ +struct sysctl_t +{ + /* No. 0 (0x00): Git short commit id */ + struct sysctl_git_id_t git_id; + /* No. 1 (0x04): System clock base frequency */ + struct sysctl_clk_freq_t clk_freq; + /* No. 2 (0x08): PLL0 controller */ + struct sysctl_pll0_t pll0; + /* No. 3 (0x0c): PLL1 controller */ + struct sysctl_pll1_t pll1; + /* No. 4 (0x10): PLL2 controller */ + struct sysctl_pll2_t pll2; + /* No. 5 (0x14): Reserved */ + uint32_t resv5; + /* No. 6 (0x18): PLL lock tester */ + struct sysctl_pll_lock_t pll_lock; + /* No. 7 (0x1c): AXI ROM detector */ + struct sysctl_rom_error_t rom_error; + /* No. 8 (0x20): Clock select controller0 */ + struct sysctl_clk_sel0_t clk_sel0; + /* No. 9 (0x24): Clock select controller1 */ + struct sysctl_clk_sel1_t clk_sel1; + /* No. 10 (0x28): Central clock enable */ + struct sysctl_clk_en_cent_t clk_en_cent; + /* No. 11 (0x2c): Peripheral clock enable */ + struct sysctl_clk_en_peri_t clk_en_peri; + /* No. 12 (0x30): Soft reset ctrl */ + struct sysctl_soft_reset_t soft_reset; + /* No. 13 (0x34): Peripheral reset controller */ + struct sysctl_peri_reset_t peri_reset; + /* No. 14 (0x38): Clock threshold controller 0 */ + struct sysctl_clk_th0_t clk_th0; + /* No. 15 (0x3c): Clock threshold controller 1 */ + struct sysctl_clk_th1_t clk_th1; + /* No. 16 (0x40): Clock threshold controller 2 */ + struct sysctl_clk_th2_t clk_th2; + /* No. 17 (0x44): Clock threshold controller 3 */ + struct sysctl_clk_th3_t clk_th3; + /* No. 18 (0x48): Clock threshold controller 4 */ + struct sysctl_clk_th4_t clk_th4; + /* No. 19 (0x4c): Clock threshold controller 5 */ + struct sysctl_clk_th5_t clk_th5; + /* No. 20 (0x50): Clock threshold controller 6 */ + struct sysctl_clk_th6_t clk_th6; + /* No. 21 (0x54): Miscellaneous controller */ + struct sysctl_misc_t misc; + /* No. 22 (0x58): Peripheral controller */ + struct sysctl_peri_t peri; + /* No. 23 (0x5c): SPI sleep controller */ + struct sysctl_spi_sleep_t spi_sleep; + /* No. 24 (0x60): Reset source status */ + struct sysctl_reset_status_t reset_status; + /* No. 25 (0x64): DMA handshake selector */ + struct sysctl_dma_sel0_t dma_sel0; + /* No. 26 (0x68): DMA handshake selector */ + struct sysctl_dma_sel1_t dma_sel1; + /* No. 27 (0x6c): IO Power Mode Select controller */ + struct sysctl_power_sel_t power_sel; + /* No. 28 (0x70): Reserved */ + uint32_t resv28; + /* No. 29 (0x74): Reserved */ + uint32_t resv29; + /* No. 30 (0x78): Reserved */ + uint32_t resv30; + /* No. 31 (0x7c): Reserved */ + uint32_t resv31; +} __attribute__((packed, aligned(4))); + +/** + * @brief System controller object instanse + */ +extern volatile struct sysctl_t *const sysctl; + +/** + * @brief Enable clock for peripheral + * + * @param[in] clock The clock to be enable + * + * @return result + * - 0 Success + * - Other Fail + */ +int sysctl_clock_enable(enum sysctl_clock_e clock); + +/** + * @brief Enable clock for peripheral + * + * @param[in] clock The clock to be disable + * + * @return result + * - 0 Success + * - Other Fail + */ +int sysctl_clock_disable(enum sysctl_clock_e clock); + +/** + * @brief Sysctl clock set threshold + * + * @param[in] which Which threshold to set + * @param[in] threshold The threshold value + * + * @return result + * - 0 Success + * - Other Fail + */ +int sysctl_clock_set_threshold(enum sysctl_threshold_e which, int threshold); + +/** + * @brief Sysctl clock get threshold + * + * @param[in] which Which threshold to get + * + * @return The threshold value + * - Other Value of threshold + * - -1 Fail + */ +int sysctl_clock_get_threshold(enum sysctl_threshold_e which); + +/** + * @brief Sysctl clock set clock select + * + * @param[in] which Which clock select to set + * @param[in] select The clock select value + * + * @return result + * - 0 Success + * - Other Fail + */ +int sysctl_clock_set_clock_select(enum sysctl_clock_select_e which, int select); + +/** + * @brief Sysctl clock get clock select + * + * @param[in] which Which clock select to get + * + * @return The clock select value + * - Other Value of clock select + * - -1 Fail + */ +int sysctl_clock_get_clock_select(enum sysctl_clock_select_e which); + +/** + * @brief Get clock source frequency + * + * @param[in] input The input clock source + * + * @return The frequency of clock source + */ +uint32_t sysctl_clock_source_get_freq(enum sysctl_clock_source_e input); + +/** + * @brief Get PLL frequency + * + * @param[in] pll The PLL id + * + * @return The frequency of PLL + */ +uint32_t sysctl_pll_get_freq(enum sysctl_pll_e pll); + +/** + * @brief Set PLL frequency and input clock + * + * @param[in] pll The PLL id + * @param[in] sel The selected PLL input clock + * @param[in] freq The frequency + * + * @return The frequency of PLL + */ +uint32_t sysctl_pll_set_freq(enum sysctl_pll_e pll, enum sysctl_clock_source_e source, uint32_t freq); + +/** + * @brief Get base clock frequency by clock id + * + * @param[in] clock The clock id + * + * @return The clock frequency + */ +uint32_t sysctl_clock_get_freq(enum sysctl_clock_e clock); + +/** + * @brief Reset device by reset controller + * + * @param[in] reset The reset signal + */ +void sysctl_reset(enum sysctl_reset_e reset); + +/** + * @brief Get git commit id + * + * @return The 4 bytes git commit id + */ +uint32_t sysctl_get_git_id(void); + +/** + * @brief Get base clock frequency, default is 26MHz + * + * @return The base clock frequency + */ +uint32_t sysctl_get_freq(void); + +/** + * @brief Get pll lock status + * + * @param[in] pll The pll id + * + * @return The lock status + * - 1 Pll is lock + * - 0 Pll have lost lock + */ +int sysctl_pll_is_lock(enum sysctl_pll_e pll); + +/** + * @brief Clear pll lock status + * + * @param[in] pll The pll id + * + * @return Result + * - 0 Success + * - Other Fail + */ +int sysctl_pll_clear_slip(enum sysctl_pll_e pll); + +/** + * @brief Enable the PLL and power on with reset + * + * @param[in] pll The pll id + * + * @return Result + * - 0 Success + * - Other Fail + */ +int sysctl_pll_enable(enum sysctl_pll_e pll); + +/** + * @brief Disable the PLL and power off + * + * @param[in] pll The pll id + * + * @return Result + * - 0 Success + * - Other Fail + */ +int sysctl_pll_disable(enum sysctl_pll_e pll); + +/** + * @brief Select DMA channel handshake peripheral signal + * + * @param[in] channel The DMA channel + * @param[in] select The peripheral select + * + * @return Result + * - 0 Success + * - Other Fail + */ +int sysctl_dma_select(enum sysctl_dma_channel_e channel, enum sysctl_dma_select_e select); + +/** + * @brief Fast set all PLL and CPU clock + * + * @return Result + * - 0 Success + * - Other Fail + */ +uint32_t sysctl_pll_fast_enable_pll(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_SYSCTL_H */ diff --git a/lib/drivers/include/timer.h b/lib/drivers/include/timer.h new file mode 100644 index 0000000..26f5b47 --- /dev/null +++ b/lib/drivers/include/timer.h @@ -0,0 +1,290 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _DRIVER_TIMER_H +#define _DRIVER_TIMER_H + +#include +#include +#ifdef __cplusplus +extern "C" { +#endif + +/* clang-format off */ +struct timer_channel_t +{ + /* TIMER_N Load Count Register (0x00+(N-1)*0x14) */ + volatile uint32_t load_count; + /* TIMER_N Current Value Register (0x04+(N-1)*0x14) */ + volatile uint32_t current_value; + /* TIMER_N Control Register (0x08+(N-1)*0x14) */ + volatile uint32_t control; + /* TIMER_N Interrupt Clear Register (0x0c+(N-1)*0x14) */ + volatile uint32_t eoi; + /* TIMER_N Interrupt Status Register (0x10+(N-1)*0x14) */ + volatile uint32_t intr_stat; +} __attribute__((packed, aligned(4))); + +struct timer_t +{ + /* TIMER_N Register (0x00-0x4c) */ + volatile struct timer_channel_t channel[4]; + /* reserverd (0x50-0x9c) */ + volatile uint32_t resv1[20]; + /* TIMER Interrupt Status Register (0xa0) */ + volatile uint32_t intr_stat; + /* TIMER Interrupt Clear Register (0xa4) */ + volatile uint32_t eoi; + /* TIMER Raw Interrupt Status Register (0xa8) */ + volatile uint32_t raw_intr_stat; + /* TIMER Component Version Register (0xac) */ + volatile uint32_t comp_version; + /* TIMER_N Load Count2 Register (0xb0-0xbc) */ + volatile uint32_t load_count2[4]; +} __attribute__((packed, aligned(4))); + +/* TIMER Control Register */ +#define TIMER_CR_ENABLE 0x00000001 +#define TIMER_CR_MODE_MASK 0x00000002 +#define TIMER_CR_FREE_MODE 0x00000000 +#define TIMER_CR_USER_MODE 0x00000002 +#define TIMER_CR_INTERRUPT_MASK 0x00000004 +#define TIMER_CR_PWM_ENABLE 0x00000008 +/* clang-format on */ + +extern volatile struct timer_t *const timer[3]; + +/** + * @brief Set timer clock frequency + * + * @param[in] timer timer + * @param[in] div clock divide value + */ +void timer_set_clock_div(uint32_t timer, uint32_t div); + +/** + * @brief Enable timer channel + * + * @param[in] timer timer + * @param[in] channel channel + */ +void timer_enable(uint32_t timer, uint32_t channel); + +/** + * @brief Disable timer channel + * + * @param[in] timer timer + * @param[in] channel channel + */ +void timer_disable(uint32_t timer, uint32_t channel); + +/** + * @brief Enable timer channel PWM + * + * @param[in] timer timer + * @param[in] channel channel + */ +void timer_enable_pwm(uint32_t timer, uint32_t channel); + +/** + * @brief Disable timer channel PWM + * + * @param[in] timer timer + * @param[in] channel channel + */ +void timer_disable_pwm(uint32_t timer, uint32_t channel); + +/** + * @brief Enable timer channel interrupt + * + * @param[in] timer timer + * @param[in] channel channel + */ +void timer_enable_interrupt(uint32_t timer, uint32_t channel); + +/** + * @brief Disable timer channel interrupt + * + * @param[in] timer timer + * @param[in] channel channel + */ +void timer_disable_interrupt(uint32_t timer, uint32_t channel); + +/** + * @brief Set timer channel mode + * + * @param[in] timer timer + * @param[in] channel channel + * @param[in] mode mode + */ +void timer_set_mode(uint32_t timer, uint32_t channel, uint32_t mode); + +/** + * @brief Set timer channel reload value + * + * @param[in] timer timer + * @param[in] channel channel + * @param[in] count count + */ +void timer_set_reload(uint32_t timer, uint32_t channel, uint32_t count); + +/** + * @brief Set timer channel reload value2 + * + * @param[in] timer timer + * @param[in] channel channel + * @param[in] count count + */ +void timer_set_reload2(uint32_t timer, uint32_t channel, uint32_t count); + +/** + * @brief Get timer channel count + * + * @param[in] timer timer + * @param[in] channel channel + * + * @return current value + */ +uint32_t timer_get_count(uint32_t timer, uint32_t channel); + +/** + * @brief Get timer channel reload value + * + * @param[in] timer timer + * @param[in] channel channel + * + * @return reload value + */ +uint32_t timer_get_reload(uint32_t timer, uint32_t channel); + +/** + * @brief Get timer channel reload value2 + * + * @param[in] timer timer + * @param[in] channel channel + * + * @return reload value2 + */ +uint32_t timer_get_reload2(uint32_t timer, uint32_t channel); + +/** + * @brief Get timer interrupt status + * + * @param[in] timer timer + * + * @return interrupt status + */ +uint32_t timer_get_interrupt_status(uint32_t timer); + +/** + * @brief Get timer raw interrupt status + * + * @param[in] timer timer + * + * @return raw interrupt status + */ +uint32_t timer_get_raw_interrupt_status(uint32_t timer); + +/** + * @brief Get timer interrupt status + * + * @param[in] timer timer + * @param[in] channel channel + * + * @return interrupt status + */ +uint32_t timer_channel_get_interrupt_status(uint32_t timer, uint32_t channel); + +/** + * @brief Clear interrupt + * + * @param[in] timer timer + */ +void timer_clear_interrupt(uint32_t timer); + +/** + * @brief Clear interrupt + * + * @param[in] timer timer + * @param[in] channel channel + */ +void timer_channel_clear_interrupt(uint32_t timer, uint32_t channel); + + +/** + * @brief Set timer timeout + * + * @param[in] timer timer + * @param[in] channel channel + * @param[in] nanoseconds timeout + * + * @return the real timeout + */ +size_t timer_set_interval(uint32_t timer, uint32_t channel, size_t nanoseconds); + +/** + * @brief Init timer + * + * @param[in] timer timer + */ +void timer_init(uint32_t timer); + +/** + * @brief Set timer timeout function + * + * @param[in] timer timer + * @param[in] channel channel + * @param[in] func timeout function + * @param[in] priority interrupt priority + * + */ +void timer_set_irq(uint32_t timer, uint32_t channel, void(*func)(), uint32_t priority); + +/** + * @brief Enable timer + * + * @param[in] timer timer + * @param[in] channel channel + * @param[in] enable Enable or disable + * + */ +void timer_set_enable(uint32_t timer, uint32_t channel, uint32_t enable); + +/** + * @brief Enable timer + * + * @param[in] timer timer + * @param[in] channel channel + * @param[in] enable Enable or disable + * + */ +void pwm_set_enable(uint32_t timer, uint32_t channel, int enable); + +/** + * @brief Set pwm duty + * + * @param[in] timer timer + * @param[in] channel channel + * @param[in] frequency pwm frequency + * @param[in] duty duty + * + */ +double pwm_set_frequency(uint32_t timer, uint32_t channel, double frequency, double duty); + + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_TIMER_H */ diff --git a/lib/drivers/include/uart.h b/lib/drivers/include/uart.h new file mode 100644 index 0000000..5ed37be --- /dev/null +++ b/lib/drivers/include/uart.h @@ -0,0 +1,209 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * @brief Universal Asynchronous Receiver/Transmitter (UART) + * + * The UART peripheral supports the following features: + * + * - 8-N-1 and 8-N-2 formats: 8 data bits, no parity bit, 1 start + * bit, 1 or 2 stop bits + * + * - 8-entry transmit and receive FIFO buffers with programmable + * watermark interrupts + * + * - 16× Rx oversampling with 2/3 majority voting per bit + * + * The UART peripheral does not support hardware flow control or + * other modem control signals, or synchronous serial data + * tranfesrs. + * + * + */ + +#ifndef _DRIVER_APBUART_H +#define _DRIVER_APBUART_H + +#include +#include "platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum +{ + UART_DEV1 = 0, + UART_DEV2, + UART_DEV3, +} uart_dev_t; + +typedef struct +{ + union + { + volatile uint32_t RBR; + volatile uint32_t DLL; + volatile uint32_t THR; + }; + + union + { + volatile uint32_t DLH; + volatile uint32_t IER; + }; + + union + { + volatile uint32_t FCR; + volatile uint32_t IIR; + }; + + volatile uint32_t LCR; + volatile uint32_t MCR; + volatile uint32_t LSR; + volatile uint32_t MSR; + volatile uint32_t SCR; + volatile uint32_t LPDLL; + volatile uint32_t LPDLH; + volatile uint32_t reserve[18]; + volatile uint32_t FAR; + volatile uint32_t TFR; + volatile uint32_t RFW; + volatile uint32_t USR; + volatile uint32_t TFL; + volatile uint32_t RFL; + volatile uint32_t SRR; + volatile uint32_t SRTS; + volatile uint32_t SBCR; + volatile uint32_t SDMAM; + volatile uint32_t SFE; + volatile uint32_t SRT; + volatile uint32_t STET; + volatile uint32_t HTX; + volatile uint32_t DMASA; + volatile uint32_t TCR; + volatile uint32_t DE_EN; + volatile uint32_t RE_EN; + volatile uint32_t DET; + volatile uint32_t TAT; + volatile uint32_t DLF; + volatile uint32_t RAR; + volatile uint32_t TAR; + volatile uint32_t LCR_EXT; + volatile uint32_t R[5]; + volatile uint32_t CPR; + volatile uint32_t UCV; + volatile uint32_t CTR; +} uart_t; + +typedef enum +{ + UART_BITWIDTH_5BIT = 0, + UART_BITWIDTH_6BIT, + UART_BITWIDTH_7BIT, + UART_BITWIDTH_8BIT, +} uart_bitwidth_t; + +typedef enum +{ + UART_STOPBIT_1 = 0, + UART_STOPBIT_1P5OR2, +} uart_stopbit_t; + +typedef enum +{ + UART_PORITY_DISABLE = 0, + UART_PORITY_ODD = 1, + UART_PORITY_EVEN = 3 +} uart_pority_t; + +typedef struct +{ + uint32_t baudrate; + uart_bitwidth_t bitwidth; + uart_stopbit_t stopbit; + uart_pority_t pority; + uint32_t is_hw_flow_en; +} uart_info_t; + +typedef enum +{ + DISABLE = 0, + ENABLE, +} uart_rede_sel; + +typedef enum +{ + UART_STOP_1, + UART_STOP_1_5, + UART_STOP_2 +} uart_stopbit; + +typedef enum +{ + UART_PARITY_None, + UART_PARITY_Odd, + UART_PARITY_Even +} uart_parity; + +/** + * @brief Send data from uart + * + * @param[in] channel Uart index + * @param[in] buffer The data be transfer + * @param[in] len The data length + * + * @return Transfer length + */ +int uart_write(uint8_t channel, const char* buffer, size_t len); + +/** + * @brief Read data from uart + * + * @param[in] channel Uart index + * @param[in] buffer The Data received + * @param[in] len Receive length + * + * @return Receive length + */ +int uart_read(uint8_t channel, char* buffer, size_t len); + +/** + * @brief Init uart + * + * @param[in] channel Uart index + * + */ +void uartapb_init(uint8_t channel); + +/** + * @brief Set uart param + * + * @param[in] channel Uart index + * @param[in] baud_rate Baudrate + * @param[in] data_width Data width + * @param[in] stopbit Stop bit + * @param[in] parity Odd Even parity + * + */ +void uart_config(uint8_t channel, size_t baud_rate, size_t data_width, uart_stopbit stopbit, uart_parity parity); + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_APBUART_H */ diff --git a/lib/drivers/include/uarths.h b/lib/drivers/include/uarths.h new file mode 100644 index 0000000..9ab4236 --- /dev/null +++ b/lib/drivers/include/uarths.h @@ -0,0 +1,223 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * @brief Universal Asynchronous Receiver/Transmitter (UART) + * + * The UART peripheral supports the following features: + * + * - 8-N-1 and 8-N-2 formats: 8 data bits, no parity bit, 1 start + * bit, 1 or 2 stop bits + * + * - 8-entry transmit and receive FIFO buffers with programmable + * watermark interrupts + * + * - 16× Rx oversampling with 2/3 majority voting per bit + * + * The UART peripheral does not support hardware flow control or + * other modem control signals, or synchronous serial data + * tranfesrs. + * + * @note UART RAM Layout + * + * | Address | Name | Description | + * |-----------|----------|---------------------------------| + * | 0x000 | txdata | Transmit data register | + * | 0x004 | rxdata | Receive data register | + * | 0x008 | txctrl | Transmit control register | + * | 0x00C | rxctrl | Receive control register | + * | 0x010 | ie | UART interrupt enable | + * | 0x014 | ip | UART Interrupt pending | + * | 0x018 | div | Baud rate divisor | + * + */ + +#ifndef _DRIVER_UARTHS_H +#define _DRIVER_UARTHS_H + +#include +#include "platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* clang-format off */ +/* Register address offsets */ +#define UARTHS_REG_TXFIFO (0x00) +#define UARTHS_REG_RXFIFO (0x04) +#define UARTHS_REG_TXCTRL (0x08) +#define UARTHS_REG_RXCTRL (0x0c) +#define UARTHS_REG_IE (0x10) +#define UARTHS_REG_IP (0x14) +#define UARTHS_REG_DIV (0x18) + +/* TXCTRL register */ +#define UARTHS_TXEN (0x01) +#define UARTHS_TXWM(x) (((x) & 0xffff) << 16) + +/* RXCTRL register */ +#define UARTHS_RXEN (0x01) +#define UARTHS_RXWM(x) (((x) & 0xffff) << 16) + +/* IP register */ +#define UARTHS_IP_TXWM (0x01) +#define UARTHS_IP_RXWM (0x02) +/* clang-format on */ + +struct uarths_txdata_t +{ + /* Bits [7:0] is data */ + uint32_t data : 8; + /* Bits [30:8] is 0 */ + uint32_t zero : 23; + /* Bit 31 is full status */ + uint32_t full : 1; +} __attribute__((packed, aligned(4))); + +struct uarths_rxdata_t +{ + /* Bits [7:0] is data */ + uint32_t data : 8; + /* Bits [30:8] is 0 */ + uint32_t zero : 23; + /* Bit 31 is empty status */ + uint32_t empty : 1; +} __attribute__((packed, aligned(4))); + +struct uarths_txctrl_t +{ + /* Bit 0 is txen, controls whether the Tx channel is active. */ + uint32_t txen : 1; + /* Bit 1 is nstop, 0 for one stop bit and 1 for two stop bits */ + uint32_t nstop : 1; + /* Bits [15:2] is reserved */ + uint32_t resv0 : 14; + /* Bits [18:16] is threshold of interrupt triggers */ + uint32_t txcnt : 3; + /* Bits [31:19] is reserved */ + uint32_t resv1 : 13; +} __attribute__((packed, aligned(4))); + +struct uarths_rxctrl_t +{ + /* Bit 0 is txen, controls whether the Tx channel is active. */ + uint32_t rxen : 1; + /* Bits [15:1] is reserved */ + uint32_t resv0 : 15; + /* Bits [18:16] is threshold of interrupt triggers */ + uint32_t rxcnt : 3; + /* Bits [31:19] is reserved */ + uint32_t resv1 : 13; +} __attribute__((packed, aligned(4))); + +struct uarths_ip_t +{ + /* Bit 0 is txwm, raised less than txcnt */ + uint32_t txwm : 1; + /* Bit 1 is txwm, raised greater than rxcnt */ + uint32_t rxwm : 1; + /* Bits [31:2] is 0 */ + uint32_t zero : 30; +} __attribute__((packed, aligned(4))); + +struct uarths_ie_t +{ + /* Bit 0 is txwm, raised less than txcnt */ + uint32_t txwm : 1; + /* Bit 1 is txwm, raised greater than rxcnt */ + uint32_t rxwm : 1; + /* Bits [31:2] is 0 */ + uint32_t zero : 30; +} __attribute__((packed, aligned(4))); + +struct uarths_div_t +{ + /* Bits [31:2] is baud rate divisor register */ + uint32_t div : 16; + /* Bits [31:16] is 0 */ + uint32_t zero : 16; +} __attribute__((packed, aligned(4))); + +struct uarths_t +{ + /* Address offset 0x00 */ + struct uarths_txdata_t txdata; + /* Address offset 0x04 */ + struct uarths_rxdata_t rxdata; + /* Address offset 0x08 */ + struct uarths_txctrl_t txctrl; + /* Address offset 0x0c */ + struct uarths_rxctrl_t rxctrl; + /* Address offset 0x10 */ + struct uarths_ie_t ie; + /* Address offset 0x14 */ + struct uarths_ip_t ip; + /* Address offset 0x18 */ + struct uarths_div_t div; +} __attribute__((packed, aligned(4))); + +extern volatile struct uarths_t *const uarths; + +/** + * @brief Initialization Core UART + * + * @return result + * - 0 Success + * - Other Fail + */ +int uart_init(); + +/** + * @brief Put a char to UART + * + * @param[in] c The char to put + * + * @note If c is '\n', a '\r' will be appended automatically + * + * @return result + * - 0 Success + * - Other Fail + */ +int uart_putchar(char c); + +/** + * @brief Send a string to UART + * + * @param[in] s The string to send + * + * @note The string must ending with '\0' + * + * @return result + * - 0 Success + * - Other Fail + */ +int uart_puts(const char *s); + + +/** + * @brief Get a byte from UART + * + * @return byte as int type from UART + */ +int uart_getc(void); + + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_UARTHS_H */ diff --git a/lib/drivers/include/wdt.h b/lib/drivers/include/wdt.h new file mode 100644 index 0000000..647d622 --- /dev/null +++ b/lib/drivers/include/wdt.h @@ -0,0 +1,189 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _DRIVER_WDT_H +#define _DRIVER_WDT_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* clang-format off */ +struct wdt_t +{ + /* WDT Control Register (0x00) */ + volatile uint32_t cr; + /* WDT Timeout Range Register (0x04) */ + volatile uint32_t torr; + /* WDT Current Counter Value Register (0x08) */ + volatile uint32_t ccvr; + /* WDT Counter Restart Register (0x0c) */ + volatile uint32_t crr; + /* WDT Interrupt Status Register (0x10) */ + volatile uint32_t stat; + /* WDT Interrupt Clear Register (0x14) */ + volatile uint32_t eoi; + /* reserverd (0x18) */ + volatile uint32_t resv1; + /* WDT Protection level Register (0x1c) */ + volatile uint32_t prot_level; + /* reserved (0x20-0xe0) */ + volatile uint32_t resv4[49]; + /* WDT Component Parameters Register 5 (0xe4) */ + volatile uint32_t comp_param_5; + /* WDT Component Parameters Register 4 (0xe8) */ + volatile uint32_t comp_param_4; + /* WDT Component Parameters Register 3 (0xec) */ + volatile uint32_t comp_param_3; + /* WDT Component Parameters Register 2 (0xf0) */ + volatile uint32_t comp_param_2; + /* WDT Component Parameters Register 1 (0xf4) */ + volatile uint32_t comp_param_1; + /* WDT Component Version Register (0xf8) */ + volatile uint32_t comp_version; + /* WDT Component Type Register (0xfc) */ + volatile uint32_t comp_type; +} __attribute__((packed, aligned(4))); + + +#define WDT_RESET_ALL 0x00000000U +#define WDT_RESET_CPU 0x00000001U + +/* WDT Control Register */ +#define WDT_CR_ENABLE 0x00000001U +#define WDT_CR_RMOD_MASK 0x00000002U +#define WDT_CR_RMOD_RESET 0x00000000U +#define WDT_CR_RMOD_INTERRUPT 0x00000002U +#define WDT_CR_RPL_MASK 0x0000001CU +#define WDT_CR_RPL(x) ((x) << 2) +/* WDT Timeout Range Register */ +#define WDT_TORR_TOP_MASK 0x000000FFU +#define WDT_TORR_TOP(x) ((x) << 4 | (x) << 0) +/* WDT Current Counter Value Register */ +#define WDT_CCVR_MASK 0xFFFFFFFFU +/* WDT Counter Restart Register */ +#define WDT_CRR_MASK 0x00000076U +/* WDT Interrupt Status Register */ +#define WDT_STAT_MASK 0x00000001U +/* WDT Interrupt Clear Register */ +#define WDT_EOI_MASK 0x00000001U +/* WDT Protection level Register */ +#define WDT_PROT_LEVEL_MASK 0x00000007U +/* WDT Component Parameter Register 5 */ +#define WDT_COMP_PARAM_5_CP_WDT_USER_TOP_MAX_MASK 0xFFFFFFFFU +/* WDT Component Parameter Register 4 */ +#define WDT_COMP_PARAM_4_CP_WDT_USER_TOP_INIT_MAX_MASK 0xFFFFFFFFU +/* WDT Component Parameter Register 3 */ +#define WDT_COMP_PARAM_3_CD_WDT_TOP_RST_MASK 0xFFFFFFFFU +/* WDT Component Parameter Register 2 */ +#define WDT_COMP_PARAM_3_CP_WDT_CNT_RST_MASK 0xFFFFFFFFU +/* WDT Component Parameter Register 1 */ +#define WDT_COMP_PARAM_1_WDT_ALWAYS_EN_MASK 0x00000001U +#define WDT_COMP_PARAM_1_WDT_DFLT_RMOD_MASK 0x00000002U +#define WDT_COMP_PARAM_1_WDT_DUAL_TOP_MASK 0x00000004U +#define WDT_COMP_PARAM_1_WDT_HC_RMOD_MASK 0x00000008U +#define WDT_COMP_PARAM_1_WDT_HC_RPL_MASK 0x00000010U +#define WDT_COMP_PARAM_1_WDT_HC_TOP_MASK 0x00000020U +#define WDT_COMP_PARAM_1_WDT_USE_FIX_TOP_MASK 0x00000040U +#define WDT_COMP_PARAM_1_WDT_PAUSE_MASK 0x00000080U +#define WDT_COMP_PARAM_1_APB_DATA_WIDTH_MASK 0x00000300U +#define WDT_COMP_PARAM_1_WDT_DFLT_RPL_MASK 0x00001C00U +#define WDT_COMP_PARAM_1_WDT_DFLT_TOP_MASK 0x000F0000U +#define WDT_COMP_PARAM_1_WDT_DFLT_TOP_INIT_MASK 0x00F00000U +#define WDT_COMP_PARAM_1_WDT_CNT_WIDTH_MASK 0x1F000000U +/* WDT Component Version Register */ +#define WDT_COMP_VERSION_MASK 0xFFFFFFFFU +/* WDT Component Type Register */ +#define WDT_COMP_TYPE_MASK 0xFFFFFFFFU +/* clang-format on */ + +/** + * @brief WDT object instanse + */ +extern volatile struct wdt_t *const wdt[2]; + +/** + * @brief Feed wdt + */ +void wdt_feed(uint8_t id); + +/** + * @brief Enable wdt + * + * @param[in] id Wdt id 0 or 1 + * + */ +void wdt_enable(uint8_t id); + +/** + * @brief Clear wdt interrupt + * + * @param[in] id Wdt id 0 or 1 + * + */ +void wdt_interrupt_clear(uint8_t id); + +/** + * @brief Clear wdt interrupt + * + * @param[in] id Wdt id 0 or 1 + * @param[in] mode Set wdt work mode + * + */ +void wdt_response_mode(uint8_t id, uint8_t mode); + +/** + * @brief Set wdt timeout + * + * @param[in] id Wdt id 0 or 1 + * @param[in] timeout Wdt trigger time + * + */ +void wdt_timeout_set(uint8_t id, uint8_t timeout); + +/** + * @brief Start wdt + * + * @param[in] id Wdt id 0 or 1 + * @param[in] toms Wdt trigger time + * + */ +int wdt_start(uint8_t id, size_t toms); + +/** + * @brief Stop wdt + * + * @param[in] id Wdt id 0 or 1 + * + */ +void wdt_stop(uint8_t id); + +/** + * @brief Set wdt interrupt function + * + * @param[in] id Wdt id 0 or 1 + * @param[in] on_irq Wdt interrupt function + * + */ +void wdt_set_irq(uint8_t id, plic_irq_callback_t on_irq); + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_WDT_H */ diff --git a/lib/drivers/otp.c b/lib/drivers/otp.c new file mode 100644 index 0000000..50e5226 --- /dev/null +++ b/lib/drivers/otp.c @@ -0,0 +1,602 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "otp.h" +#include "platform.h" +#include "sysctl.h" + +/* clang-format off */ +#define DELAY_TIMEOUT 0xFFFFFFU +#define WRTEST_NUM 0xA5U +/* clang-format on */ + +volatile struct otp_t* const otp = (volatile struct otp_t*)OTP_BASE_ADDR; + +void otp_init(uint8_t div) +{ + sysctl_clock_enable(SYSCTL_CLOCK_OTP); + otp->otp_cpu_ctrl = 0; + otp->otp_thershold = div; + otp->data_blk_ctrl = 0; + otp->gb_otp_en = 0; + otp->otp_pwr_mode = 0; + otp->otp_web_cpu = 1; + otp->otp_rstb_cpu = 1; + otp->otp_seltm_cpu = 0; + otp->otp_readen_cpu = 0; + otp->otp_pgmen_cpu = 0; + otp->otp_dle_cpu = 0; + otp->otp_din_cpu = 0; + otp->otp_cpumpen_cpu = 0; + otp->otp_cle_cpu = 0; + otp->otp_ceb_cpu = 1; + otp->otp_adr_cpu = 0; + otp->otp_dat_cpu = 0; +} + +void otp_test_enable(void) +{ + otp->otp_cpu_ctrl = 0xCAAC; +} + +void otp_test_disable(void) +{ + otp->otp_cpu_ctrl = 0; +} + +void otp_key_output_enable(void) +{ + otp->gb_otp_en = 1; +} + +void otp_key_output_disable(void) +{ + otp->gb_otp_en = 0; +} + +enum otp_status_t otp_status_get(uint32_t flag) +{ + if (otp->otp_status & flag) + return OTP_FLAG_SET; + return OTP_FLAG_UNSET; +} + +static enum otp_status_t otp_bisr_write(void) +{ + uint32_t time_out = 0; + + otp->otp_cle = 1; + otp->otp_mode = 0x02; + otp->otp_test_mode = 0x30; + otp->test_step = 0; + otp->otp_ceb = 0; + while (otp->bisr_finish == 0) + { + time_out++; + if (time_out >= DELAY_TIMEOUT) + return OTP_ERROR_TIMEOUT; + } + otp->bisr_finish = 0; + if (otp->pro_wrong) + return OTP_ERROR_BISR; + return OTP_OK; +} + +static enum otp_status_t otp_bisr_read(void) +{ + uint32_t time_out = 0; + + otp->otp_cle = 1; + otp->otp_mode = 0x02; + otp->otp_test_mode = 0x30; + otp->test_step = 1; + otp->otp_ceb = 0; + while (otp->bisr_finish == 0) + { + time_out++; + if (time_out >= DELAY_TIMEOUT) + return OTP_ERROR_TIMEOUT; + } + otp->bisr_finish = 0; + return OTP_OK; +} + +enum otp_status_t otp_blank_check(void) +{ + enum otp_status_t status; + uint32_t time_out = 0; + + if (otp_func_reg_disable_get(BLANK_TEST_DISABLE) == OTP_FUNC_DISABLE) + return OTP_FUNC_DISABLE; + + otp->otp_cle = 1; + otp->otp_mode = 0x02; + otp->otp_test_mode = 0x24; + otp->blank_finish = 0; + otp->otp_ceb = 0; + while (otp->blank_finish == 0) + { + time_out++; + if (time_out >= DELAY_TIMEOUT) + return OTP_ERROR_TIMEOUT; + } + if (otp->otp_bisr_fail) + return OTP_ERROR_BLANK; + + status = otp_bisr_write(); + if (status != OTP_OK) + return status; + status = otp_bisr_read(); + if (status != OTP_OK) + return status; + status = otp_func_reg_disable_set(BLANK_TEST_DISABLE); + if (status != OTP_OK) + return status; + return OTP_OK; +} + +enum otp_status_t otp_testdec(void) +{ + uint32_t time_out = 0; + + otp->otp_cle = 1; + otp->otp_mode = 0x02; + otp->otp_test_mode = 0x21; + otp->otp_ceb = 0; + while (otp->td_result == 0) + { + time_out++; + if (time_out >= DELAY_TIMEOUT) + return OTP_ERROR_TIMEOUT; + } + if (otp->td_result == 0x01) + { + otp->td_result = 0; + return OTP_ERROR_TESTDEC; + } + return OTP_OK; +} + +enum otp_status_t otp_wrtest(void) +{ + uint16_t addr, data, i, j; + uint32_t time_out; + + otp->otp_cle = 1; + otp->otp_mode = 0x02; + otp->otp_test_mode = 0x01; + otp->test_step = 0; + otp->data_acp_flag = 0; + otp->otp_ceb = 0; + addr = 0; + for (i = 0; i < 128; i++) + { + data = WRTEST_NUM; + for (j = 0; j < 8; j++) + { + if ((addr == 1023) || (data & 0x01)) + { + time_out = 0; + while (otp->otp_adr_in_flag == 0) + { + time_out++; + if (time_out >= DELAY_TIMEOUT) + return OTP_ERROR_TIMEOUT; + } + otp->otp_apb_adr = addr; + if (addr == 1023) + { + otp->otp_in_dat = data & 0x01; + otp->otp_last_dat = 0x01; + } + else + otp->otp_in_dat = 0x01; + otp->dat_in_finish = 0x01; + time_out = 0; + while (otp->data_acp_flag == 0) + { + time_out++; + if (time_out >= DELAY_TIMEOUT) + return OTP_ERROR_TIMEOUT; + } + if (otp->data_acp_flag == 0x01) + { + otp->data_acp_flag = 0; + return OTP_ERROR_WRITE; + } + otp->data_acp_flag = 0; + } + data >>= 1; + addr++; + } + } + time_out = 0; + while ((otp->wr_result & 0x04) == 0) + { + time_out++; + if (time_out >= DELAY_TIMEOUT) + return OTP_ERROR_TIMEOUT; + } + otp->wr_result &= 0xFFFFFFFB; + + otp->otp_cle = 1; + otp->otp_mode = 0x02; + otp->otp_test_mode = 0x01; + otp->test_step = 1; + otp->data_acp_flag = 0; + otp->otp_ceb = 0; + addr = 0; + for (i = 0; i < 128; i++) + { + time_out = 0; + while (otp->otp_adr_in_flag == 0) + { + time_out++; + if (time_out >= DELAY_TIMEOUT) + return OTP_ERROR_TIMEOUT; + if (otp->wr_result == 0x01) + { + otp->wr_result = 0; + return OTP_ERROR_WRTEST; + } + } + otp->otp_in_dat = WRTEST_NUM; + otp->otp_apb_adr = addr; + if (i == 127) + otp->otp_last_dat = 0x01; + addr += 8; + } + time_out = 0; + while ((otp->wr_result & 0x03) == 0) + { + time_out++; + if (time_out >= DELAY_TIMEOUT) + return OTP_ERROR_TIMEOUT; + } + if ((otp->wr_result & 0x03) == 0x01) + { + otp->wr_result = 0; + return OTP_ERROR_WRTEST; + } + return OTP_OK; +} + +static enum otp_status_t otp_write_byte(uint32_t addr, uint8_t* data_buf, uint32_t length) +{ + enum otp_status_t status; + uint8_t data, index; + uint32_t time_out; + + otp->otp_cle = 0; + otp->otp_mode = 1; + otp->data_acp_flag = 0; + otp->otp_wrg_adr_flag = 0; + otp->otp_ceb = 0; + index = 0; + addr *= 8; + length *= 8; + data = *data_buf++; + while (length--) + { + if ((length == 0) || (data & 0x01)) + { + time_out = 0; + while (otp->otp_adr_in_flag == 0) + { + time_out++; + if (time_out >= DELAY_TIMEOUT) + return OTP_ERROR_TIMEOUT; + } + otp->otp_apb_adr = addr; + if (length == 0) + { + otp->otp_in_dat = data & 0x01; + otp->otp_last_dat = 1; + } + else + otp->otp_in_dat = 1; + otp->dat_in_finish = 1; + time_out = 0; + while (otp->data_acp_flag == 0) + { + time_out++; + if (time_out >= DELAY_TIMEOUT) + return OTP_ERROR_TIMEOUT; + } + if (otp->otp_wrg_adr_flag == 1) + return OTP_ERROR_ADDRESS; + if (otp->data_acp_flag == 1) + return OTP_ERROR_WRITE; + otp->data_acp_flag = 0; + } + data >>= 1; + addr++; + index++; + if (index == 8) + { + index = 0; + data = *data_buf++; + } + } + + status = otp_bisr_write(); + if (status != OTP_OK) + return status; + status = otp_bisr_read(); + if (status != OTP_OK) + return status; + return OTP_OK; +} + +static enum otp_status_t otp_read_byte(uint32_t addr, uint8_t* data_buf, uint32_t length) +{ + uint32_t time_out; + + otp->otp_cle = 0; + otp->otp_mode = 0; + otp->otp_wrg_adr_flag = 0; + otp->otp_ceb = 0; + addr *= 8; + while (length--) + { + time_out = 0; + while (otp->otp_adr_in_flag == 0) + { + time_out++; + if (time_out >= DELAY_TIMEOUT) + return OTP_ERROR_TIMEOUT; + } + if (length == 0) + otp->otp_last_dat = 1; + otp->otp_apb_adr = addr; + time_out = 0; + while (otp->otp_data_rdy == 0) + { + time_out++; + if (time_out >= DELAY_TIMEOUT) + return OTP_ERROR_TIMEOUT; + } + if (otp->otp_wrg_adr_flag == 0x01) + return OTP_ERROR_ADDRESS; + *data_buf++ = otp->otp_data; + addr += 8; + } + return OTP_OK; +} + +enum otp_status_t otp_write_data(uint32_t addr, uint8_t* data_buf, uint32_t length) +{ + enum otp_status_t status; + + if (addr >= OTP_BISR_DATA_ADDR) + return OTP_ERROR_ADDRESS; + length = length <= OTP_BISR_DATA_ADDR - addr ? length : OTP_BISR_DATA_ADDR - addr; + + status = otp_write_byte(addr, data_buf, length); + if (status == OTP_ERROR_ADDRESS) + status = OTP_BLOCK_PROTECTED; + return status; +} + +enum otp_status_t otp_read_data(uint32_t addr, uint8_t* data_buf, uint32_t length) +{ + enum otp_status_t status; + + if (addr >= OTP_BISR_DATA_ADDR) + return OTP_ERROR_ADDRESS; + length = length <= OTP_BISR_DATA_ADDR - addr ? length : OTP_BISR_DATA_ADDR - addr; + + status = otp_read_byte(addr, data_buf, length); + if (status == OTP_ERROR_ADDRESS) + status = OTP_ERROR_NULL; + return status; +} + +enum otp_status_t otp_key_write(uint8_t* data_buf) +{ + enum otp_status_t status; + + status = otp_write_byte(OTP_AES_KEY_ADDR, data_buf, 16); + if (status == OTP_ERROR_ADDRESS) + status = OTP_FUNC_DISABLE; + return status; +} + +enum otp_status_t otp_key_compare(uint8_t* data_buf) +{ + uint32_t time_out = 0; + + otp->key_cmp_result = 0; + otp->otp_cmp_key = ((uint32_t)data_buf[0] << 24) | ((uint32_t)data_buf[1] << 16) | ((uint32_t)data_buf[2] << 8) | (uint32_t)data_buf[3]; + otp->otp_cmp_key = ((uint32_t)data_buf[4] << 24) | ((uint32_t)data_buf[5] << 16) | ((uint32_t)data_buf[6] << 8) | (uint32_t)data_buf[7]; + otp->otp_cmp_key = ((uint32_t)data_buf[8] << 24) | ((uint32_t)data_buf[9] << 16) | ((uint32_t)data_buf[10] << 8) | (uint32_t)data_buf[11]; + otp->otp_cmp_key = ((uint32_t)data_buf[12] << 24) | ((uint32_t)data_buf[13] << 16) | ((uint32_t)data_buf[14] << 8) | (uint32_t)data_buf[15]; + while (otp->key_cmp_result == 0) + { + time_out++; + if (time_out >= DELAY_TIMEOUT) + return OTP_ERROR_TIMEOUT; + } + if (otp->key_cmp_result == 0x01) + return OTP_ERROR_KEYCOMP; + else if (otp->key_cmp_result == 0x03) + return OTP_FUNC_DISABLE; + return OTP_OK; +} + +enum otp_status_t otp_data_block_protect_set(enum otp_data_block_t block) +{ + enum otp_status_t status; + uint8_t value; + + if (block >= DATA_BLOCK_MAX) + return OTP_ERROR_PARAM; + otp->data_blk_ctrl = 0x01; + value = 0x03 << ((block % 4) * 2); + status = otp_write_byte(OTP_BLOCK_CTL_ADDR + block / 4, &value, 1); + otp->data_blk_ctrl = 0; + return status; +} + +enum otp_status_t otp_func_reg_disable_set(enum otp_func_reg_t func) +{ + enum otp_status_t status; + uint8_t value; + + if (func >= FUNC_REG_MAX) + return OTP_ERROR_PARAM; + otp->data_blk_ctrl = 0x01; + value = 0x03 << ((func % 4) * 2); + status = otp_write_byte(OTP_WIRED_REG_ADDR + func / 4, &value, 1); + otp->data_blk_ctrl = 0; + return status; +} + +enum otp_status_t otp_data_block_protect_get(enum otp_data_block_t block) +{ + if (block < DATA_BLOCK_MAX / 2) + { + if (otp->block_flag_low & (0x01 << block)) + return OTP_BLOCK_PROTECTED; + } + else if (block < DATA_BLOCK_MAX) + { + if (otp->block_flag_high & (0x01 << (block - DATA_BLOCK_MAX / 2))) + return OTP_BLOCK_PROTECTED; + } + else + return OTP_ERROR_PARAM; + return OTP_BLOCK_NORMAL; +} + +enum otp_status_t otp_func_reg_disable_get(enum otp_func_reg_t func) +{ + if (func < FUNC_REG_MAX / 2) + { + if (otp->reg_flag_low & (0x01 << func)) + return OTP_FUNC_DISABLE; + } + else if (func < FUNC_REG_MAX) + { + if (otp->reg_flag_high & (0x01 << (func - FUNC_REG_MAX / 2))) + return OTP_FUNC_DISABLE; + } + else + return OTP_ERROR_PARAM; + return OTP_FUNC_ENABLE; +} + +enum otp_status_t otp_data_block_protect_refresh(enum otp_data_block_t block) +{ + uint8_t value; + + if (block < DATA_BLOCK_MAX) + return otp_read_byte(OTP_BLOCK_CTL_ADDR + block / 4, &value, 1); + else + return OTP_ERROR_PARAM; +} + +enum otp_status_t otp_soft_write(uint32_t addr, uint8_t* data_buf, uint32_t length) +{ + uint8_t data, index, count; + + otp->otp_ceb_cpu = 1; + otp->otp_cle_cpu = 0; + otp->otp_seltm_cpu = 0; + otp->otp_readen_cpu = 0; + otp->otp_dle_cpu = 0; + otp->otp_web_cpu = 1; + otp->otp_cpumpen_cpu = 0; + otp->otp_pgmen_cpu = 0; + otp->otp_rstb_cpu = 1; + + otp->otp_ceb_cpu = 0; + otp->otp_rstb_cpu = 0; + otp->otp_rstb_cpu = 1; + + index = 0; + addr *= 8; + length *= 8; + data = *data_buf++; + while (length) + { + otp->otp_adr_cpu = addr; + otp->otp_din_cpu = data & 0x01; + otp->otp_dle_cpu = 1; + otp->otp_web_cpu = 0; + otp->otp_web_cpu = 1; + otp->otp_dle_cpu = 0; + count = 20; + while (count--) + { + otp->otp_pgmen_cpu = 1; + otp->otp_cpumpen_cpu = 1; + otp->otp_web_cpu = 0; + otp->otp_web_cpu = 1; + otp->otp_cpumpen_cpu = 0; + otp->otp_pgmen_cpu = 0; + if (otp->otp_dat_cpu == 0) + break; + } + if (otp->otp_dat_cpu & 0x01) + break; + data >>= 1; + addr++; + index++; + if (index == 8) + { + index = 0; + data = *data_buf++; + } + length--; + } + otp->otp_ceb_cpu = 1; + if (length) + return OTP_ERROR_WRITE; + return OTP_OK; +} + +enum otp_status_t otp_soft_read(uint32_t addr, uint8_t* data_buf, uint32_t length) +{ + otp->otp_ceb_cpu = 1; + otp->otp_dle_cpu = 0; + otp->otp_cle_cpu = 0; + otp->otp_pgmen_cpu = 0; + otp->otp_web_cpu = 1; + otp->otp_readen_cpu = 0; + otp->otp_rstb_cpu = 1; + + otp->otp_ceb_cpu = 0; + otp->otp_rstb_cpu = 0; + otp->otp_rstb_cpu = 1; + + while (length) + { + otp->otp_adr_cpu = addr; + otp->otp_readen_cpu = 1; + *data_buf++ = otp->otp_dat_cpu; + otp->otp_readen_cpu = 0; + addr += 8; + length--; + } + otp->otp_ceb_cpu = 1; + if (length) + return OTP_ERROR_WRITE; + return OTP_OK; +} + +uint32_t otp_wrong_address_get(void) +{ + return otp->otp_pro_adr; +} diff --git a/lib/drivers/plic.c b/lib/drivers/plic.c new file mode 100644 index 0000000..5f1e6ed --- /dev/null +++ b/lib/drivers/plic.c @@ -0,0 +1,204 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include "env/encoding.h" +#include "plic.h" +#include "syscalls.h" +#include "syslog.h" + +volatile struct plic_t* const plic = (volatile struct plic_t*)PLIC_BASE_ADDR; + +struct plic_instance_t +{ + plic_irq_callback_t callback; + void* ctx; +}; + +static struct plic_instance_t plic_instance[PLIC_NUM_HARTS][IRQN_MAX]; + +int plic_init(void) +{ + int i = 0; + + /* Get current hart id */ + unsigned long hart_id = read_csr(mhartid); + + /* Disable all interrupts for the current hart. */ + for (i = 0; i < ((PLIC_NUM_SOURCES + 32u) / 32u); i++) + plic->target_enables.target[hart_id].enable[i] = 0; + + /* Set priorities to zero. */ + for (i = 0; i < PLIC_NUM_SOURCES; i++) + plic->source_priorities.priority[i] = 0; + + /* Set the threshold to zero. */ + plic->targets.target[hart_id].priority_threshold = 0; + + /* Clear PLIC instance for every cores */ + for (i = 0; i < IRQN_MAX; i++) + { + /* clang-format off */ + plic_instance[hart_id][i] = (const struct plic_instance_t){ + .callback = NULL, + .ctx = NULL, + }; + /* clang-format on */ + } + + /* + * A successful claim will also atomically clear the corresponding + * pending bit on the interrupt source. A target can perform a claim + * at any time, even if the EIP is not set. + */ + i = 0; + while (plic->targets.target[hart_id].claim_complete > 0 && i < 100) + { + /* This loop will clear pending bit on the interrupt source */ + i++; + } + + /* Enable machine external interrupts. */ + set_csr(mie, MIP_MEIP); + return 0; +} + +int plic_irq_enable(plic_irq_t irq_number) +{ + /* Check parameters */ + if (PLIC_NUM_SOURCES < irq_number || 0 > irq_number) + return -1; + unsigned long hart_id = read_csr(mhartid); + /* Get current enable bit array by IRQ number */ + uint32_t current = plic->target_enables.target[hart_id].enable[irq_number / 32]; + /* Set enable bit in enable bit array */ + current |= (uint32_t)1 << (irq_number % 32); + /* Write back the enable bit array */ + plic->target_enables.target[hart_id].enable[irq_number / 32] = current; + return 0; +} + +int plic_irq_disable(plic_irq_t irq_number) +{ + /* Check parameters */ + if (PLIC_NUM_SOURCES < irq_number || 0 > irq_number) + return -1; + unsigned long hart_id = read_csr(mhartid); + /* Get current enable bit array by IRQ number */ + uint32_t current = plic->target_enables.target[hart_id].enable[irq_number / 32]; + /* Clear enable bit in enable bit array */ + current &= ~((uint32_t)1 << (irq_number % 32)); + /* Write back the enable bit array */ + plic->target_enables.target[hart_id].enable[irq_number / 32] = current; + return 0; +} + +int plic_set_priority(plic_irq_t irq_number, uint32_t priority) +{ + /* Check parameters */ + if (PLIC_NUM_SOURCES < irq_number || 0 > irq_number) + return -1; + /* Set interrupt priority by IRQ number */ + plic->source_priorities.priority[irq_number] = priority; + return 0; +} + +uint32_t plic_get_priority(plic_irq_t irq_number) +{ + /* Check parameters */ + if (PLIC_NUM_SOURCES < irq_number || 0 > irq_number) + return 0; + /* Get interrupt priority by IRQ number */ + return plic->source_priorities.priority[irq_number]; +} + +uint32_t plic_irq_claim(void) +{ + unsigned long hart_id = read_csr(mhartid); + /* Perform IRQ claim */ + return plic->targets.target[hart_id].claim_complete; +} + +int plic_irq_complete(uint32_t source) +{ + unsigned long hart_id = read_csr(mhartid); + /* Perform IRQ complete */ + plic->targets.target[hart_id].claim_complete = source; + return 0; +} + +int plic_irq_register(plic_irq_t irq, plic_irq_callback_t callback, void* ctx) +{ + /* Read hart id */ + unsigned long hart_id = read_csr(mhartid); + /* Set user callback function */ + plic_instance[hart_id][irq].callback = callback; + /* Assign user context */ + plic_instance[hart_id][irq].ctx = ctx; + return 0; +} + +int plic_irq_deregister(plic_irq_t irq) +{ + /* Just assign NULL to user callback function and context */ + return plic_irq_register(irq, NULL, NULL); +} + +/*Entry Point for PLIC Interrupt Handler*/ +uintptr_t handle_irq_m_ext(uintptr_t cause, uintptr_t epc, uintptr_t regs[32]) +{ + /* + * After the highest-priority pending interrupt is claimed by a target + * and the corresponding IP bit is cleared, other lower-priority + * pending interrupts might then become visible to the target, and so + * the PLIC EIP bit might not be cleared after a claim. The interrupt + * handler can check the local meip/heip/seip/ueip bits before exiting + * the handler, to allow more efficient service of other interrupts + * without first restoring the interrupted context and taking another + * interrupt trap. + */ + if (read_csr(mip) & MIP_MEIP) + { + /* Get current hart id */ + uint64_t hart_id = read_csr(mhartid); + /* Get primitive interrupt enable flag */ + uint64_t ie_flag = read_csr(mie); + /* Get current IRQ num */ + uint32_t int_num = plic->targets.target[hart_id].claim_complete; + /* Get primitive IRQ threshold */ + uint32_t int_threshold = plic->targets.target[hart_id].priority_threshold; + /* Set new IRQ threshold = current IRQ threshold */ + plic->targets.target[hart_id].priority_threshold = plic->source_priorities.priority[int_num]; + /* Disable software interrupt and timer interrupt */ + clear_csr(mie, MIP_MTIP | MIP_MSIP); + /* Enable global interrupt */ + set_csr(mstatus, MSTATUS_MIE); + if (plic_instance[hart_id][int_num].callback) + plic_instance[hart_id][int_num].callback( + plic_instance[hart_id][int_num].ctx); + /* Perform IRQ complete */ + plic->targets.target[hart_id].claim_complete = int_num; + /* Disable global interrupt */ + clear_csr(mstatus, MSTATUS_MIE); + /* Set MPIE and MPP flag used to MRET instructions restore MIE flag */ + set_csr(mstatus, MSTATUS_MPIE | MSTATUS_MPP); + /* Restore primitive interrupt enable flag */ + write_csr(mie, ie_flag); + /* Restore primitive IRQ threshold */ + plic->targets.target[hart_id].priority_threshold = int_threshold; + } + + return epc; +} diff --git a/lib/drivers/rtc.c b/lib/drivers/rtc.c new file mode 100644 index 0000000..4c7d8d8 --- /dev/null +++ b/lib/drivers/rtc.c @@ -0,0 +1,581 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include "env/encoding.h" +#include "sysctl.h" +#include "rtc.h" + +volatile struct rtc_t *const rtc = (volatile struct rtc_t *)RTC_BASE_ADDR; + +struct tm rtc_date_time; + +int rtc_timer_set_mode(rtc_timer_mode_e timer_mode) +{ + struct rtc_register_ctrl_t register_ctrl = rtc->register_ctrl; + + switch (timer_mode) + { + case RTC_TIMER_PAUSE: + register_ctrl.read_enable = 0; + register_ctrl.write_enable = 0; + break; + case RTC_TIMER_RUNNING: + register_ctrl.read_enable = 1; + register_ctrl.write_enable = 0; + break; + case RTC_TIMER_SETTING: + register_ctrl.read_enable = 0; + register_ctrl.write_enable = 1; + break; + default: + register_ctrl.read_enable = 0; + register_ctrl.write_enable = 0; + break; + } + + rtc->register_ctrl = register_ctrl; + + return 0; +} + +rtc_timer_mode_e rtc_timer_get_mode(void) +{ + struct rtc_register_ctrl_t register_ctrl = rtc->register_ctrl; + rtc_timer_mode_e timer_mode = RTC_TIMER_PAUSE; + + if ((!register_ctrl.read_enable) && (!register_ctrl.write_enable)) + { + /* RTC_TIMER_PAUSE */ + timer_mode = RTC_TIMER_PAUSE; + } + else if ((register_ctrl.read_enable) && (!register_ctrl.write_enable)) + { + /* RTC_TIMER_RUNNING */ + timer_mode = RTC_TIMER_RUNNING; + } + else if ((!register_ctrl.read_enable) && (register_ctrl.write_enable)) { + /* RTC_TIMER_SETTING */ + timer_mode = RTC_TIMER_RUNNING; + } + else + { + /* Something is error, reset timer mode */ + rtc_timer_set_mode(timer_mode); + } + + return timer_mode; +} + +static inline int rtc_in_range(int value, int min, int max) +{ + return ((value >= min) && (value <= max)); +} + +int rtc_timer_set_tm(const struct tm *tm) +{ + struct rtc_date_t timer_date; + struct rtc_time_t timer_time; + struct rtc_extended_t timer_extended; + + if (tm) + { + /* + * Range of tm->tm_sec could be [0,61] + * + * Range of tm->tm_sec allows for a positive leap second. Two + * leap seconds in the same minute are not allowed (the C90 + * range 0..61 was a defect) + */ + if (rtc_in_range(tm->tm_sec, 0, 59)) + timer_time.second = tm->tm_sec; + else + return -1; + + /* Range of tm->tm_min could be [0,59] */ + if (rtc_in_range(tm->tm_min, 0, 59)) + timer_time.minute = tm->tm_min; + else + return -1; + + /* Range of tm->tm_hour could be [0, 23] */ + if (rtc_in_range(tm->tm_hour, 0, 23)) + timer_time.hour = tm->tm_hour; + else + return -1; + + /* Range of tm->tm_mday could be [1, 31] */ + if (rtc_in_range(tm->tm_mday, 1, 31)) + timer_date.day = tm->tm_mday; + else + return -1; + + /* + * Range of tm->tm_mon could be [0, 11] + * But in this RTC, date.month should be [1, 12] + */ + if (rtc_in_range(tm->tm_mon, 0, 11)) + timer_date.month = tm->tm_mon + 1; + else + return -1; + + /* + * Range of tm->tm_year is the years since 1900 + * But in this RTC, year is split into year and century + * In this RTC, century range is [0,31], year range is [0,99] + */ + int human_year = tm->tm_year + 1900; + int rtc_year = human_year % 100; + int rtc_century = human_year / 100; + + if (rtc_in_range(rtc_year, 0, 99) && + rtc_in_range(rtc_century, 0, 31)) + { + timer_date.year = rtc_year; + timer_extended.century = rtc_century; + } + else + return -1; + + /* Range of tm->tm_wday could be [0, 6] */ + if (rtc_in_range(tm->tm_wday, 0, 6)) + timer_date.week = tm->tm_wday; + else + return -1; + + /* Set RTC mode to timer setting mode */ + rtc_timer_set_mode(RTC_TIMER_SETTING); + /* Write value to RTC */ + rtc->date = timer_date; + rtc->time = timer_time; + rtc->extended = timer_extended; + /* Get CPU current freq */ + unsigned long freq = sysctl_clock_get_freq(SYSCTL_CLOCK_CPU); + /* Set threshold to 1/26000000 s */ + freq = freq / 26000000; + /* Get current CPU cycle */ + unsigned long start_cycle = read_csr(mcycle); + /* Wait for 1/26000000 s to sync data */ + while (read_csr(mcycle) - start_cycle < freq) + continue; + /* Set RTC mode to timer running mode */ + rtc_timer_set_mode(RTC_TIMER_RUNNING); + } + + return 0; +} + +int rtc_timer_set_alarm_tm(const struct tm *tm) +{ + struct rtc_alarm_date_t alarm_date; + struct rtc_alarm_time_t alarm_time; + + if (tm) { + /* + * Range of tm->tm_sec could be [0,61] + * + * Range of tm->tm_sec allows for a positive leap second. Two + * leap seconds in the same minute are not allowed (the C90 + * range 0..61 was a defect) + */ + if (rtc_in_range(tm->tm_sec, 0, 59)) + alarm_time.second = tm->tm_sec; + else + return -1; + + /* Range of tm->tm_min could be [0,59] */ + if (rtc_in_range(tm->tm_min, 0, 59)) + alarm_time.minute = tm->tm_min; + else + return -1; + + /* Range of tm->tm_hour could be [0, 23] */ + if (rtc_in_range(tm->tm_hour, 0, 23)) + alarm_time.hour = tm->tm_hour; + else + return -1; + + /* Range of tm->tm_mday could be [1, 31] */ + if (rtc_in_range(tm->tm_mday, 1, 31)) + alarm_date.day = tm->tm_mday; + else + return -1; + + /* + * Range of tm->tm_mon could be [0, 11] + * But in this RTC, date.month should be [1, 12] + */ + if (rtc_in_range(tm->tm_mon, 0, 11)) + alarm_date.month = tm->tm_mon + 1; + else + return -1; + + /* + * Range of tm->tm_year is the years since 1900 + * But in this RTC, year is split into year and century + * In this RTC, century range is [0,31], year range is [0,99] + */ + int human_year = tm->tm_year + 1900; + int rtc_year = human_year % 100; + int rtc_century = human_year / 100; + + if (rtc_in_range(rtc_year, 0, 99) && + rtc_in_range(rtc_century, 0, 31)) + { + alarm_date.year = rtc_year; + } else + return -1; + + /* Range of tm->tm_wday could be [0, 6] */ + if (rtc_in_range(tm->tm_wday, 0, 6)) + alarm_date.week = tm->tm_wday; + else + return -1; + + /* Write value to RTC */ + rtc->alarm_date = alarm_date; + rtc->alarm_time = alarm_time; + } + + return 0; +} + +int rtc_year_is_leap(int year) +{ + return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); +} + +int rtc_get_yday(int year, int month, int day) +{ + static const int days[2][13] = + { + {0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}, + {0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335} + }; + int leap = rtc_year_is_leap(year); + + return days[leap][month] + day; +} + +int rtc_get_wday(int year, int month, int day) +{ + /* Magic method to get weekday */ + int weekday = (day += month < 3 ? year-- : year - 2, 23 * month / 9 + day + 4 + year / 4 - year / 100 + year / 400) % 7; + return weekday; +} + +struct tm *rtc_timer_get_tm(void) +{ + if (rtc_timer_get_mode() != RTC_TIMER_RUNNING) + return NULL; + + struct rtc_date_t timer_date = rtc->date; + struct rtc_time_t timer_time = rtc->time; + struct rtc_extended_t timer_extended = rtc->extended; + + struct tm *tm = &rtc_date_time; + + tm->tm_sec = timer_time.second % 60; + tm->tm_min = timer_time.minute % 60; + tm->tm_hour = timer_time.hour % 24; + tm->tm_mday = timer_date.day % 31; + tm->tm_mon = (timer_date.month % 12) - 1; + tm->tm_year = (timer_date.year % 100) + (timer_extended.century * 100) - 1900; + tm->tm_wday = timer_date.week; + tm->tm_yday = rtc_get_yday(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday); + tm->tm_isdst = -1; + + return tm; +} + +struct tm *rtc_timer_get_alarm_tm(void) +{ + if (rtc_timer_get_mode() != RTC_TIMER_RUNNING) + return NULL; + + struct rtc_alarm_date_t alarm_date = rtc->alarm_date; + struct rtc_alarm_time_t alarm_time = rtc->alarm_time; + struct rtc_extended_t timer_extended = rtc->extended; + + struct tm *tm = &rtc_date_time; + + tm->tm_sec = alarm_time.second % 60; + tm->tm_min = alarm_time.minute % 60; + tm->tm_hour = alarm_time.hour % 24; + tm->tm_mday = alarm_date.day % 31; + tm->tm_mon = (alarm_date.month % 12) - 1; + /* Alarm and Timer use same timer_extended.century */ + tm->tm_year = (alarm_date.year % 100) + (timer_extended.century * 100) - 1900; + tm->tm_wday = alarm_date.week; + tm->tm_yday = rtc_get_yday(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday); + tm->tm_isdst = -1; + + return tm; +} + +int rtc_timer_set(int year, int month, int day, int hour, int minute, int second) +{ + struct tm date_time = + { + .tm_sec = second, + .tm_min = minute, + .tm_hour = hour, + .tm_mday = day, + .tm_mon = month - 1, + .tm_year = year - 1900, + .tm_wday = rtc_get_wday(year, month, day), + .tm_yday = rtc_get_yday(year, month, day), + .tm_isdst = -1, + }; + return rtc_timer_set_tm(&date_time); +} + +int rtc_timer_get(int *year, int *month, int *day, int *hour, int *minute, int *second) +{ + struct tm *tm = rtc_timer_get_tm(); + + if (tm) + { + if (year) + *year = tm->tm_year + 1900; + if (month) + *month = tm->tm_mon + 1; + if (day) + *day = tm->tm_mday; + if (hour) + *hour = tm->tm_hour; + if (minute) + *minute = tm->tm_min; + if (second) + *second = tm->tm_sec; + } else + return -1; + + return 0; +} + +int rtc_timer_set_alarm(int year, int month, int day, int hour, int minute, int second) +{ + struct tm date_time = { + .tm_sec = second, + .tm_min = minute, + .tm_hour = hour, + .tm_mday = day, + .tm_mon = month - 1, + .tm_year = year - 1900, + .tm_wday = rtc_get_wday(year, month, day), + .tm_yday = rtc_get_yday(year, month, day), + .tm_isdst = -1, + }; + + return rtc_timer_set_alarm_tm(&date_time); +} + +int rtc_timer_get_alarm(int *year, int *month, int *day, int *hour, int *minute, int *second) +{ + struct tm *tm = rtc_timer_get_alarm_tm(); + + if (tm) { + if (year) + *year = tm->tm_year + 1900; + if (month) + *month = tm->tm_mon + 1; + if (day) + *day = tm->tm_mday; + if (hour) + *hour = tm->tm_hour; + if (minute) + *minute = tm->tm_min; + if (second) + *second = tm->tm_sec; + } else + return -1; + + return 0; +} + +int rtc_timer_set_clock_frequency(unsigned int frequency) +{ + struct rtc_initial_count_t initial_count; + + initial_count.count = frequency; + rtc->initial_count = initial_count; + return 0; +} + +unsigned int rtc_timer_get_clock_frequency(void) +{ + return rtc->initial_count.count; +} + +int rtc_timer_set_clock_count_value(unsigned int count) +{ + struct rtc_current_count_t current_count; + + current_count.count = count; + rtc->current_count = current_count; + return 0; +} + +unsigned int rtc_timer_get_clock_count_value(void) +{ + return rtc->current_count.count; +} + +int rtc_tick_interrupt_set(int enable) +{ + struct rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl; + + interrupt_ctrl.tick_enable = enable; + rtc->interrupt_ctrl = interrupt_ctrl; + return 0; +} + +int rtc_tick_interrupt_get(void) +{ + struct rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl; + + return interrupt_ctrl.tick_enable; +} + +int rtc_tick_interrupt_mode_set(rtc_tick_interrupt_mode_e mode) +{ + struct rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl; + + interrupt_ctrl.tick_int_mode = mode; + rtc->interrupt_ctrl = interrupt_ctrl; + return 0; +} + +rtc_tick_interrupt_mode_e rtc_tick_interrupt_mode_get(void) +{ + struct rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl; + + return interrupt_ctrl.tick_int_mode; +} + +int rtc_alarm_interrupt_set(int enable) +{ + struct rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl; + + interrupt_ctrl.alarm_enable = enable; + rtc->interrupt_ctrl = interrupt_ctrl; + return 0; +} + +int rtc_alarm_interrupt_get(void) +{ + struct rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl; + + return interrupt_ctrl.alarm_enable; +} + +int rtc_alarm_interrupt_mask_set(struct rtc_mask_t mask) +{ + struct rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl; + + interrupt_ctrl.alarm_compare_mask = *(uint8_t *)&mask; + rtc->interrupt_ctrl = interrupt_ctrl; + return 0; +} + +struct rtc_mask_t rtc_alarm_interrupt_mask_get(void) +{ + struct rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl; + + uint8_t compare_mask = interrupt_ctrl.alarm_compare_mask; + + return *(struct rtc_mask_t *)&compare_mask; +} + +int rtc_protect_set(int enable) +{ + struct rtc_register_ctrl_t register_ctrl = rtc->register_ctrl; + + struct rtc_mask_t mask = + { + .second = 1, + /* Second mask */ + .minute = 1, + /* Minute mask */ + .hour = 1, + /* Hour mask */ + .week = 1, + /* Week mask */ + .day = 1, + /* Day mask */ + .month = 1, + /* Month mask */ + .year = 1, + }; + + struct rtc_mask_t unmask = + { + .second = 0, + /* Second mask */ + .minute = 0, + /* Minute mask */ + .hour = 0, + /* Hour mask */ + .week = 0, + /* Week mask */ + .day = 0, + /* Day mask */ + .month = 0, + /* Month mask */ + .year = 0, + }; + + if (enable) + { + /* Turn RTC in protect mode, no one can write time */ + register_ctrl.timer_mask = *(uint8_t *)&unmask; + register_ctrl.alarm_mask = *(uint8_t *)&unmask; + register_ctrl.initial_count_mask = 0; + register_ctrl.interrupt_register_mask = 0; + } + else + { + /* Turn RTC in unprotect mode, everyone can write time */ + register_ctrl.timer_mask = *(uint8_t *)&mask; + register_ctrl.alarm_mask = *(uint8_t *)&mask; + register_ctrl.initial_count_mask = 1; + register_ctrl.interrupt_register_mask = 1; + } + + rtc->register_ctrl = register_ctrl; + return 0; +} + +int rtc_init(void) +{ + /* Reset RTC */ + sysctl_reset(SYSCTL_RESET_RTC); + /* Enable RTC */ + sysctl_clock_enable(SYSCTL_CLOCK_RTC); + rtc_timer_set_mode(RTC_TIMER_SETTING); + /* Unprotect RTC */ + rtc_protect_set(0); + /* Set RTC clock frequency */ + rtc_timer_set_clock_frequency( + sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0) + ); + rtc_timer_set_clock_count_value(1); + + /* Set RTC mode to timer running mode */ + rtc_timer_set_mode(RTC_TIMER_RUNNING); + return 0; +} diff --git a/lib/drivers/sha256.c b/lib/drivers/sha256.c new file mode 100644 index 0000000..849274e --- /dev/null +++ b/lib/drivers/sha256.c @@ -0,0 +1,135 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include "env/encoding.h" +#include "sha256.h" +#include "syscalls.h" +#include "sysctl.h" + +volatile struct sha256_t* const sha256 = (volatile struct sha256_t*)SHA256_BASE_ADDR; + +#define ROTL(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) +#define ROTR(x, n) (((x) >> (n)) | ((x) << (32 - (n)))) +#define _BYTESWAP(x) ((ROTR((x), 8) & 0xff00ff00L) | (ROTL((x), 8) & 0x00ff00ffL)) +#define _BYTESWAP64(x) __byteswap64(x) + +static inline uint64_t __byteswap64(uint64_t x) +{ + uint32_t a = x >> 32; + uint32_t b = (uint32_t)x; + + return ((uint64_t)_BYTESWAP(b) << 32) | (uint64_t)_BYTESWAP(a); +} +static const uint8_t padding[64] = +{ + 0x80, 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, 0x02, 0x00}; + +int sha256_init(uint8_t dma_en, uint32_t input_size, SHA256Context* sc) +{ + sysctl_clock_enable(SYSCTL_CLOCK_SHA); + sysctl_reset(SYSCTL_RESET_SHA); + input_size = (input_size + 64) / 64; + if (dma_en) + sha256->sha_input_ctrl |= 1; + else + sha256->sha_input_ctrl &= ~0x01; + + sha256->sha_data_num = input_size; + + sha256->sha_status |= 1 << 16; /*0 for little endian, 1 for big endian*/ + sha256->sha_status |= 1; /*enable sha256*/ + + sc->totalLength = 0LL; + sc->hash[0] = 0x6a09e667L; + sc->hash[1] = 0xbb67ae85L; + sc->hash[2] = 0x3c6ef372L; + sc->hash[3] = 0xa54ff53aL; + sc->hash[4] = 0x510e527fL; + sc->hash[5] = 0x9b05688cL; + sc->hash[6] = 0x1f83d9abL; + sc->hash[7] = 0x5be0cd19L; + sc->bufferLength = 0L; + return 1; +} + +void sha256_update(SHA256Context* sc, const void* vdata, uint32_t len) +{ + const uint8_t* data = vdata; + uint32_t bufferBytesLeft; + uint32_t bytesToCopy; + uint32_t i; + + while (len) + { + bufferBytesLeft = 64L - sc->bufferLength; + + bytesToCopy = bufferBytesLeft; + if (bytesToCopy > len) + bytesToCopy = len; + + memcpy(&sc->buffer.bytes[sc->bufferLength], data, bytesToCopy); + + sc->totalLength += bytesToCopy * 8L; + + sc->bufferLength += bytesToCopy; + data += bytesToCopy; + len -= bytesToCopy; + + if (sc->bufferLength == 64L) + { + for (i = 0; i < 16; i++) + { + while (sha256->sha_input_ctrl & (1 << 8)) + ; + sha256->sha_data_in1 = sc->buffer.words[i]; + } + sc->bufferLength = 0L; + } + } +} + +void sha256_final(SHA256Context* sc, uint8_t hash[SHA256_HASH_SIZE]) +{ + uint32_t bytesToPad; + uint64_t lengthPad; + int i; + + bytesToPad = 120L - sc->bufferLength; + if (bytesToPad > 64L) + bytesToPad -= 64L; + lengthPad = _BYTESWAP64(sc->totalLength); + sha256_update(sc, padding, bytesToPad); + sha256_update(sc, &lengthPad, 8L); + + while (!(sha256->sha_status & 0x01)) + ; + + if (hash) + { + for (i = 0; i < SHA256_HASH_WORDS; i++) + { + *((uint32_t*)hash) = sha256->sha_result[SHA256_HASH_WORDS - i - 1]; + hash += 4; + } + } +} diff --git a/lib/drivers/spi.c b/lib/drivers/spi.c new file mode 100644 index 0000000..c602c52 --- /dev/null +++ b/lib/drivers/spi.c @@ -0,0 +1,615 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "platform.h" +#include "spi.h" +#include "fpioa.h" +#include "common.h" +#include "sysctl.h" +#include +#include + +#define SPI_MAX_NUM 4 + +volatile struct spi_t *const spi[4] = { + (volatile struct spi_t *)SPI0_BASE_ADDR, + (volatile struct spi_t *)SPI1_BASE_ADDR, + (volatile struct spi_t *)SPI_SLAVE_BASE_ADDR, + (volatile struct spi_t *)SPI3_BASE_ADDR +}; + +int spi_clk_init(uint8_t spi_bus){ + configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2); + sysctl_clock_enable(SYSCTL_CLOCK_SPI0 + spi_bus); + sysctl_clock_set_threshold(SYSCTL_THRESHOLD_SPI0 + spi_bus, 0); + return 0; +} + +int spi_init(uint8_t spi_bus){ + spi_clk_init(spi_bus); + dmac_init(); + return 0; +} + +int spi_master_config(uint8_t spi_bus, spi_mode mode, spi_frame_format frame_format, size_t data_bit_length){ + configASSERT(data_bit_length >= 4 && data_bit_length <= 32); + configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2); + + uint8_t dfs_offset, frf_offset; + switch(spi_bus){ + case 0: + case 1: + dfs_offset = 16; + frf_offset = 21; + break; + case 2: + configASSERT(!"Spi Bus 2 Not Support!"); + break; + case 3: + default: + dfs_offset = 0; + frf_offset = 22; + break; + } + + switch (frame_format) + { + case SPI_FF_DUAL: + configASSERT(data_bit_length % 2 == 0); + break; + case SPI_FF_QUAD: + configASSERT(data_bit_length % 4 == 0); + break; + case SPI_FF_OCTAL: + configASSERT(data_bit_length % 8 == 0); + break; + default: + break; + } + volatile struct spi_t *spi_adapter = spi[spi_bus]; + + spi_adapter->baudr = 0x14; + spi_adapter->imr = 0x00; + spi_adapter->dmacr = 0x00; + spi_adapter->dmatdlr = 0x10; + spi_adapter->dmardlr = 0x00; + spi_adapter->ser = 0x00; + spi_adapter->ssienr = 0x00; + spi_adapter->ctrlr0 = (mode << 6) | (frame_format << frf_offset) | ((data_bit_length - 1) << dfs_offset); + spi_adapter->spi_ctrlr0 = 0; + return 0; +} + +void spi_trans_config(uint8_t spi_bus, size_t instruction_length, size_t address_length, + size_t wait_cycles, spi_addr_inst_trans_mode trans_mode) +{ + configASSERT(wait_cycles < (1 << 5)); + configASSERT(trans_mode < 3); + configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2); + volatile struct spi_t *spi_handle = spi[spi_bus]; + uint32_t inst_l; + switch (instruction_length) + { + case 0: + inst_l = 0; + break; + case 4: + inst_l = 1; + break; + case 8: + inst_l = 2; + break; + case 16: + inst_l = 3; + break; + default: + configASSERT(!"Invalid instruction length"); + break; + } + + configASSERT(address_length % 4 == 0 && address_length <= 60); + uint32_t addr_l = address_length / 4; + + spi_handle->spi_ctrlr0 = (wait_cycles << 11) | (inst_l << 8) | (addr_l << 2) | trans_mode; +} + +int spi_send_data(uint8_t spi_bus, uint32_t chip_sel, uint8_t *cmd_buff, uint8_t cmd_len, uint8_t *tx_buff, uint32_t tx_len) +{ + uint32_t index, fifo_len; + configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2); + + volatile struct spi_t *spi_handle = spi[spi_bus]; + spi_handle->ssienr = 0x01; + while (cmd_len){ + spi_handle->dr[0] = *cmd_buff++; + cmd_len--; + } + fifo_len = 32 - spi_handle->txflr; + fifo_len = fifo_len < tx_len ? fifo_len : tx_len; + for (index = 0; index < fifo_len; index++) + spi_handle->dr[0] = *tx_buff++; + tx_len -= fifo_len; + spi_handle->ser = chip_sel; + while (tx_len) { + fifo_len = 32 - spi_handle->txflr; + fifo_len = fifo_len < tx_len ? fifo_len : tx_len; + for (index = 0; index < fifo_len; index++) + spi_handle->dr[0] = *tx_buff++; + tx_len -= fifo_len; + } + while ((spi_handle->sr & 0x05) != 0x04) + ; + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; + return 0; +} + +int spi_send_data_dma(dmac_channel_number channel_num, uint8_t spi_bus, uint32_t chip_sel, + uint8_t *cmd_buff, uint8_t cmd_len, uint8_t *tx_buff, uint32_t tx_len) +{ + configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2); + volatile struct spi_t *spi_handle = spi[spi_bus]; + + uint32_t *buf = malloc((cmd_len + tx_len) * sizeof(uint32_t)); + int i; + for(i = 0; i < cmd_len; i++){ + buf[i] = cmd_buff[i]; + } + + for(i = 0; i < tx_len; i++){ + buf[cmd_len + i] = tx_buff[i]; + } + spi_handle->dmacr = 0x2; /*enable dma transmit*/ + spi_handle->ssienr = 0x01; + + sysctl_dma_select(channel_num, SYSCTL_DMA_SELECT_SSI0_TX_REQ + spi_bus * 2); + dmac_set_single_mode(channel_num, buf, (void *)(&spi_handle->dr[0]), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, cmd_len + tx_len); + spi_handle->ser = chip_sel; + dmac_wait_done(channel_num); + free((void*)buf); + + + while ((spi_handle->sr & 0x05) != 0x04) + ; + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; + return 0; +} + +int spi_normal_send_dma(dmac_channel_number channel_num, uint8_t spi_bus, uint32_t chip_sel, + void *tx_buff, uint32_t tx_len, spi_transfer_width stw) +{ + configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2); + volatile struct spi_t *spi_handle = spi[spi_bus]; + + uint32_t *buf = malloc((tx_len) * sizeof(uint32_t)); + int i; + for(i = 0; i < tx_len; i++){ + switch(stw){ + case SPI_TRANS_SHORT: + buf[i] = ((uint16_t *)tx_buff)[i]; + break; + case SPI_TRANS_INT: + buf[i] = ((uint32_t *)tx_buff)[i]; + break; + break; + case SPI_TRANS_CHAR: + default: + buf[i] = ((uint8_t *)tx_buff)[i]; + break; + } + } + spi_handle->dmacr = 0x2; /*enable dma transmit*/ + spi_handle->ssienr = 0x01; + + sysctl_dma_select(channel_num, SYSCTL_DMA_SELECT_SSI0_TX_REQ + spi_bus * 2); + dmac_set_single_mode(channel_num, buf, (void *)(&spi_handle->dr[0]), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, tx_len); + spi_handle->ser = chip_sel; + dmac_wait_done(channel_num); + free((void*)buf); + + while ((spi_handle->sr & 0x05) != 0x04) + ; + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; + return 0; +} + +int spi_receive_data(uint8_t spi_bus, uint32_t chip_sel, uint8_t *cmd_buff, uint8_t cmd_len, uint8_t *rx_buff, uint32_t rx_len) +{ + uint32_t index, fifo_len; + configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2); + volatile struct spi_t *spi_handle = spi[spi_bus]; + + spi_handle->ctrlr1 = rx_len - 1; + spi_handle->ssienr = 0x01; + while (cmd_len--) + spi_handle->dr[0] = *cmd_buff++; + spi_handle->ser = chip_sel; + while (rx_len) { + fifo_len = spi_handle->rxflr; + fifo_len = fifo_len < rx_len ? fifo_len : rx_len; + for (index = 0; index < fifo_len; index++) + *rx_buff++ = spi_handle->dr[0]; + rx_len -= fifo_len; + } + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; + return 0; +} + +int spi_receive_data_dma(dmac_channel_number w_channel_num, dmac_channel_number r_channel_num, + uint8_t spi_bus, uint32_t chip_sel, uint8_t *cmd_buff, uint8_t cmd_len, uint8_t *rx_buff, uint32_t rx_len) +{ + configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2); + volatile struct spi_t *spi_handle = spi[spi_bus]; + + uint32_t * write_cmd = malloc(sizeof(uint32_t) * (cmd_len + rx_len)); + size_t i; + for (i = 0; i < cmd_len; i++) + write_cmd[i] = cmd_buff[i]; + + spi_handle->ctrlr1 = rx_len - 1; + spi_handle->dmacr = 0x3; + spi_handle->ssienr = 0x01; + spi_handle->ser = chip_sel; + + sysctl_dma_select(w_channel_num, SYSCTL_DMA_SELECT_SSI0_TX_REQ + spi_bus * 2); + sysctl_dma_select(r_channel_num, SYSCTL_DMA_SELECT_SSI0_RX_REQ + spi_bus * 2); + + + dmac_set_single_mode(r_channel_num, (void *)(&spi_handle->dr[0]), write_cmd, DMAC_ADDR_NOCHANGE, DMAC_ADDR_INCREMENT, + DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, rx_len); + + dmac_set_single_mode(w_channel_num, write_cmd, (void *)(&spi_handle->dr[0]), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, cmd_len); + + dmac_wait_done(w_channel_num); + dmac_wait_done(r_channel_num); + + for(i = 0; i < rx_len; i++){ + rx_buff[i] = write_cmd[i]; + } + free(write_cmd); + + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; + return 0; +} + + +int spi_special_receive_data(uint8_t spi_bus, uint32_t chip_sel, uint32_t *cmd_buff, uint8_t cmd_len, uint8_t *rx_buff, uint32_t rx_len) +{ + uint32_t index, fifo_len; + configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2); + volatile struct spi_t *spi_handle = spi[spi_bus]; + + spi_handle->ctrlr1 = rx_len - 1; + spi_handle->ssienr = 0x01; + while (cmd_len--) + spi_handle->dr[0] = *cmd_buff++; + spi_handle->ser = chip_sel; + while (rx_len) { + fifo_len = spi_handle->rxflr; + fifo_len = fifo_len < rx_len ? fifo_len : rx_len; + for (index = 0; index < fifo_len; index++) + *rx_buff++ = spi_handle->dr[0]; + rx_len -= fifo_len; + } + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; + return 0; +} + +int spi_special_receive_data_dma(dmac_channel_number w_channel_num, dmac_channel_number r_channel_num, + uint8_t spi_bus, uint32_t chip_sel, uint32_t *cmd_buff, uint8_t cmd_len, uint8_t *rx_buff, uint32_t rx_len) +{ + configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2); + volatile struct spi_t *spi_handle = spi[spi_bus]; + + uint32_t * write_cmd = malloc(sizeof(uint32_t) * (cmd_len + rx_len)); + size_t i; + for (i = 0; i < cmd_len; i++) + write_cmd[i] = cmd_buff[i]; + + spi_handle->ctrlr1 = rx_len - 1; + spi_handle->dmacr = 0x3; + spi_handle->ssienr = 0x01; + spi_handle->ser = chip_sel; + + sysctl_dma_select(w_channel_num, SYSCTL_DMA_SELECT_SSI0_TX_REQ + spi_bus * 2); + sysctl_dma_select(r_channel_num, SYSCTL_DMA_SELECT_SSI0_RX_REQ + spi_bus * 2); + + + dmac_set_single_mode(r_channel_num, (void *)(&spi_handle->dr[0]), write_cmd, DMAC_ADDR_NOCHANGE, DMAC_ADDR_INCREMENT, + DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, rx_len); + + dmac_set_single_mode(w_channel_num, write_cmd, (void *)(&spi_handle->dr[0]), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, cmd_len); + + dmac_wait_done(w_channel_num); + dmac_wait_done(r_channel_num); + + for(i = 0; i < rx_len; i++){ + rx_buff[i] = write_cmd[i]; + } + free(write_cmd); + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; + return 0; + +} + + +int spi_special_send_data(uint8_t spi_bus, uint32_t chip_sel, uint32_t *cmd_buff, uint8_t cmd_len, uint8_t *tx_buff, uint32_t tx_len) +{ + uint32_t index, fifo_len; + configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2); + + volatile struct spi_t *spi_handle = spi[spi_bus]; + + spi_handle->ssienr = 0x01; + while (cmd_len--) + spi_handle->dr[0] = *cmd_buff++; + fifo_len = 32 - spi_handle->txflr; + fifo_len = fifo_len < tx_len ? fifo_len : tx_len; + for (index = 0; index < fifo_len; index++) + spi_handle->dr[0] = *tx_buff++; + tx_len -= fifo_len; + spi_handle->ser = chip_sel; + while (tx_len) { + fifo_len = 32 - spi_handle->txflr; + fifo_len = fifo_len < tx_len ? fifo_len : tx_len; + for (index = 0; index < fifo_len; index++) + spi_handle->dr[0] = *tx_buff++; + tx_len -= fifo_len; + } + while ((spi_handle->sr & 0x05) != 0x04) + ; + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; + return 0; +} + +int spi_special_send_data_dma(dmac_channel_number channel_num,uint8_t spi_bus, uint32_t chip_sel, + uint32_t *cmd_buff, uint8_t cmd_len, uint8_t *tx_buff, uint32_t tx_len) +{ + configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2); + volatile struct spi_t *spi_handle = spi[spi_bus]; + + uint32_t *buf = malloc((cmd_len + tx_len) * sizeof(uint32_t)); + int i; + for(i = 0; i < cmd_len; i++){ + buf[i] = cmd_buff[i]; + } + + for(i = 0; i < tx_len; i++){ + buf[cmd_len + i] = tx_buff[i]; + } + spi_handle->dmacr = 0x2; /*enable dma transmit*/ + spi_handle->ssienr = 0x01; + + sysctl_dma_select(channel_num, SYSCTL_DMA_SELECT_SSI0_TX_REQ + spi_bus * 2); + dmac_set_single_mode(channel_num, buf, (void *)(&spi_handle->dr[0]), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, cmd_len + tx_len); + spi_handle->ser = chip_sel; + dmac_wait_done(channel_num); + free((void*)buf); + + while ((spi_handle->sr & 0x05) != 0x04) + ; + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; + return 0; +} + +int spi_fill_dma(dmac_channel_number channel_num,uint8_t spi_bus, uint32_t chip_sel, + uint32_t *cmd_buff, uint32_t cmd_len) +{ + configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2); + volatile struct spi_t *spi_handle = spi[spi_bus]; + + spi_handle->dmacr = 0x2; /*enable dma transmit*/ + spi_handle->ssienr = 0x01; + + sysctl_dma_select(channel_num, SYSCTL_DMA_SELECT_SSI0_TX_REQ + spi_bus * 2); + dmac_set_single_mode(channel_num, cmd_buff, (void *)(&spi_handle->dr[0]), DMAC_ADDR_NOCHANGE, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, cmd_len); + spi_handle->ser = chip_sel; + dmac_wait_done(channel_num); + + while ((spi_handle->sr & 0x05) != 0x04) + ; + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; + return 0; +} + +void spi_set_tmod(uint8_t spi_bus, uint32_t tmod) +{ + configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2); + volatile struct spi_t *spi_handle = spi[spi_bus]; + uint8_t tmod_offset = 0; + switch(spi_bus){ + case 0: + case 1: + tmod_offset = 8; + break; + case 2: + configASSERT(!"Spi Bus 2 Not Support!"); + break; + case 3: + default: + tmod_offset = 10; + break; + } + + set_bit(&spi_handle->ctrlr0, 3 << tmod_offset, tmod << tmod_offset); +} + +void spi_set_frame_format(uint8_t spi_bus, uint32_t spi_frf) +{ + configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2); + volatile struct spi_t *spi_handle = spi[spi_bus]; + uint8_t frf_offset = 0; + switch(spi_bus){ + case 0: + case 1: + frf_offset = 21; + break; + case 2: + configASSERT(!"Spi Bus 2 Not Support!"); + break; + case 3: + default: + frf_offset = 22; + break; + } + + set_bit(&spi_handle->ctrlr0, 3 << frf_offset, spi_frf << frf_offset); +} + +int spi_get_frame_format(uint8_t spi_bus) +{ + configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2); + volatile struct spi_t *spi_handle = spi[spi_bus]; + uint8_t frf_offset = 0; + switch(spi_bus){ + case 0: + case 1: + frf_offset = 21; + break; + case 2: + configASSERT(!"Spi Bus 2 Not Support!"); + break; + case 3: + default: + frf_offset = 22; + break; + } + return ((spi_handle->ctrlr0 >> frf_offset) & 0x03); +} + +/* + SPI MODE0-3 + Serial Clock Polarity + Serial Clock Phase +*/ +void spi_set_work_mode(uint8_t spi_bus, spi_mode mode) +{ + configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2); + volatile struct spi_t *spi_handle = spi[spi_bus]; + set_bit(&spi_handle->ctrlr0, 0x3 << 6, mode << 6); +} + +void spi_set_frame_size(uint8_t spi_bus, uint32_t dfs) +{ + configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2); + volatile struct spi_t *spi_handle = spi[spi_bus]; + + uint8_t dfs_offset; + switch(spi_bus){ + case 0: + case 1: + dfs_offset = 16; + break; + case 2: + configASSERT(!"Spi Bus 2 Not Support!"); + break; + case 3: + default: + dfs_offset = 0; + break; + } + int frame_format = spi_get_frame_format(spi_bus); + switch (frame_format) + { + case SPI_FF_DUAL: + configASSERT(dfs % 2 == 0); + break; + case SPI_FF_QUAD: + configASSERT(dfs % 4 == 0); + break; + case SPI_FF_OCTAL: + configASSERT(dfs % 8 == 0); + break; + default: + break; + } + set_bit(&spi_handle->ctrlr0, 0x1F << dfs_offset, (dfs-1) << dfs_offset); +} + +void spi_set_wait_cycles(uint8_t spi_bus, uint32_t wcycles) +{ + configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2); + configASSERT(wcycles < (1 << 5)); + int frame_format = spi_get_frame_format(spi_bus); + configASSERT(frame_format != SPI_FF_STANDARD); + volatile struct spi_t *spi_handle = spi[spi_bus]; + + set_bit(&spi_handle->spi_ctrlr0, 0x1F << 11, wcycles << 11); +} + +void spi_set_inst_length(uint8_t spi_bus, uint32_t instruction_length) +{ + configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2); + int frame_format = spi_get_frame_format(spi_bus); + configASSERT(frame_format != SPI_FF_STANDARD); + volatile struct spi_t *spi_handle = spi[spi_bus]; + + uint32_t inst_l = 0; + switch (instruction_length) + { + case 0: + inst_l = 0; + break; + case 4: + inst_l = 1; + break; + case 8: + inst_l = 2; + break; + case 16: + inst_l = 3; + break; + default: + configASSERT("Invalid instruction length"); + break; + } + + set_bit(&spi_handle->spi_ctrlr0, 0x3 << 8, inst_l << 8); +} + +void spi_set_address_length(uint8_t spi_bus, uint32_t address_length) +{ + configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2); + int frame_format = spi_get_frame_format(spi_bus); + configASSERT(frame_format != SPI_FF_STANDARD); + configASSERT(address_length % 4 == 0 && address_length <= 60); + volatile struct spi_t *spi_handle = spi[spi_bus]; + uint32_t addr_l = address_length / 4; + set_bit(&spi_handle->spi_ctrlr0, 0xF << 2, addr_l << 2); +} + +void spi_set_trans_mode(uint8_t spi_bus, spi_addr_inst_trans_mode trans_mode) +{ + configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2); + int frame_format = spi_get_frame_format(spi_bus); + configASSERT(frame_format != SPI_FF_STANDARD); + volatile struct spi_t *spi_handle = spi[spi_bus]; + set_bit(&spi_handle->spi_ctrlr0, 0x3 << 0, trans_mode << 0); +} + diff --git a/lib/drivers/sysclock.c b/lib/drivers/sysclock.c new file mode 100644 index 0000000..36bd89a --- /dev/null +++ b/lib/drivers/sysclock.c @@ -0,0 +1,69 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "sysclock.h" +#include "stdio.h" +#include "sysctl.h" +#include "uarths.h" + +void sys_clock_init() +{ + sysctl_clock_set_clock_select(SYSCTL_CLOCK_SELECT_ACLK, SYSCTL_SOURCE_IN0); + + sysctl_pll_enable(SYSCTL_PLL0); + sysctl_pll_set_freq(SYSCTL_PLL0, SYSCTL_SOURCE_IN0, PLL0_OUTPUT_FREQ); + while (sysctl_pll_is_lock(SYSCTL_PLL0) == 0) + sysctl_pll_clear_slip(SYSCTL_PLL0); + sysctl_clock_enable(SYSCTL_CLOCK_PLL0); + sysctl->clk_sel0.aclk_divider_sel = 0; + sysctl_clock_set_clock_select(SYSCTL_CLOCK_SELECT_ACLK, SYSCTL_SOURCE_PLL0); + + sysctl_pll_enable(SYSCTL_PLL1); + sysctl_pll_set_freq(SYSCTL_PLL1, SYSCTL_SOURCE_IN0, PLL1_OUTPUT_FREQ); + while (sysctl_pll_is_lock(SYSCTL_PLL1) == 0) + sysctl_pll_clear_slip(SYSCTL_PLL1); + sysctl_clock_enable(SYSCTL_CLOCK_PLL1); + + sysctl_pll_enable(SYSCTL_PLL2); + sysctl_pll_set_freq(SYSCTL_PLL2, SYSCTL_SOURCE_IN0, PLL2_OUTPUT_FREQ); + while (sysctl_pll_is_lock(SYSCTL_PLL2) == 0) + sysctl_pll_clear_slip(SYSCTL_PLL2); + sysctl_clock_enable(SYSCTL_CLOCK_PLL2); +} + +uint32_t system_set_cpu_frequency(uint32_t frequency) +{ + sysctl_clock_set_clock_select(SYSCTL_CLOCK_SELECT_ACLK, SYSCTL_SOURCE_IN0); + sysctl->pll0.pll_reset0 = 1; + + uint32_t result = sysctl_pll_set_freq(SYSCTL_PLL0, SYSCTL_SOURCE_IN0, frequency * 2); + sysctl->pll0.pll_reset0 = 0; + while (1) + { + uint32_t lock = sysctl->pll_lock.pll_lock0 & 0x3; + if (lock == 0x3) + { + break; + } + else + { + sysctl->pll_lock.pll_slip_clear0 = 1; + } + } + + sysctl->pll0.pll_out_en0 = 1; + sysctl_clock_set_clock_select(SYSCTL_CLOCK_SELECT_ACLK, SYSCTL_SOURCE_PLL0); + uart_init(); + return result; +} diff --git a/lib/drivers/sysctl.c b/lib/drivers/sysctl.c new file mode 100644 index 0000000..003b472 --- /dev/null +++ b/lib/drivers/sysctl.c @@ -0,0 +1,1726 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include "sysctl.h" + +#define SYSCTRL_CLOCK_FREQ_IN0 (26000000UL) + +const uint8_t get_select_pll2[] = +{ + [SYSCTL_SOURCE_IN0] = 0, + [SYSCTL_SOURCE_PLL0] = 1, + [SYSCTL_SOURCE_PLL1] = 2, +}; + +const uint8_t get_source_pll2[] = +{ + [0] = SYSCTL_SOURCE_IN0, + [1] = SYSCTL_SOURCE_PLL0, + [2] = SYSCTL_SOURCE_PLL1, +}; + +const uint8_t get_select_aclk[] = +{ + [SYSCTL_SOURCE_IN0] = 0, + [SYSCTL_SOURCE_PLL0] = 1, +}; + +const uint8_t get_source_aclk[] = +{ + [0] = SYSCTL_SOURCE_IN0, + [1] = SYSCTL_SOURCE_PLL0, +}; + +volatile struct sysctl_t *const sysctl = (volatile struct sysctl_t *)SYSCTL_BASE_ADDR; + +uint32_t sysctl_get_git_id(void) +{ + return sysctl->git_id.git_id; +} + +uint32_t sysctl_get_freq(void) +{ + return sysctl->clk_freq.clk_freq; +} + +static void sysctl_reset_ctl(enum sysctl_reset_e reset, uint8_t rst_value) +{ + switch (reset) + { + case SYSCTL_RESET_SOC: + sysctl->soft_reset.soft_reset = rst_value; + break; + case SYSCTL_RESET_ROM: + sysctl->peri_reset.rom_reset = rst_value; + break; + case SYSCTL_RESET_DMA: + sysctl->peri_reset.dma_reset = rst_value; + break; + case SYSCTL_RESET_AI: + sysctl->peri_reset.ai_reset = rst_value; + break; + case SYSCTL_RESET_DVP: + sysctl->peri_reset.dvp_reset = rst_value; + break; + case SYSCTL_RESET_FFT: + sysctl->peri_reset.fft_reset = rst_value; + break; + case SYSCTL_RESET_GPIO: + sysctl->peri_reset.gpio_reset = rst_value; + break; + case SYSCTL_RESET_SPI0: + sysctl->peri_reset.spi0_reset = rst_value; + break; + case SYSCTL_RESET_SPI1: + sysctl->peri_reset.spi1_reset = rst_value; + break; + case SYSCTL_RESET_SPI2: + sysctl->peri_reset.spi2_reset = rst_value; + break; + case SYSCTL_RESET_SPI3: + sysctl->peri_reset.spi3_reset = rst_value; + break; + case SYSCTL_RESET_I2S0: + sysctl->peri_reset.i2s0_reset = rst_value; + break; + case SYSCTL_RESET_I2S1: + sysctl->peri_reset.i2s1_reset = rst_value; + break; + case SYSCTL_RESET_I2S2: + sysctl->peri_reset.i2s2_reset = rst_value; + break; + case SYSCTL_RESET_I2C0: + sysctl->peri_reset.i2c0_reset = rst_value; + break; + case SYSCTL_RESET_I2C1: + sysctl->peri_reset.i2c1_reset = rst_value; + break; + case SYSCTL_RESET_I2C2: + sysctl->peri_reset.i2c2_reset = rst_value; + break; + case SYSCTL_RESET_UART1: + sysctl->peri_reset.uart1_reset = rst_value; + break; + case SYSCTL_RESET_UART2: + sysctl->peri_reset.uart2_reset = rst_value; + break; + case SYSCTL_RESET_UART3: + sysctl->peri_reset.uart3_reset = rst_value; + break; + case SYSCTL_RESET_AES: + sysctl->peri_reset.aes_reset = rst_value; + break; + case SYSCTL_RESET_FPIOA: + sysctl->peri_reset.fpioa_reset = rst_value; + break; + case SYSCTL_RESET_TIMER0: + sysctl->peri_reset.timer0_reset = rst_value; + break; + case SYSCTL_RESET_TIMER1: + sysctl->peri_reset.timer1_reset = rst_value; + break; + case SYSCTL_RESET_TIMER2: + sysctl->peri_reset.timer2_reset = rst_value; + break; + case SYSCTL_RESET_WDT0: + sysctl->peri_reset.wdt0_reset = rst_value; + break; + case SYSCTL_RESET_WDT1: + sysctl->peri_reset.wdt1_reset = rst_value; + break; + case SYSCTL_RESET_SHA: + sysctl->peri_reset.sha_reset = rst_value; + break; + case SYSCTL_RESET_RTC: + sysctl->peri_reset.rtc_reset = rst_value; + break; + + default: + break; + } +} + +void sysctl_reset(enum sysctl_reset_e reset) +{ + sysctl_reset_ctl(reset, 1); + sysctl_reset_ctl(reset, 0); +} + +static int sysctl_clock_bus_en(enum sysctl_clock_e clock, uint8_t en) +{ + /* + * The timer is under APB0, to prevent apb0_clk_en1 and apb0_clk_en0 + * on same register, we split it to peripheral and central two + * registers, to protect CPU close apb0 clock accidentally. + * + * The apb0_clk_en0 and apb0_clk_en1 have same function, + * one of them set, the APB0 clock enable. + */ + + /* The APB clock should carefully disable */ + if (en) + { + switch (clock) + { + /* + * These peripheral devices are under APB0 + * GPIO, UART1, UART2, UART3, SPI_SLAVE, I2S0, I2S1, + * I2S2, I2C0, I2C1, I2C2, FPIOA, SHA256, TIMER0, + * TIMER1, TIMER2 + */ + case SYSCTL_CLOCK_GPIO: + case SYSCTL_CLOCK_SPI2: + case SYSCTL_CLOCK_I2S0: + case SYSCTL_CLOCK_I2S1: + case SYSCTL_CLOCK_I2S2: + case SYSCTL_CLOCK_I2C0: + case SYSCTL_CLOCK_I2C1: + case SYSCTL_CLOCK_I2C2: + case SYSCTL_CLOCK_UART1: + case SYSCTL_CLOCK_UART2: + case SYSCTL_CLOCK_UART3: + case SYSCTL_CLOCK_FPIOA: + case SYSCTL_CLOCK_TIMER0: + case SYSCTL_CLOCK_TIMER1: + case SYSCTL_CLOCK_TIMER2: + case SYSCTL_CLOCK_SHA: + sysctl->clk_en_cent.apb0_clk_en = en; + break; + + /* + * These peripheral devices are under APB1 + * WDT, AES, OTP, DVP, SYSCTL + */ + case SYSCTL_CLOCK_AES: + case SYSCTL_CLOCK_WDT0: + case SYSCTL_CLOCK_WDT1: + case SYSCTL_CLOCK_OTP: + case SYSCTL_CLOCK_RTC: + sysctl->clk_en_cent.apb1_clk_en = en; + break; + + /* + * These peripheral devices are under APB2 + * SPI0, SPI1 + */ + case SYSCTL_CLOCK_SPI0: + case SYSCTL_CLOCK_SPI1: + sysctl->clk_en_cent.apb2_clk_en = en; + break; + + default: + break; + } + } + + return 0; +} + +static int sysctl_clock_device_en(enum sysctl_clock_e clock, uint8_t en) +{ + switch (clock) + { + /* + * These devices are PLL + */ + case SYSCTL_CLOCK_PLL0: + sysctl->pll0.pll_out_en0 = en; + break; + case SYSCTL_CLOCK_PLL1: + sysctl->pll1.pll_out_en1 = en; + break; + case SYSCTL_CLOCK_PLL2: + sysctl->pll2.pll_out_en2 = en; + break; + + /* + * These devices are CPU, SRAM, APB bus, ROM, DMA, AI + */ + case SYSCTL_CLOCK_CPU: + sysctl->clk_en_cent.cpu_clk_en = en; + break; + case SYSCTL_CLOCK_SRAM0: + sysctl->clk_en_cent.sram0_clk_en = en; + break; + case SYSCTL_CLOCK_SRAM1: + sysctl->clk_en_cent.sram1_clk_en = en; + break; + case SYSCTL_CLOCK_APB0: + sysctl->clk_en_cent.apb0_clk_en = en; + break; + case SYSCTL_CLOCK_APB1: + sysctl->clk_en_cent.apb1_clk_en = en; + break; + case SYSCTL_CLOCK_APB2: + sysctl->clk_en_cent.apb2_clk_en = en; + break; + case SYSCTL_CLOCK_ROM: + sysctl->clk_en_peri.rom_clk_en = en; + break; + case SYSCTL_CLOCK_DMA: + sysctl->clk_en_peri.dma_clk_en = en; + break; + case SYSCTL_CLOCK_AI: + sysctl->clk_en_peri.ai_clk_en = en; + break; + case SYSCTL_CLOCK_DVP: + sysctl->clk_en_peri.dvp_clk_en = en; + break; + case SYSCTL_CLOCK_FFT: + sysctl->clk_en_peri.fft_clk_en = en; + break; + case SYSCTL_CLOCK_SPI3: + sysctl->clk_en_peri.spi3_clk_en = en; + break; + + /* + * These peripheral devices are under APB0 + * GPIO, UART1, UART2, UART3, SPI_SLAVE, I2S0, I2S1, + * I2S2, I2C0, I2C1, I2C2, FPIOA, SHA256, TIMER0, + * TIMER1, TIMER2 + */ + case SYSCTL_CLOCK_GPIO: + sysctl->clk_en_peri.gpio_clk_en = en; + break; + case SYSCTL_CLOCK_SPI2: + sysctl->clk_en_peri.spi2_clk_en = en; + break; + case SYSCTL_CLOCK_I2S0: + sysctl->clk_en_peri.i2s0_clk_en = en; + break; + case SYSCTL_CLOCK_I2S1: + sysctl->clk_en_peri.i2s1_clk_en = en; + break; + case SYSCTL_CLOCK_I2S2: + sysctl->clk_en_peri.i2s2_clk_en = en; + break; + case SYSCTL_CLOCK_I2C0: + sysctl->clk_en_peri.i2c0_clk_en = en; + break; + case SYSCTL_CLOCK_I2C1: + sysctl->clk_en_peri.i2c1_clk_en = en; + break; + case SYSCTL_CLOCK_I2C2: + sysctl->clk_en_peri.i2c2_clk_en = en; + break; + case SYSCTL_CLOCK_UART1: + sysctl->clk_en_peri.uart1_clk_en = en; + break; + case SYSCTL_CLOCK_UART2: + sysctl->clk_en_peri.uart2_clk_en = en; + break; + case SYSCTL_CLOCK_UART3: + sysctl->clk_en_peri.uart3_clk_en = en; + break; + case SYSCTL_CLOCK_FPIOA: + sysctl->clk_en_peri.fpioa_clk_en = en; + break; + case SYSCTL_CLOCK_TIMER0: + sysctl->clk_en_peri.timer0_clk_en = en; + break; + case SYSCTL_CLOCK_TIMER1: + sysctl->clk_en_peri.timer1_clk_en = en; + break; + case SYSCTL_CLOCK_TIMER2: + sysctl->clk_en_peri.timer2_clk_en = en; + break; + case SYSCTL_CLOCK_SHA: + sysctl->clk_en_peri.sha_clk_en = en; + break; + + /* + * These peripheral devices are under APB1 + * WDT, AES, OTP, DVP, SYSCTL + */ + case SYSCTL_CLOCK_AES: + sysctl->clk_en_peri.aes_clk_en = en; + break; + case SYSCTL_CLOCK_WDT0: + sysctl->clk_en_peri.wdt0_clk_en = en; + break; + case SYSCTL_CLOCK_WDT1: + sysctl->clk_en_peri.wdt1_clk_en = en; + break; + case SYSCTL_CLOCK_OTP: + sysctl->clk_en_peri.otp_clk_en = en; + break; + case SYSCTL_CLOCK_RTC: + sysctl->clk_en_peri.rtc_clk_en = en; + break; + + /* + * These peripheral devices are under APB2 + * SPI0, SPI1 + */ + case SYSCTL_CLOCK_SPI0: + sysctl->clk_en_peri.spi0_clk_en = en; + break; + case SYSCTL_CLOCK_SPI1: + sysctl->clk_en_peri.spi1_clk_en = en; + break; + + default: + break; + } + + return 0; +} + +int sysctl_clock_enable(enum sysctl_clock_e clock) +{ + if (clock >= SYSCTL_CLOCK_MAX) + return -1; + sysctl_clock_bus_en(clock, 1); + sysctl_clock_device_en(clock, 1); + return 0; +} + +int sysctl_clock_disable(enum sysctl_clock_e clock) +{ + if (clock >= SYSCTL_CLOCK_MAX) + return -1; + sysctl_clock_bus_en(clock, 0); + sysctl_clock_device_en(clock, 0); + return 0; +} + +int sysctl_clock_set_threshold(enum sysctl_threshold_e which, int threshold) +{ + switch (which) + { + /* + * These threshold is 3 bit width + */ + case SYSCTL_THRESHOLD_APB0: + sysctl->clk_sel0.apb0_clk_sel = (uint8_t)threshold & 0x07; + break; + case SYSCTL_THRESHOLD_APB1: + sysctl->clk_sel0.apb1_clk_sel = (uint8_t)threshold & 0x07; + break; + case SYSCTL_THRESHOLD_APB2: + sysctl->clk_sel0.apb2_clk_sel = (uint8_t)threshold & 0x07; + break; + + /* + * These threshold is 4 bit width + */ + case SYSCTL_THRESHOLD_SRAM0: + sysctl->clk_th0.sram0_gclk_threshold = (uint8_t)threshold & 0x0F; + break; + case SYSCTL_THRESHOLD_SRAM1: + sysctl->clk_th0.sram1_gclk_threshold = (uint8_t)threshold & 0x0F; + break; + case SYSCTL_THRESHOLD_AI: + sysctl->clk_th0.ai_gclk_threshold = (uint8_t)threshold & 0x0F; + break; + case SYSCTL_THRESHOLD_DVP: + sysctl->clk_th0.dvp_gclk_threshold = (uint8_t)threshold & 0x0F; + break; + case SYSCTL_THRESHOLD_ROM: + sysctl->clk_th0.rom_gclk_threshold = (uint8_t)threshold & 0x0F; + break; + + /* + * These threshold is 8 bit width + */ + case SYSCTL_THRESHOLD_SPI0: + sysctl->clk_th1.spi0_clk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_SPI1: + sysctl->clk_th1.spi1_clk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_SPI2: + sysctl->clk_th1.spi2_clk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_SPI3: + sysctl->clk_th1.spi3_clk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_TIMER0: + sysctl->clk_th2.timer0_clk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_TIMER1: + sysctl->clk_th2.timer1_clk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_TIMER2: + sysctl->clk_th2.timer2_clk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_I2S0_M: + sysctl->clk_th4.i2s0_mclk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_I2S1_M: + sysctl->clk_th4.i2s1_mclk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_I2S2_M: + sysctl->clk_th5.i2s2_mclk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_I2C0: + sysctl->clk_th5.i2c0_clk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_I2C1: + sysctl->clk_th5.i2c1_clk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_I2C2: + sysctl->clk_th5.i2c2_clk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_WDT0: + sysctl->clk_th6.wdt0_clk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_WDT1: + sysctl->clk_th6.wdt1_clk_threshold = (uint8_t)threshold; + break; + + /* + * These threshold is 16 bit width + */ + case SYSCTL_THRESHOLD_I2S0: + sysctl->clk_th3.i2s0_clk_threshold = (uint16_t)threshold; + break; + case SYSCTL_THRESHOLD_I2S1: + sysctl->clk_th3.i2s1_clk_threshold = (uint16_t)threshold; + break; + case SYSCTL_THRESHOLD_I2S2: + sysctl->clk_th4.i2s2_clk_threshold = (uint16_t)threshold; + break; + + default: + break; + } + + return 0; +} + +int sysctl_clock_get_threshold(enum sysctl_threshold_e which) +{ + int threshold = 0; + + switch (which) + { + /* + * Select and get threshold value + */ + case SYSCTL_THRESHOLD_ACLK: + threshold = (int)sysctl->clk_sel0.aclk_divider_sel; + break; + case SYSCTL_THRESHOLD_APB0: + threshold = (int)sysctl->clk_sel0.apb0_clk_sel; + break; + case SYSCTL_THRESHOLD_APB1: + threshold = (int)sysctl->clk_sel0.apb1_clk_sel; + break; + case SYSCTL_THRESHOLD_APB2: + threshold = (int)sysctl->clk_sel0.apb2_clk_sel; + break; + case SYSCTL_THRESHOLD_SRAM0: + threshold = (int)sysctl->clk_th0.sram0_gclk_threshold; + break; + case SYSCTL_THRESHOLD_SRAM1: + threshold = (int)sysctl->clk_th0.sram1_gclk_threshold; + break; + case SYSCTL_THRESHOLD_AI: + threshold = (int)sysctl->clk_th0.ai_gclk_threshold; + break; + case SYSCTL_THRESHOLD_DVP: + threshold = (int)sysctl->clk_th0.dvp_gclk_threshold; + break; + case SYSCTL_THRESHOLD_ROM: + threshold = (int)sysctl->clk_th0.rom_gclk_threshold; + break; + case SYSCTL_THRESHOLD_SPI0: + threshold = (int)sysctl->clk_th1.spi0_clk_threshold; + break; + case SYSCTL_THRESHOLD_SPI1: + threshold = (int)sysctl->clk_th1.spi1_clk_threshold; + break; + case SYSCTL_THRESHOLD_SPI2: + threshold = (int)sysctl->clk_th1.spi2_clk_threshold; + break; + case SYSCTL_THRESHOLD_SPI3: + threshold = (int)sysctl->clk_th1.spi3_clk_threshold; + break; + case SYSCTL_THRESHOLD_TIMER0: + threshold = (int)sysctl->clk_th2.timer0_clk_threshold; + break; + case SYSCTL_THRESHOLD_TIMER1: + threshold = (int)sysctl->clk_th2.timer1_clk_threshold; + break; + case SYSCTL_THRESHOLD_TIMER2: + threshold = (int)sysctl->clk_th2.timer2_clk_threshold; + break; + case SYSCTL_THRESHOLD_I2S0: + threshold = (int)sysctl->clk_th3.i2s0_clk_threshold; + break; + case SYSCTL_THRESHOLD_I2S1: + threshold = (int)sysctl->clk_th3.i2s1_clk_threshold; + break; + case SYSCTL_THRESHOLD_I2S2: + threshold = (int)sysctl->clk_th4.i2s2_clk_threshold; + break; + case SYSCTL_THRESHOLD_I2S0_M: + threshold = (int)sysctl->clk_th4.i2s0_mclk_threshold; + break; + case SYSCTL_THRESHOLD_I2S1_M: + threshold = (int)sysctl->clk_th4.i2s1_mclk_threshold; + break; + case SYSCTL_THRESHOLD_I2S2_M: + threshold = (int)sysctl->clk_th5.i2s2_mclk_threshold; + break; + case SYSCTL_THRESHOLD_I2C0: + threshold = (int)sysctl->clk_th5.i2c0_clk_threshold; + break; + case SYSCTL_THRESHOLD_I2C1: + threshold = (int)sysctl->clk_th5.i2c1_clk_threshold; + break; + case SYSCTL_THRESHOLD_I2C2: + threshold = (int)sysctl->clk_th5.i2c2_clk_threshold; + break; + case SYSCTL_THRESHOLD_WDT0: + threshold = (int)sysctl->clk_th6.wdt0_clk_threshold; + break; + case SYSCTL_THRESHOLD_WDT1: + threshold = (int)sysctl->clk_th6.wdt1_clk_threshold; + break; + + default: + break; + } + + return threshold; +} + +int sysctl_clock_set_clock_select(enum sysctl_clock_select_e which, int select) +{ + switch (which) + { + /* + * These clock select is 1 bit width + */ + case SYSCTL_CLOCK_SELECT_PLL0_BYPASS: + sysctl->pll0.pll_bypass0 = select & 0x01; + break; + case SYSCTL_CLOCK_SELECT_PLL1_BYPASS: + sysctl->pll1.pll_bypass1 = select & 0x01; + break; + case SYSCTL_CLOCK_SELECT_PLL3_BYPASS: + sysctl->pll2.pll_bypass2 = select & 0x01; + break; + case SYSCTL_CLOCK_SELECT_ACLK: + sysctl->clk_sel0.aclk_sel = select & 0x01; + break; + case SYSCTL_CLOCK_SELECT_SPI3: + sysctl->clk_sel0.spi3_clk_sel = select & 0x01; + break; + case SYSCTL_CLOCK_SELECT_TIMER0: + sysctl->clk_sel0.timer0_clk_sel = select & 0x01; + break; + case SYSCTL_CLOCK_SELECT_TIMER1: + sysctl->clk_sel0.timer1_clk_sel = select & 0x01; + break; + case SYSCTL_CLOCK_SELECT_TIMER2: + sysctl->clk_sel0.timer2_clk_sel = select & 0x01; + break; + case SYSCTL_CLOCK_SELECT_SPI3_SAMPLE: + sysctl->clk_sel1.spi3_sample_clk_sel = select & 0x01; + break; + + /* + * These clock select is 2 bit width + */ + case SYSCTL_CLOCK_SELECT_PLL2: + sysctl->pll2.pll_ckin_sel2 = select & 0x03; + break; + + default: + break; + } + + return 0; +} + +int sysctl_clock_get_clock_select(enum sysctl_clock_select_e which) +{ + int clock_select = 0; + + switch (which) + { + /* + * Select and get clock select value + */ + case SYSCTL_CLOCK_SELECT_PLL0_BYPASS: + clock_select = (int)sysctl->pll0.pll_bypass0; + break; + case SYSCTL_CLOCK_SELECT_PLL1_BYPASS: + clock_select = (int)sysctl->pll1.pll_bypass1; + break; + case SYSCTL_CLOCK_SELECT_PLL3_BYPASS: + clock_select = (int)sysctl->pll2.pll_bypass2; + break; + case SYSCTL_CLOCK_SELECT_PLL2: + clock_select = (int)sysctl->pll2.pll_ckin_sel2; + break; + case SYSCTL_CLOCK_SELECT_ACLK: + clock_select = (int)sysctl->clk_sel0.aclk_sel; + break; + case SYSCTL_CLOCK_SELECT_SPI3: + clock_select = (int)sysctl->clk_sel0.spi3_clk_sel; + break; + case SYSCTL_CLOCK_SELECT_TIMER0: + clock_select = (int)sysctl->clk_sel0.timer0_clk_sel; + break; + case SYSCTL_CLOCK_SELECT_TIMER1: + clock_select = (int)sysctl->clk_sel0.timer1_clk_sel; + break; + case SYSCTL_CLOCK_SELECT_TIMER2: + clock_select = (int)sysctl->clk_sel0.timer2_clk_sel; + break; + case SYSCTL_CLOCK_SELECT_SPI3_SAMPLE: + clock_select = (int)sysctl->clk_sel1.spi3_sample_clk_sel; + break; + + default: + break; + } + + return clock_select; +} + +uint32_t sysctl_clock_source_get_freq(enum sysctl_clock_source_e input) +{ + uint32_t result; + + switch (input) + { + case SYSCTL_SOURCE_IN0: + result = SYSCTRL_CLOCK_FREQ_IN0; + break; + case SYSCTL_SOURCE_PLL0: + result = sysctl_pll_get_freq(SYSCTL_PLL0); + break; + case SYSCTL_SOURCE_PLL1: + result = sysctl_pll_get_freq(SYSCTL_PLL1); + break; + case SYSCTL_SOURCE_PLL2: + result = sysctl_pll_get_freq(SYSCTL_PLL2); + break; + case SYSCTL_SOURCE_ACLK: + result = sysctl_clock_get_freq(SYSCTL_CLOCK_ACLK); + break; + + default: + result = 0; + break; + } + return result; +} + +int sysctl_pll_is_lock(enum sysctl_pll_e pll) +{ + /* + * All bit enable means PLL lock + * + * struct pll_lock_t + * { + * uint8_t overflow : 1; + * uint8_t rfslip : 1; + * uint8_t fbslip : 1; + * }; + * + */ + + uint8_t lock = 0; + + if (pll >= SYSCTL_PLL_MAX) + return 0; + + switch (pll) + { + case SYSCTL_PLL0: + lock = sysctl->pll_lock.pll_lock0; + break; + + case SYSCTL_PLL1: + lock = sysctl->pll_lock.pll_lock1; + break; + + case SYSCTL_PLL2: + lock = sysctl->pll_lock.pll_lock2; + break; + + default: + break; + } + + if (lock == 3) + return 1; + + return 0; +} + +int sysctl_pll_clear_slip(enum sysctl_pll_e pll) +{ + if (pll >= SYSCTL_PLL_MAX) + return -1; + + switch (pll) + { + case SYSCTL_PLL0: + sysctl->pll_lock.pll_slip_clear0 = 1; + break; + + case SYSCTL_PLL1: + sysctl->pll_lock.pll_slip_clear1 = 1; + break; + + case SYSCTL_PLL2: + sysctl->pll_lock.pll_slip_clear2 = 1; + break; + + default: + break; + } + + return sysctl_pll_is_lock(pll) ? 0 : -1; +} + +int sysctl_pll_enable(enum sysctl_pll_e pll) +{ + /* + * ---+ + * PWRDN | + * +------------------------------------------------------------- + * ^ + * | + * | + * t1 + * +------------------+ + * RESET | | + * ----------+ +----------------------------------- + * ^ ^ ^ + * |<----- t_rst ---->|<---------- t_lock ---------->| + * | | | + * t2 t3 t4 + */ + + if (pll >= SYSCTL_PLL_MAX) + return -1; + + switch (pll) + { + case SYSCTL_PLL0: + /* Do not bypass PLL */ + sysctl->pll0.pll_bypass0 = 0; + /* + * Power on the PLL, negtive from PWRDN + * 0 is power off + * 1 is power on + */ + sysctl->pll0.pll_pwrd0 = 1; + /* + * Reset trigger of the PLL, connected RESET + * 0 is free + * 1 is reset + */ + sysctl->pll0.pll_reset0 = 0; + sysctl->pll0.pll_reset0 = 1; + sysctl->pll0.pll_reset0 = 0; + break; + + case SYSCTL_PLL1: + /* Do not bypass PLL */ + sysctl->pll1.pll_bypass1 = 0; + /* + * Power on the PLL, negtive from PWRDN + * 0 is power off + * 1 is power on + */ + sysctl->pll1.pll_pwrd1 = 1; + /* + * Reset trigger of the PLL, connected RESET + * 0 is free + * 1 is reset + */ + sysctl->pll1.pll_reset1 = 0; + sysctl->pll1.pll_reset1 = 1; + sysctl->pll1.pll_reset1 = 0; + break; + + case SYSCTL_PLL2: + /* Do not bypass PLL */ + sysctl->pll2.pll_bypass2 = 0; + /* + * Power on the PLL, negtive from PWRDN + * 0 is power off + * 1 is power on + */ + sysctl->pll2.pll_pwrd2 = 1; + /* + * Reset trigger of the PLL, connected RESET + * 0 is free + * 1 is reset + */ + sysctl->pll2.pll_reset2 = 0; + sysctl->pll2.pll_reset2 = 1; + sysctl->pll2.pll_reset2 = 0; + break; + + default: + break; + } + + return 0; +} + +int sysctl_pll_disable(enum sysctl_pll_e pll) +{ + if (pll >= SYSCTL_PLL_MAX) + return -1; + + switch (pll) + { + case SYSCTL_PLL0: + /* Bypass PLL */ + sysctl->pll0.pll_bypass0 = 1; + /* + * Power on the PLL, negtive from PWRDN + * 0 is power off + * 1 is power on + */ + sysctl->pll0.pll_pwrd0 = 0; + break; + + case SYSCTL_PLL1: + /* Bypass PLL */ + sysctl->pll1.pll_bypass1 = 1; + /* + * Power on the PLL, negtive from PWRDN + * 0 is power off + * 1 is power on + */ + sysctl->pll1.pll_pwrd1 = 0; + break; + + case SYSCTL_PLL2: + /* Bypass PLL */ + sysctl->pll2.pll_bypass2 = 1; + /* + * Power on the PLL, negtive from PWRDN + * 0 is power off + * 1 is power on + */ + sysctl->pll2.pll_pwrd2 = 0; + break; + + default: + break; + } + + return 0; +} + +uint32_t sysctl_pll_get_freq(enum sysctl_pll_e pll) +{ + uint32_t freq_in = 0, freq_out = 0; + uint32_t nr = 0, nf = 0, od = 0; + uint8_t select = 0; + + if (pll >= SYSCTL_PLL_MAX) + return 0; + + switch (pll) + { + case SYSCTL_PLL0: + freq_in = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + nr = sysctl->pll0.clkr0 + 1; + nf = sysctl->pll0.clkf0 + 1; + od = sysctl->pll0.clkod0 + 1; + break; + + case SYSCTL_PLL1: + freq_in = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + nr = sysctl->pll1.clkr1 + 1; + nf = sysctl->pll1.clkf1 + 1; + od = sysctl->pll1.clkod1 + 1; + break; + + case SYSCTL_PLL2: + /* + * Get input frequency accroding select register + */ + select = sysctl->pll2.pll_ckin_sel2; + if (select < sizeof(get_source_pll2)) + freq_in = sysctl_clock_source_get_freq(get_source_pll2[select]); + else + return 0; + + nr = sysctl->pll2.clkr2 + 1; + nf = sysctl->pll2.clkf2 + 1; + od = sysctl->pll2.clkod2 + 1; + break; + + default: + break; + } + + /* + * Get final PLL output frequency + * FOUT = FIN / NR * NF / OD + */ + freq_out = (double)freq_in / (double)nr * (double)nf / (double)od; + return freq_out; +} + +uint32_t sysctl_pll_set_freq(enum sysctl_pll_e pll, enum sysctl_clock_source_e source, uint32_t freq) +{ + uint32_t freq_in = 0; + + if (pll >= SYSCTL_PLL_MAX) + return 0; + + if (source >= SYSCTL_SOURCE_MAX) + return 0; + + switch (pll) + { + case SYSCTL_PLL0: + case SYSCTL_PLL1: + /* + * Check input clock source + */ + if (source != SYSCTL_SOURCE_IN0) + return 0; + freq_in = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + /* + * Check input clock frequency + */ + if (freq_in == 0) + return 0; + break; + + case SYSCTL_PLL2: + /* + * Check input clock source + */ + if (source < sizeof(get_select_pll2)) + freq_in = sysctl_clock_source_get_freq(source); + /* + * Check input clock frequency + */ + if (freq_in == 0) + return 0; + break; + + default: + return 0; + } + + /* + * Begin calculate PLL registers' value + */ + + /* constants */ + const double vco_min = 3.5e+08; + const double vco_max = 1.75e+09; + const double ref_min = 1.36719e+07; + const double ref_max = 1.75e+09; + const int nr_min = 1; + const int nr_max = 16; + const int nf_min = 1; + const int nf_max = 64; + const int no_min = 1; + const int no_max = 16; + const int nb_min = 1; + const int nb_max = 64; + const int max_vco = 1; + const int ref_rng = 1; + + /* variables */ + int nr = 0; + int nrx = 0; + int nf = 0; + int nfi = 0; + int no = 0; + int noe = 0; + int not = 0; + int nor = 0; + int nore = 0; + int nb = 0; + int first = 0; + int firstx = 0; + int found = 0; + + long long nfx = 0; + double fin = 0, fout = 0, fvco = 0; + double val = 0, nval = 0, err = 0, merr = 0, terr = 0; + int x_nrx = 0, x_no = 0, x_nb = 0; + long long x_nfx = 0; + double x_fvco = 0, x_err = 0; + + fin = freq_in; + fout = freq; + val = fout / fin; + terr = 0.5 / ((double)(nf_max / 2)); + first = firstx = 1; + if (terr == -1) + { + printf("NR\tNF\tOD\tNB\tFvco\t\terror\n"); + printf("------------------------------------------------------\n"); + } + else if (terr != -2) + { + first = 0; + if (terr == 0) + terr = 1e-16; + merr = fabs(terr); + } + found = 0; + for (nfi = val; nfi < nf_max; ++nfi) + { + nr = rint(((double)nfi) / val); + if (nr == 0) + continue; + if ((ref_rng) && (nr < nr_min)) + continue; + if (fin / ((double)nr) > ref_max) + continue; + nrx = nr; + nf = nfx = nfi; + nval = ((double)nfx) / ((double)nr); + if (nf == 0) + nf = 1; + err = 1 - nval / val; + + if ((first) || (fabs(err) < merr * (1 + 1e-6)) || (fabs(err) < 1e-16)) + { + not = floor(vco_max / fout); + for (no = (not > no_max) ? no_max : not; no > no_min; --no) + { + if ((ref_rng) && ((nr / no) < nr_min)) + continue; + if ((nr % no) == 0) + break; + } + if ((nr % no) != 0) + continue; + nor = ((not > no_max) ? no_max : not) / no; + nore = nf_max / nf; + if (nor > nore) + nor = nore; + noe = ceil(vco_min / fout); + if (!max_vco) + { + nore = (noe - 1) / no + 1; + nor = nore; + not = 0; /* force next if to fail */ + } + if ((((no * nor) < (not >> 1)) || ((no * nor) < noe)) && ((no * nor) < (nf_max / nf))) + { + no = nf_max / nf; + if (no > no_max) + no = no_max; + if (no > not) + no = not; + nfx *= no; + nf *= no; + if ((no > 1) && (!firstx)) + continue; + /* wait for larger nf in later iterations */ + } + else + { + nrx /= no; + nfx *= nor; + nf *= nor; + no *= nor; + if (no > no_max) + continue; + if ((nor > 1) && (!firstx)) + continue; + /* wait for larger nf in later iterations */ + } + + nb = nfx; + if (nb < nb_min) + nb = nb_min; + if (nb > nb_max) + continue; + + fvco = fin / ((double)nrx) * ((double)nfx); + if (fvco < vco_min) + continue; + if (fvco > vco_max) + continue; + if (nf < nf_min) + continue; + if ((ref_rng) && (fin / ((double)nrx) < ref_min)) + continue; + if ((ref_rng) && (nrx > nr_max)) + continue; + if (!(((firstx) && (terr < 0)) || (fabs(err) < merr * (1 - 1e-6)) || ((max_vco) && (no > x_no)))) + continue; + if ((!firstx) && (terr >= 0) && (nrx > x_nrx)) + continue; + + found = 1; + x_no = no; + x_nrx = nrx; + x_nfx = nfx; + x_nb = nb; + x_fvco = fvco; + x_err = err; + first = firstx = 0; + merr = fabs(err); + if (terr != -1) + continue; + printf("%d\t%lld\t%d\t%d\t%e\t%#+g\n", nrx, nfx, no, nb, fvco, err); + } + } + if (!found) + { + printf("Error: No workable settings found.\n"); + return 0; + } + + nrx = x_nrx; + nfx = x_nfx; + no = x_no; + nb = x_nb; + fvco = x_fvco; + err = x_err; + if ((terr != -2) && (fabs(err) >= terr * (1 - 1e-6))) + { + printf("Error: No appropriate ratio found.\n"); + return 0; + } + +#ifdef CONFIG_PLL_DEBUG_ENABLE + printf("NR = %d\n", nrx); + printf("NF = %lld\n", nfx); + printf("OD = %d\n", no); + printf("NB = %d\n", nb); + + printf("\n"); + printf("Fin = %g\n", fin); + printf("Fvco = %g\n", fvco); + printf("Fout = %g\n", fvco / no); + printf("error = %+g\n", err); + + printf("\n"); + printf("CLKR[3:0] = %02x\n", nrx - 1); + printf("CLKF[5:0] = %02x\n", (unsigned int)nfx - 1); + printf("CLKOD[3:0] = %02x\n", no - 1); + printf("BWADJ[5:0] = %02x\n", nb - 1); +#endif /* CONFIG_PLL_DEBUG_ENABLE */ + + /* + * Begin write PLL registers' value, + * Using atomic write method. + */ + struct sysctl_pll0_t pll0; + struct sysctl_pll1_t pll1; + struct sysctl_pll2_t pll2; + + switch (pll) + { + case SYSCTL_PLL0: + /* Read register from bus */ + pll0 = sysctl->pll0; + /* Set register temporary value */ + pll0.clkr0 = nrx - 1; + pll0.clkf0 = nfx - 1; + pll0.clkod0 = no - 1; + pll0.bwadj0 = nb - 1; + /* Write register back to bus */ + sysctl->pll0 = pll0; + break; + + case SYSCTL_PLL1: + /* Read register from bus */ + pll1 = sysctl->pll1; + /* Set register temporary value */ + pll1.clkr1 = nrx - 1; + pll1.clkf1 = nfx - 1; + pll1.clkod1 = no - 1; + pll1.bwadj1 = nb - 1; + /* Write register back to bus */ + sysctl->pll1 = pll1; + break; + + case SYSCTL_PLL2: + /* Read register from bus */ + pll2 = sysctl->pll2; + /* Set register temporary value */ + if (source < sizeof(get_select_pll2)) + pll2.pll_ckin_sel2 = get_select_pll2[source]; + + pll2.clkr2 = nrx - 1; + pll2.clkf2 = nfx - 1; + pll2.clkod2 = no - 1; + pll2.bwadj2 = nb - 1; + /* Write register back to bus */ + sysctl->pll2 = pll2; + break; + + default: + return 0; + } + + return sysctl_pll_get_freq(pll); +} + +uint32_t sysctl_clock_get_freq(enum sysctl_clock_e clock) +{ + uint32_t source = 0; + uint32_t result = 0; + + switch (clock) + { + /* + * These clock directly under PLL clock domain + * They are using gated divider. + */ + case SYSCTL_CLOCK_PLL0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0); + result = source; + break; + case SYSCTL_CLOCK_PLL1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL1); + result = source; + break; + case SYSCTL_CLOCK_PLL2: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL2); + result = source; + break; + + /* + * These clock directly under ACLK clock domain + */ + case SYSCTL_CLOCK_CPU: + switch (sysctl_clock_get_clock_select(SYSCTL_CLOCK_SELECT_ACLK)) + { + case 0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + break; + case 1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0) / + (2ULL << sysctl_clock_get_threshold(SYSCTL_THRESHOLD_ACLK)); + break; + default: + break; + } + result = source; + break; + case SYSCTL_CLOCK_DMA: + switch (sysctl_clock_get_clock_select(SYSCTL_CLOCK_SELECT_ACLK)) + { + case 0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + break; + case 1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0) / + (2ULL << sysctl_clock_get_threshold(SYSCTL_THRESHOLD_ACLK)); + break; + default: + break; + } + result = source; + break; + case SYSCTL_CLOCK_FFT: + switch (sysctl_clock_get_clock_select(SYSCTL_CLOCK_SELECT_ACLK)) + { + case 0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + break; + case 1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0) / + (2ULL << sysctl_clock_get_threshold(SYSCTL_THRESHOLD_ACLK)); + break; + default: + break; + } + result = source; + break; + case SYSCTL_CLOCK_ACLK: + switch (sysctl_clock_get_clock_select(SYSCTL_CLOCK_SELECT_ACLK)) + { + case 0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + break; + case 1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0) / + (2ULL << sysctl_clock_get_threshold(SYSCTL_THRESHOLD_ACLK)); + break; + default: + break; + } + result = source; + break; + case SYSCTL_CLOCK_HCLK: + switch (sysctl_clock_get_clock_select(SYSCTL_CLOCK_SELECT_ACLK)) + { + case 0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + break; + case 1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0) / + (2ULL << sysctl_clock_get_threshold(SYSCTL_THRESHOLD_ACLK)); + break; + default: + break; + } + result = source; + break; + + /* + * These clock under ACLK clock domain. + * They are using gated divider. + */ + case SYSCTL_CLOCK_SRAM0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_ACLK); + result = source / (sysctl_clock_get_threshold(SYSCTL_THRESHOLD_SRAM0) + 1); + break; + case SYSCTL_CLOCK_SRAM1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_ACLK); + result = source / (sysctl_clock_get_threshold(SYSCTL_THRESHOLD_SRAM1) + 1); + break; + case SYSCTL_CLOCK_ROM: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_ACLK); + result = source / (sysctl_clock_get_threshold(SYSCTL_THRESHOLD_ROM) + 1); + break; + case SYSCTL_CLOCK_DVP: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_ACLK); + result = source / (sysctl_clock_get_threshold(SYSCTL_THRESHOLD_DVP) + 1); + break; + + /* + * These clock under ACLK clock domain. + * They are using even divider. + */ + case SYSCTL_CLOCK_APB0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_ACLK); + result = source / (sysctl_clock_get_threshold(SYSCTL_THRESHOLD_APB0) + 1); + break; + case SYSCTL_CLOCK_APB1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_ACLK); + result = source / (sysctl_clock_get_threshold(SYSCTL_THRESHOLD_APB1) + 1); + break; + case SYSCTL_CLOCK_APB2: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_ACLK); + result = source / (sysctl_clock_get_threshold(SYSCTL_THRESHOLD_APB2) + 1); + break; + + /* + * These clock under AI clock domain. + * They are using gated divider. + */ + case SYSCTL_CLOCK_AI: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL1); + result = source / (sysctl_clock_get_threshold(SYSCTL_THRESHOLD_AI) + 1); + break; + + /* + * These clock under I2S clock domain. + * They are using even divider. + */ + case SYSCTL_CLOCK_I2S0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL2); + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_I2S0) + 1) * 2); + break; + case SYSCTL_CLOCK_I2S1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL2); + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_I2S1) + 1) * 2); + break; + case SYSCTL_CLOCK_I2S2: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL2); + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_I2S2) + 1) * 2); + break; + + /* + * These clock under WDT clock domain. + * They are using even divider. + */ + case SYSCTL_CLOCK_WDT0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_WDT0) + 1) * 2); + break; + case SYSCTL_CLOCK_WDT1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_WDT1) + 1) * 2); + break; + + /* + * These clock under PLL0 clock domain. + * They are using even divider. + */ + case SYSCTL_CLOCK_SPI0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0); + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_SPI0) + 1) * 2); + break; + case SYSCTL_CLOCK_SPI1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0); + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_SPI1) + 1) * 2); + break; + case SYSCTL_CLOCK_SPI2: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0); + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_SPI2) + 1) * 2); + break; + case SYSCTL_CLOCK_I2C0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0); + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_I2C0) + 1) * 2); + break; + case SYSCTL_CLOCK_I2C1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0); + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_I2C1) + 1) * 2); + break; + case SYSCTL_CLOCK_I2C2: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0); + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_I2C2) + 1) * 2); + break; + + /* + * These clock under PLL0_SEL clock domain. + * They are using even divider. + */ + case SYSCTL_CLOCK_SPI3: + switch (sysctl_clock_get_clock_select(SYSCTL_CLOCK_SELECT_SPI3)) + { + case 0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + break; + case 1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0); + break; + default: + break; + } + + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_SPI3) + 1) * 2); + break; + case SYSCTL_CLOCK_TIMER0: + switch (sysctl_clock_get_clock_select(SYSCTL_CLOCK_SELECT_TIMER0)) + { + case 0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + break; + case 1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0); + break; + default: + break; + } + + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_TIMER0) + 1) * 2); + break; + case SYSCTL_CLOCK_TIMER1: + switch (sysctl_clock_get_clock_select(SYSCTL_CLOCK_SELECT_TIMER1)) + { + case 0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + break; + case 1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0); + break; + default: + break; + } + + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_TIMER1) + 1) * 2); + break; + case SYSCTL_CLOCK_TIMER2: + switch (sysctl_clock_get_clock_select(SYSCTL_CLOCK_SELECT_TIMER2)) + { + case 0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + break; + case 1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0); + break; + default: + break; + } + + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_TIMER2) + 1) * 2); + break; + + /* + * These clock under MISC clock domain. + * They are using even divider. + */ + + /* + * These clock under APB0 clock domain. + * They are using even divider. + */ + case SYSCTL_CLOCK_GPIO: + source = sysctl_clock_get_freq(SYSCTL_CLOCK_APB0); + result = source; + break; + case SYSCTL_CLOCK_UART1: + source = sysctl_clock_get_freq(SYSCTL_CLOCK_APB0); + result = source; + break; + case SYSCTL_CLOCK_UART2: + source = sysctl_clock_get_freq(SYSCTL_CLOCK_APB0); + result = source; + break; + case SYSCTL_CLOCK_UART3: + source = sysctl_clock_get_freq(SYSCTL_CLOCK_APB0); + result = source; + break; + case SYSCTL_CLOCK_FPIOA: + source = sysctl_clock_get_freq(SYSCTL_CLOCK_APB0); + result = source; + break; + case SYSCTL_CLOCK_SHA: + source = sysctl_clock_get_freq(SYSCTL_CLOCK_APB0); + result = source; + break; + + /* + * These clock under APB1 clock domain. + * They are using even divider. + */ + case SYSCTL_CLOCK_AES: + source = sysctl_clock_get_freq(SYSCTL_CLOCK_APB1); + result = source; + break; + case SYSCTL_CLOCK_OTP: + source = sysctl_clock_get_freq(SYSCTL_CLOCK_APB1); + result = source; + break; + case SYSCTL_CLOCK_RTC: + source = sysctl_clock_get_freq(SYSCTL_CLOCK_APB1); + result = source; + break; + + /* + * These clock under APB2 clock domain. + * They are using even divider. + */ + /* + * Do nothing. + */ + default: + break; + } + return result; +} + +int sysctl_dma_select(enum sysctl_dma_channel_e channel, enum sysctl_dma_select_e select) +{ + struct sysctl_dma_sel0_t dma_sel0; + struct sysctl_dma_sel1_t dma_sel1; + + /* Read register from bus */ + dma_sel0 = sysctl->dma_sel0; + dma_sel1 = sysctl->dma_sel1; + switch (channel) + { + case SYSCTL_DMA_CHANNEL_0: + dma_sel0.dma_sel0 = select; + break; + + case SYSCTL_DMA_CHANNEL_1: + dma_sel0.dma_sel1 = select; + break; + + case SYSCTL_DMA_CHANNEL_2: + dma_sel0.dma_sel2 = select; + break; + + case SYSCTL_DMA_CHANNEL_3: + dma_sel0.dma_sel3 = select; + break; + + case SYSCTL_DMA_CHANNEL_4: + dma_sel0.dma_sel4 = select; + break; + + case SYSCTL_DMA_CHANNEL_5: + dma_sel1.dma_sel5 = select; + break; + + default: + return -1; + } + + /* Write register back to bus */ + sysctl->dma_sel0 = dma_sel0; + sysctl->dma_sel1 = dma_sel1; + + return 0; +} + +uint32_t sysctl_pll_fast_enable_pll(void) +{ + /* + * Begin write PLL registers' value, + * Using atomic write method. + */ + struct sysctl_pll0_t pll0; + struct sysctl_pll1_t pll1; + struct sysctl_pll2_t pll2; + + /* Read register from bus */ + pll0 = sysctl->pll0; + pll1 = sysctl->pll1; + pll2 = sysctl->pll2; + + /* PLL VCO MAX freq: 1.8GHz */ + + /* PLL0: 26M reference clk get 793M output clock */ + pll0.clkr0 = 0; + pll0.clkf0 = 60; + pll0.clkod0 = 1; + pll0.bwadj0 = 60; + + /* PLL1: 26M reference clk get 390M output clock */ + pll1.clkr1 = 0; + pll1.clkf1 = 59; + pll1.clkod1 = 3; + pll1.bwadj1 = 59; + + /* PLL2: 26M reference clk get 390M output clock */ + pll2.clkr2 = 0; + pll2.clkf2 = 59; + pll2.clkod2 = 3; + pll2.bwadj2 = 59; + + /* Write register to bus */ + sysctl->pll0 = pll0; + sysctl->pll1 = pll1; + sysctl->pll2 = pll2; + + sysctl_pll_enable(SYSCTL_PLL0); + sysctl_pll_enable(SYSCTL_PLL1); + sysctl_pll_enable(SYSCTL_PLL2); + + while (sysctl_pll_is_lock(SYSCTL_PLL0) == 0) + sysctl_pll_clear_slip(SYSCTL_PLL0); + while (sysctl_pll_is_lock(SYSCTL_PLL1) == 0) + sysctl_pll_clear_slip(SYSCTL_PLL1); + while (sysctl_pll_is_lock(SYSCTL_PLL2) == 0) + sysctl_pll_clear_slip(SYSCTL_PLL2); + + sysctl_clock_enable(SYSCTL_CLOCK_PLL0); + sysctl_clock_enable(SYSCTL_CLOCK_PLL1); + sysctl_clock_enable(SYSCTL_CLOCK_PLL2); + + /* Set ACLK to PLL0 */ + sysctl_clock_set_clock_select(SYSCTL_CLOCK_SELECT_ACLK, SYSCTL_SOURCE_PLL0); + + return 0; +} diff --git a/lib/drivers/timer.c b/lib/drivers/timer.c new file mode 100644 index 0000000..aa5f522 --- /dev/null +++ b/lib/drivers/timer.c @@ -0,0 +1,214 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "timer.h" +#include "sysctl.h" +#include "stddef.h" +#include "common.h" +#include "plic.h" +#include "io.h" + +volatile struct timer_t *const timer[3] = +{ + (volatile struct timer_t *)TIMER0_BASE_ADDR, + (volatile struct timer_t *)TIMER1_BASE_ADDR, + (volatile struct timer_t *)TIMER2_BASE_ADDR +}; + +void timer_init(uint32_t tim) +{ + sysctl_clock_enable(SYSCTL_CLOCK_TIMER0 + tim); +} + +void timer_set_clock_div(uint32_t tim, uint32_t div) +{ + sysctl_clock_set_threshold(tim == 0 ? SYSCTL_THRESHOLD_TIMER0 : + tim == 1 ? SYSCTL_THRESHOLD_TIMER1 : + SYSCTL_THRESHOLD_TIMER2, div); +} + +void timer_enable(uint32_t tim, uint32_t channel) +{ + timer[tim]->channel[channel].control |= TIMER_CR_ENABLE; +} + +void timer_disable(uint32_t tim, uint32_t channel) +{ + timer[tim]->channel[channel].control &= (~TIMER_CR_ENABLE); +} + +void timer_enable_pwm(uint32_t tim, uint32_t channel) +{ + timer[tim]->channel[channel].control |= TIMER_CR_PWM_ENABLE; +} + +void timer_disable_pwm(uint32_t tim, uint32_t channel) +{ + timer[tim]->channel[channel].control &= (~TIMER_CR_PWM_ENABLE); +} + +void timer_enable_interrupt(uint32_t tim, uint32_t channel) +{ + timer[tim]->channel[channel].control &= (~TIMER_CR_INTERRUPT_MASK); +} + +void timer_disable_interrupt(uint32_t tim, uint32_t channel) +{ + timer[tim]->channel[channel].control |= TIMER_CR_INTERRUPT_MASK; +} + +void timer_set_mode(uint32_t tim, uint32_t channel, uint32_t mode) +{ + timer[tim]->channel[channel].control &= (~TIMER_CR_MODE_MASK); + timer[tim]->channel[channel].control |= mode; +} + +void timer_set_reload(uint32_t tim, uint32_t channel, uint32_t count) +{ + timer[tim]->channel[channel].load_count = count; +} + +void timer_set_reload2(uint32_t tim, uint32_t channel, uint32_t count) +{ + timer[tim]->load_count2[channel] = count; +} + +uint32_t timer_get_count(uint32_t tim, uint32_t channel) +{ + return timer[tim]->channel[channel].current_value; +} + +uint32_t timer_get_reload(uint32_t tim, uint32_t channel) +{ + return timer[tim]->channel[channel].load_count; +} + +uint32_t timer_get_reload2(uint32_t tim, uint32_t channel) +{ + return timer[tim]->load_count2[channel]; +} + +uint32_t timer_get_interrupt_status(uint32_t tim) +{ + return timer[tim]->intr_stat; +} + +uint32_t timer_get_raw_interrupt_status(uint32_t tim) +{ + return timer[tim]->raw_intr_stat; +} + +uint32_t timer_channel_get_interrupt_status(uint32_t tim, uint32_t channel) +{ + return timer[tim]->channel[channel].intr_stat; +} + +void timer_clear_interrupt(uint32_t tim) +{ + timer[tim]->eoi = timer[tim]->eoi; +} + +void timer_channel_clear_interrupt(uint32_t tim, uint32_t channel) +{ + timer[tim]->channel[channel].eoi = timer[tim]->channel[channel].eoi; +} + +void timer_set_enable(uint32_t tim, uint32_t channel, uint32_t enable){ + if (enable) + timer[tim]->channel[channel].control = TIMER_CR_USER_MODE | TIMER_CR_ENABLE; + else + timer[tim]->channel[channel].control = TIMER_CR_INTERRUPT_MASK; +} + +size_t timer_set_interval(uint32_t tim, uint32_t channel, size_t nanoseconds) +{ + uint32_t clk_freq = sysctl_clock_get_freq(SYSCTL_CLOCK_TIMER0 + tim); + + double min_step = 1e9 / clk_freq; + size_t value = (size_t)(nanoseconds / min_step); + configASSERT(value > 0 && value < UINT32_MAX); + timer[tim]->channel[channel].load_count = (uint32_t)value; + return (size_t)(min_step * value); +} + +typedef void(*timer_ontick)(); +timer_ontick time_irq[3][4] = { NULL }; + +static int timer_isr(void *parm) +{ + uint32_t tim; + for (tim = 0; tim < 3; tim++) + { + if (parm == timer[tim]) + break; + } + + uint32_t channel = timer[tim]->intr_stat; + size_t i = 0; + for (i = 0; i < 4; i++) + { + if (channel & 1) + { + if (time_irq[tim][i]) + (time_irq[tim][i])(); + break; + } + + channel >>= 1; + } + + readl(&timer[tim]->eoi); + return 0; +} + +void timer_set_irq(uint32_t tim, uint32_t channel, void(*func)(), uint32_t priority) +{ + time_irq[tim][channel] = func; + if (channel < 2) + { + plic_set_priority(IRQN_TIMER0A_INTERRUPT + tim * 2, priority); + plic_irq_register(IRQN_TIMER0A_INTERRUPT + tim * 2, timer_isr, (void *)timer[tim]); + plic_irq_enable(IRQN_TIMER0A_INTERRUPT + tim * 2); + } + else + { + plic_set_priority(IRQN_TIMER0B_INTERRUPT + tim * 2, priority); + plic_irq_register(IRQN_TIMER0B_INTERRUPT + tim * 2, timer_isr, NULL); + plic_irq_enable(IRQN_TIMER0B_INTERRUPT + tim * 2); + } +} + +void pwm_set_enable(uint32_t tim, uint32_t channel, int enable) +{ + if (enable) + timer[tim]->channel[channel].control = TIMER_CR_INTERRUPT_MASK | TIMER_CR_PWM_ENABLE | TIMER_CR_USER_MODE | TIMER_CR_ENABLE; + else + timer[tim]->channel[channel].control = TIMER_CR_INTERRUPT_MASK; +} + +double pwm_set_frequency(uint32_t tim, uint32_t channel, double frequency, double duty) +{ + uint32_t clk_freq = sysctl_clock_get_freq(SYSCTL_CLOCK_TIMER0 + tim); + + int32_t periods = (int32_t)(clk_freq / frequency); + configASSERT(periods > 0 && periods <= INT32_MAX); + frequency = clk_freq / (double)periods; + + uint32_t percent = (uint32_t)(duty * periods); + timer[tim]->channel[channel].load_count = periods - percent; + timer[tim]->load_count2[channel] = percent; + + return frequency; +} + diff --git a/lib/drivers/uart.c b/lib/drivers/uart.c new file mode 100644 index 0000000..f75a5f6 --- /dev/null +++ b/lib/drivers/uart.c @@ -0,0 +1,194 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include "plic.h" +#include "sysctl.h" +#include "uart.h" +#include "common.h" +#include "atomic.h" + +#define __UART_BRATE_CONST 16 + +typedef struct +{ + uart_t *uart; + const uart_info_t *uart_info; + uint32_t uart_status; +} uart_devinfo_t; + +volatile uart_t* const uart[3] = +{ + (volatile uart_t*)UART1_BASE_ADDR, + (volatile uart_t*)UART2_BASE_ADDR, + (volatile uart_t*)UART3_BASE_ADDR +}; + +#define RING_BUFF_LEN 64U + +typedef struct +{ + size_t head; + size_t tail; + size_t length; + char ring_buff[RING_BUFF_LEN]; +} ring_buff_t; + +ring_buff_t *ring_recv[3] = {NULL, NULL, NULL}; + +static int write_ringbuff(uint8_t channel, uint8_t rdata) +{ + ring_buff_t *rb = ring_recv[channel]; + + if (rb->length >= RING_BUFF_LEN) + { + return -1; + } + rb->ring_buff[rb->tail] = rdata; + rb->tail = (rb->tail + 1) % RING_BUFF_LEN; + atomic_add(&rb->length, 1); + return 0; +} + +static int read_ringbuff(uint8_t channel, char *rdata, size_t len) +{ + ring_buff_t *rb = ring_recv[channel]; + size_t cnt = 0; + while ((len--) && rb->length) + { + *(rdata++) = rb->ring_buff[rb->head]; + rb->head = (rb->head + 1) % RING_BUFF_LEN; + atomic_add(&rb->length, -1); + cnt++; + } + return cnt; +} + +static int on_irq_apbuart_recv(void *param) +{ + int i = 0; + for (i = 0; i < 3; i++) + { + if (param == uart[i]) + break; + } + + while (uart[i]->LSR & 1) + { + write_ringbuff(i, ((uint8_t)(uart[i]->RBR & 0xff))); + } + return 0; +} + +static int uartapb_putc(uint8_t channel, char c) +{ + while (!(uart[channel]->LSR & (1u << 6))) + continue; + uart[channel]->THR = c; + return 0; +} + +int uartapb_getc(uint8_t channel) +{ + while (!(uart[channel]->LSR & 1)) + continue; + + return (char)(uart[channel]->RBR & 0xff); +} + + +int uart_read(uint8_t channel, char* buffer, size_t len) +{ + return read_ringbuff(channel, buffer, len); +} + +int uart_write(uint8_t channel, const char* buffer, size_t len) +{ + int write = 0; + while (write < len) + { + uartapb_putc(channel, *buffer++); + write++; + } + + return write; +} + +void uart_config(uint8_t channel, size_t baud_rate, size_t data_width, uart_stopbit stopbit, uart_parity parity) +{ + + configASSERT(data_width >= 5 && data_width <= 8); + if (data_width == 5) + { + configASSERT(stopbit != UART_STOP_2); + } + else + { + configASSERT(stopbit != UART_STOP_1_5); + } + + uint32_t stopbit_val = stopbit == UART_STOP_1 ? 0 : 1; + uint32_t parity_val; + switch (parity) + { + case UART_PARITY_None: + parity_val = 0; + break; + case UART_PARITY_Odd: + parity_val = 1; + break; + case UART_PARITY_Even: + parity_val = 3; + break; + default: + configASSERT(!"Invalid parity"); + break; + } + + uint32_t freq = sysctl_clock_get_freq(SYSCTL_CLOCK_APB0); + uint32_t u16Divider = (freq + __UART_BRATE_CONST * baud_rate / 2) / + (__UART_BRATE_CONST * baud_rate); + + /* Set UART registers */ + uart[channel]->TCR &= ~(1u); + uart[channel]->TCR &= ~(1u << 3); + uart[channel]->TCR &= ~(1u << 4); + uart[channel]->TCR |= (1u << 2); + uart[channel]->TCR &= ~(1u << 1); + uart[channel]->DE_EN &= ~(1u); + + uart[channel]->LCR |= 1u << 7; + uart[channel]->DLL = u16Divider & 0xFF; + uart[channel]->DLH = u16Divider >> 8; + uart[channel]->LCR = 0; + uart[channel]->LCR = (data_width - 5) | (stopbit_val << 2) | (parity_val << 3); + uart[channel]->LCR &= ~(1u << 7); + uart[channel]->MCR &= ~3; + uart[channel]->IER = 1; /*RX INT enable*/ +} + +void uartapb_init(uint8_t channel) +{ + sysctl_clock_enable(SYSCTL_CLOCK_UART1 + channel); + + ring_buff_t *rb = malloc(sizeof(ring_buff_t)); + rb->head = 0; + rb->tail = 0; + rb->length = 0; + ring_recv[channel] = rb; + plic_irq_register(IRQN_UART1_INTERRUPT + channel, on_irq_apbuart_recv, (void *)uart[channel]); + plic_set_priority(IRQN_UART1_INTERRUPT + channel, 1); + plic_irq_enable(IRQN_UART1_INTERRUPT); +} diff --git a/lib/drivers/uarths.c b/lib/drivers/uarths.c new file mode 100644 index 0000000..eb18855 --- /dev/null +++ b/lib/drivers/uarths.c @@ -0,0 +1,97 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "uarths.h" +#include "sysctl.h" +#include "env/encoding.h" + +volatile struct uarths_t *const uarths = (volatile struct uarths_t *)UARTHS_BASE_ADDR; + +static inline int uart_putc(char c) +{ + /* Read hart id */ + unsigned long hart_id = read_csr(mhartid); + /* Set print data reg */ + volatile uint32_t *reg = (volatile uint32_t *)0x50440080UL; + /* Push data out */ + if (hart_id == 0) + { + /* Select core 0 data reg */ + *reg = (0UL << 30) | c; + } + else + { + /* Select core 1 data reg */ + *reg = (1UL << 30) | c; + } + + /* Convert to DOS style (CRLF terminated) */ + if (c == '\n') + { + while (uarths->txdata.full) + continue; + uarths->txdata.data = '\r'; + } + while (uarths->txdata.full) + continue; + uarths->txdata.data = c; + + return 0; +} + +int uart_getc(void) +{ + /* while not empty */ + struct uarths_rxdata_t recv = uarths->rxdata; + + if (recv.empty) + return EOF; + else + return recv.data; +} + +int uart_putchar(char c) +{ + return uart_putc(c); +} + +int uart_puts(const char *s) +{ + while (*s) + if (uart_putc(*s++) != 0) + return -1; + return 0; +} + +int uart_init() +{ + uint32_t freq = sysctl_clock_get_freq(SYSCTL_CLOCK_CPU); + uint16_t div = freq / 115200 - 1; + + /* Set UART registers */ + uarths->div.div = div; + uarths->txctrl.txen = 1; + uarths->rxctrl.rxen = 1; + uarths->txctrl.txcnt = 0; + uarths->rxctrl.rxcnt = 0; + uarths->ip.txwm = 1; + uarths->ip.rxwm = 1; + uarths->ie.txwm = 0; + uarths->ie.rxwm = 1; + + return 0; +} diff --git a/lib/drivers/wdt.c b/lib/drivers/wdt.c new file mode 100644 index 0000000..fc750f7 --- /dev/null +++ b/lib/drivers/wdt.c @@ -0,0 +1,120 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "wdt.h" +#include "platform.h" +#include "stddef.h" +#include "common.h" +#include "sysctl.h" +#include "plic.h" + +plic_irq_callback_t wdt_irq[2]; + +volatile struct wdt_t *const wdt[2] = +{ + (volatile struct wdt_t *)WDT0_BASE_ADDR, + (volatile struct wdt_t *)WDT1_BASE_ADDR +}; + +void wdt_feed(uint8_t id) +{ + wdt[id]->crr = WDT_CRR_MASK; +} + +void wdt_enable(uint8_t id) +{ + wdt[id]->crr = WDT_CRR_MASK; + wdt[id]->cr |= WDT_CR_ENABLE; +} + +void wdt_disable(uint8_t id) +{ + wdt[id]->crr = WDT_CRR_MASK; + wdt[id]->cr &= (~WDT_CR_ENABLE); +} + +void wdt_timeout_set(uint8_t id, uint8_t timeout) +{ + wdt[id]->torr = WDT_TORR_TOP(timeout); +} + +void wdt_response_mode(uint8_t id, uint8_t mode) +{ + wdt[id]->cr &= (~WDT_CR_RMOD_MASK); + wdt[id]->cr |= mode; +} + +void wdt_interrupt_clear(uint8_t id) +{ + wdt[id]->eoi = wdt[id]->eoi; +} + +void wdt_set_irq(uint8_t id, plic_irq_callback_t on_irq) +{ + wdt_irq[id] = on_irq; +} + +size_t wdt_get_pclk(uint8_t id) +{ + return id ? sysctl_clock_get_freq(SYSCTL_CLOCK_WDT1) : sysctl_clock_get_freq(SYSCTL_CLOCK_WDT0); +} + +ssize_t log_2(size_t x) +{ + ssize_t i = 0; + for (i = sizeof(size_t) * 8; i >= 0; i--) + { + if ((x >> i) & 0x1) + { + break; + } + } + return i; +} + +uint8_t wdt_get_top(uint8_t id, size_t timeout_ms) +{ + size_t wdt_clk = wdt_get_pclk(id); + size_t ret = (timeout_ms * wdt_clk / 1000) >> 16; + if (ret) + ret = log_2(ret); + if (ret > 0xf) + ret = 0xf; + return (uint8_t)ret; +} + + +int wdt_start(uint8_t id, size_t toms) +{ + wdt_disable(id); + wdt_interrupt_clear(id); + plic_irq_register(id ? IRQN_WDT1_INTERRUPT : IRQN_WDT0_INTERRUPT, wdt_irq[id], NULL); + plic_set_priority(id ? IRQN_WDT1_INTERRUPT : IRQN_WDT0_INTERRUPT, 1); + plic_irq_enable(id ? IRQN_WDT1_INTERRUPT : IRQN_WDT0_INTERRUPT); + + sysctl_reset(id ? SYSCTL_RESET_WDT1 : SYSCTL_RESET_WDT0); + sysctl_clock_set_threshold(id ? SYSCTL_THRESHOLD_WDT1 : SYSCTL_THRESHOLD_WDT0, 0); + sysctl_clock_enable(id ? SYSCTL_CLOCK_WDT1 : SYSCTL_CLOCK_WDT0); + wdt_response_mode(id, WDT_CR_RMOD_INTERRUPT); + uint8_t m_top = wdt_get_top(id, toms); + wdt_timeout_set(id, m_top); + wdt_enable(id); + return 0; +} + +void wdt_stop(uint8_t id) +{ + wdt_disable(id); +} + diff --git a/lib/firmware/include/font.h b/lib/firmware/include/font.h new file mode 100644 index 0000000..4e7c010 --- /dev/null +++ b/lib/firmware/include/font.h @@ -0,0 +1,366 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _FONT_H_ +#define _FONT_H_ + +#include + +uint8_t const ascii0816[] = +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x81, 0xA5, 0x81, 0x81, 0xBD, + 0x99, 0x81, 0x81, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xFF, + 0xDB, 0xFF, 0xFF, 0xC3, 0xE7, 0xFF, 0xFF, 0x7E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x6C, 0xFE, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7C, 0xFE, + 0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, + 0x3C, 0x3C, 0xE7, 0xE7, 0xE7, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x18, 0x18, 0x3C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, + 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0x99, 0xBD, + 0xBD, 0x99, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x1E, 0x0E, + 0x1A, 0x32, 0x78, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x33, 0x3F, 0x30, 0x30, 0x30, + 0x30, 0x70, 0xF0, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x63, + 0x7F, 0x63, 0x63, 0x63, 0x63, 0x67, 0xE7, 0xE6, 0xC0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x18, 0xDB, 0x3C, 0xE7, 0x3C, 0xDB, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFE, 0xF8, + 0xF0, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0E, + 0x1E, 0x3E, 0xFE, 0x3E, 0x1E, 0x0E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xDB, + 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7C, 0xC6, 0x60, 0x38, 0x6C, 0xC6, 0xC6, 0x6C, 0x38, 0x0C, 0xC6, + 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFE, 0xFE, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, + 0x7E, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, + 0xC0, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x28, 0x6C, 0xFE, 0x6C, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7C, 0x7C, 0xFE, 0xFE, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0x7C, 0x7C, + 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x3C, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, + 0x6C, 0xFE, 0x6C, 0x6C, 0x6C, 0xFE, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x7C, 0xC6, 0xC2, 0xC0, 0x7C, 0x06, 0x06, 0x86, 0xC6, 0x7C, + 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC2, 0xC6, 0x0C, 0x18, + 0x30, 0x60, 0xC6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, + 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, + 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xD6, 0xD6, 0xC6, 0xC6, 0x6C, 0x38, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, + 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0x06, 0x06, 0x3C, 0x06, 0x06, 0x06, 0xC6, 0x7C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x1C, 0x3C, 0x6C, 0xCC, 0xFE, + 0x0C, 0x0C, 0x0C, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC0, + 0xC0, 0xC0, 0xFC, 0x06, 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x60, 0xC0, 0xC0, 0xFC, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC6, 0x06, 0x06, 0x0C, 0x18, + 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, + 0xC6, 0xC6, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x06, 0x06, 0x0C, 0x78, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, + 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, + 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xDE, 0xDE, + 0xDE, 0xDC, 0xC0, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, + 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x66, 0x66, 0xFC, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0xC2, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC2, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x6C, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xFE, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68, + 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, + 0xC2, 0xC0, 0xC0, 0xDE, 0xC6, 0xC6, 0x66, 0x3A, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x0C, + 0x0C, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xE6, 0x66, 0x66, 0x6C, 0x78, 0x78, 0x6C, 0x66, 0x66, 0xE6, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x60, 0x60, 0x60, 0x60, 0x60, + 0x60, 0x62, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xEE, + 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xC6, 0xE6, 0xF6, 0xFE, 0xDE, 0xCE, 0xC6, 0xC6, 0xC6, 0xC6, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, + 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x66, + 0x66, 0x66, 0x7C, 0x60, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xDE, 0x7C, + 0x0C, 0x0E, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x6C, + 0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, + 0xC6, 0x60, 0x38, 0x0C, 0x06, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7E, 0x7E, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, + 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, + 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xD6, 0xD6, 0xFE, 0xEE, 0x6C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0x6C, 0x7C, 0x38, 0x38, + 0x7C, 0x6C, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, + 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFE, 0xC6, 0x86, 0x0C, 0x18, 0x30, 0x60, 0xC2, 0xC6, 0xFE, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6, 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, 0xFF, 0x00, 0x00, + 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0C, 0x7C, + 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x60, + 0x60, 0x78, 0x6C, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC0, 0xC0, 0xC0, 0xC6, 0x7C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x0C, 0x0C, 0x3C, 0x6C, 0xCC, + 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x6C, 0x64, 0x60, 0xF0, 0x60, 0x60, 0x60, 0x60, 0xF0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xCC, 0xCC, + 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xCC, 0x78, 0x00, 0x00, 0x00, 0xE0, 0x60, + 0x60, 0x6C, 0x76, 0x66, 0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0E, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x00, 0xE0, 0x60, + 0x60, 0x66, 0x6C, 0x78, 0x78, 0x6C, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xFE, 0xD6, + 0xD6, 0xD6, 0xD6, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x76, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0x0C, 0x1E, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x76, 0x66, 0x60, 0x60, 0x60, 0xF0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0x60, + 0x38, 0x0C, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30, + 0x30, 0xFC, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xC6, 0xC6, 0xD6, 0xD6, 0xD6, 0xFE, 0x6C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x38, 0x38, 0x6C, 0xC6, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, + 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x0C, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xFE, 0xCC, 0x18, 0x30, 0x60, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0E, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0E, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18, + 0x18, 0x18, 0x0E, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6, + 0xC6, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, + 0xC2, 0xC0, 0xC0, 0xC0, 0xC2, 0x66, 0x3C, 0x0C, 0x06, 0x7C, 0x00, 0x00, + 0x00, 0x00, 0xCC, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x00, 0x7C, 0xC6, 0xFE, + 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, + 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xCC, 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0C, 0x7C, + 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x38, + 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x60, 0x60, 0x66, 0x3C, 0x0C, 0x06, + 0x3C, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0x00, 0x7C, 0xC6, 0xFE, + 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00, + 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x66, + 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, + 0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x38, 0x00, + 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x30, 0x60, 0x00, 0xFE, 0x66, 0x60, 0x7C, 0x60, 0x60, 0x66, 0xFE, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x76, 0x36, + 0x7E, 0xD8, 0xD8, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x6C, + 0xCC, 0xCC, 0xFE, 0xCC, 0xCC, 0xCC, 0xCC, 0xCE, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x6C, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00, 0x00, 0x7C, 0xC6, 0xC6, + 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, + 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x78, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xCC, 0xCC, 0xCC, + 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00, + 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x0C, 0x78, 0x00, + 0x00, 0xC6, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, + 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x3C, + 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x6C, 0x64, 0x60, 0xF0, 0x60, 0x60, 0x60, 0x60, 0xE6, 0xFC, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, + 0x7E, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xCC, 0xCC, + 0xF8, 0xC4, 0xCC, 0xDE, 0xCC, 0xCC, 0xCC, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0E, 0x1B, 0x18, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, + 0xD8, 0x70, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0C, 0x7C, + 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, + 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x30, 0x60, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xCC, 0xCC, 0xCC, + 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, + 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x76, 0xDC, 0x00, 0xC6, 0xE6, 0xF6, 0xFE, 0xDE, 0xCE, 0xC6, 0xC6, 0xC6, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x6C, 0x6C, 0x3E, 0x00, 0x7E, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x6C, + 0x38, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xC0, 0xC6, 0xC6, 0x7C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC0, + 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFE, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xC0, 0xC0, 0xC2, 0xC6, 0xCC, 0x18, 0x30, 0x60, 0xDC, 0x86, 0x0C, + 0x18, 0x3E, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC2, 0xC6, 0xCC, 0x18, 0x30, + 0x66, 0xCE, 0x9E, 0x3E, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, + 0x00, 0x18, 0x18, 0x18, 0x3C, 0x3C, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6C, 0xD8, 0x6C, 0x36, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x6C, 0x36, + 0x6C, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44, + 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, + 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, + 0x55, 0xAA, 0x55, 0xAA, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, + 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0xF8, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x18, 0xF8, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, + 0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x06, 0xF6, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0xF8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xF7, 0x00, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, + 0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x76, 0xDC, 0xD8, 0xD8, 0xD8, 0xDC, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0xD8, 0xCC, 0xC6, 0xC6, 0xC6, 0xCC, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC6, 0xC6, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFE, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFE, 0xC6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xC6, 0xFE, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xD8, 0xD8, + 0xD8, 0xD8, 0xD8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xC0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x18, 0x3C, 0x66, 0x66, + 0x66, 0x3C, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, + 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x6C, 0x6C, 0x6C, 0xEE, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x30, 0x18, 0x0C, 0x3E, 0x66, + 0x66, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7E, 0xDB, 0xDB, 0xDB, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x06, 0x7E, 0xDB, 0xDB, 0xF3, 0x7E, 0x60, 0xC0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x30, 0x60, 0x60, 0x7C, 0x60, + 0x60, 0x60, 0x30, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, + 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18, + 0x18, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, + 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x00, 0x7E, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0xD8, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x18, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, 0x00, + 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x6C, + 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0C, 0x0C, + 0x0C, 0x0C, 0x0C, 0xEC, 0x6C, 0x6C, 0x3C, 0x1C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xD8, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xD8, 0x30, 0x60, 0xC8, 0xF8, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}; + +#endif + diff --git a/lib/firmware/include/lcd.h b/lib/firmware/include/lcd.h new file mode 100644 index 0000000..51ae6d3 --- /dev/null +++ b/lib/firmware/include/lcd.h @@ -0,0 +1,82 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _LCD_H_ +#define _LCD_H_ + +#include + +/* clang-format off */ +#define LCD_X_MAX (320) +#define LCD_Y_MAX (480) + +#define BLACK 0x0000 +#define NAVY 0x000F +#define DARKGREEN 0x03E0 +#define DARKCYAN 0x03EF +#define MAROON 0x7800 +#define PURPLE 0x780F +#define OLIVE 0x7BE0 +#define LIGHTGREY 0xC618 +#define DARKGREY 0x7BEF +#define BLUE 0x001F +#define GREEN 0x07E0 +#define CYAN 0x07FF +#define RED 0xF800 +#define MAGENTA 0xF81F +#define YELLOW 0xFFE0 +#define WHITE 0xFFFF +#define ORANGE 0xFD20 +#define GREENYELLOW 0xAFE5 +#define PINK 0xF81F +#define USER_COLOR 0xAA55 +/* clang-format on */ + +enum lcd_dir_t +{ + DIR_XY_RLUD = 0x00, + DIR_YX_RLUD = 0x20, + DIR_XY_LRUD = 0x40, + DIR_YX_LRUD = 0x60, + DIR_XY_RLDU = 0x80, + DIR_YX_RLDU = 0xA0, + DIR_XY_LRDU = 0xC0, + DIR_YX_LRDU = 0xE0, + DIR_XY_MASK = 0x20, + DIR_MASK = 0xE0, +}; + +typedef struct +{ + uint8_t mode; + uint8_t dir; + uint16_t width; + uint16_t height; +} lcd_ctl_t; + +int lcd_busy(void); +void lcd_polling_enable(void); +void lcd_interrupt_enable(void); +void lcd_init(void); +void lcd_clear(uint16_t color); +void lcd_set_direction(enum lcd_dir_t dir); +void lcd_set_area(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2); +void lcd_draw_point(uint16_t x, uint16_t y, uint16_t color); +void lcd_draw_string(uint16_t x, uint16_t y, char *str, uint16_t color); +void lcd_draw_picture(uint16_t x1, uint16_t y1, uint16_t width, uint16_t height, uint32_t *ptr); +void lcd_draw_rectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t width, uint16_t color); +void lcd_ram_draw_string(char *str, uint32_t *ptr, uint16_t font_color, uint16_t bg_color); + +#endif + diff --git a/lib/firmware/include/nt35310.h b/lib/firmware/include/nt35310.h new file mode 100644 index 0000000..9f60e7a --- /dev/null +++ b/lib/firmware/include/nt35310.h @@ -0,0 +1,113 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _NT35310_H_ +#define _NT35310_H_ + +#include + +/* clang-format off */ +#define NO_OPERATION 0x00 +#define SOFTWARE_RESET 0x01 +#define READ_ID 0x04 +#define READ_STATUS 0x09 +#define READ_POWER_MODE 0x0A +#define READ_MADCTL 0x0B +#define READ_PIXEL_FORMAT 0x0C +#define READ_IMAGE_FORMAT 0x0D +#define READ_SIGNAL_MODE 0x0E +#define READ_SELT_DIAG_RESULT 0x0F +#define SLEEP_ON 0x10 +#define SLEEP_OFF 0x11 +#define PARTIAL_DISPALY_ON 0x12 +#define NORMAL_DISPALY_ON 0x13 +#define INVERSION_DISPALY_OFF 0x20 +#define INVERSION_DISPALY_ON 0x21 +#define GAMMA_SET 0x26 +#define DISPALY_OFF 0x28 +#define DISPALY_ON 0x29 +#define HORIZONTAL_ADDRESS_SET 0x2A +#define VERTICAL_ADDRESS_SET 0x2B +#define MEMORY_WRITE 0x2C +#define COLOR_SET 0x2D +#define MEMORY_READ 0x2E +#define PARTIAL_AREA 0x30 +#define VERTICAL_SCROL_DEFINE 0x33 +#define TEAR_EFFECT_LINE_OFF 0x34 +#define TEAR_EFFECT_LINE_ON 0x35 +#define MEMORY_ACCESS_CTL 0x36 +#define VERTICAL_SCROL_S_ADD 0x37 +#define IDLE_MODE_OFF 0x38 +#define IDLE_MODE_ON 0x39 +#define PIXEL_FORMAT_SET 0x3A +#define WRITE_MEMORY_CONTINUE 0x3C +#define READ_MEMORY_CONTINUE 0x3E +#define SET_TEAR_SCANLINE 0x44 +#define GET_SCANLINE 0x45 +#define WRITE_BRIGHTNESS 0x51 +#define READ_BRIGHTNESS 0x52 +#define WRITE_CTRL_DISPALY 0x53 +#define READ_CTRL_DISPALY 0x54 +#define WRITE_BRIGHTNESS_CTL 0x55 +#define READ_BRIGHTNESS_CTL 0x56 +#define WRITE_MIN_BRIGHTNESS 0x5E +#define READ_MIN_BRIGHTNESS 0x5F +#define READ_ID1 0xDA +#define READ_ID2 0xDB +#define READ_ID3 0xDC +#define RGB_IF_SIGNAL_CTL 0xB0 +#define NORMAL_FRAME_CTL 0xB1 +#define IDLE_FRAME_CTL 0xB2 +#define PARTIAL_FRAME_CTL 0xB3 +#define INVERSION_CTL 0xB4 +#define BLANK_PORCH_CTL 0xB5 +#define DISPALY_FUNCTION_CTL 0xB6 +#define ENTRY_MODE_SET 0xB7 +#define BACKLIGHT_CTL1 0xB8 +#define BACKLIGHT_CTL2 0xB9 +#define BACKLIGHT_CTL3 0xBA +#define BACKLIGHT_CTL4 0xBB +#define BACKLIGHT_CTL5 0xBC +#define BACKLIGHT_CTL7 0xBE +#define BACKLIGHT_CTL8 0xBF +#define POWER_CTL1 0xC0 +#define POWER_CTL2 0xC1 +#define VCOM_CTL1 0xC5 +#define VCOM_CTL2 0xC7 +#define NV_MEMORY_WRITE 0xD0 +#define NV_MEMORY_PROTECT_KEY 0xD1 +#define NV_MEMORY_STATUS_READ 0xD2 +#define READ_ID4 0xD3 +#define POSITIVE_GAMMA_CORRECT 0xE0 +#define NEGATIVE_GAMMA_CORRECT 0xE1 +#define DIGITAL_GAMMA_CTL1 0xE2 +#define DIGITAL_GAMMA_CTL2 0xE3 +#define INTERFACE_CTL 0xF6 + +#define DCX_IO (33) +#define DCX_GPIONUM (2) + +#define SPI_CHANNEL 0 +#define SPI_SLAVE_SELECT 3 +/* clang-format on */ + +void tft_hard_init(void); +void tft_write_command(uint8_t cmd); +void tft_write_byte(uint8_t *data_buf, uint32_t length); +void tft_write_half(uint16_t *data_buf, uint32_t length); +void tft_write_word(uint32_t *data_buf, uint32_t length, uint32_t flag); +void tft_fill_data(uint32_t *data_buf, uint32_t length); + +#endif + diff --git a/lib/firmware/include/ov2640.h b/lib/firmware/include/ov2640.h new file mode 100644 index 0000000..941142e --- /dev/null +++ b/lib/firmware/include/ov2640.h @@ -0,0 +1,26 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _OV2640_H +#define _OV2640_H + +#include + +#define OV2640_ADDR 0x60 + +int ov2640_init(void); +int ov2640_read_id(uint16_t *manuf_id, uint16_t *device_id); + +#endif /* _OV2640_H */ + diff --git a/lib/firmware/include/ov5640.h b/lib/firmware/include/ov5640.h new file mode 100644 index 0000000..b738324 --- /dev/null +++ b/lib/firmware/include/ov5640.h @@ -0,0 +1,52 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _OV5640_H +#define _OV5640_H + +#include + +#define OV5640_ID 0X5640 +#define OV5640_ADDR 0X78 +#define OV5640_CHIPIDH 0X300A +#define OV5640_CHIPIDL 0X300B + +#define XSIZE 320 +#define YSIZE 240 +#define LCD_GRAM_ADDRESS 0x60020000 + +#define QQVGA_160_120 0 +#define QCIF_176_144 1 +#define QVGA_320_240 2 +#define WQVGA_400_240 3 +#define CIF_352_288 4 + +#define jpeg_buf_size (30*1024) + +const uint16_t jpeg_size_tbl[][2]= +{ + 160, 120, /*QQVGA*/ + 176, 144, /*QCIF*/ + 320, 240, /*QVGA*/ + 400, 240, /*WQVGA*/ + 352, 288, /*CIF*/ +}; + +uint8_t ov5640_wr_reg(uint16_t reg, uint8_t data); +uint8_t ov5640_rd_reg(uint16_t reg); +uint8_t ov5640_init(void); +void ov5640_flash_lamp(uint8_t sw); + +#endif + diff --git a/lib/firmware/include/ov5640cfg.h b/lib/firmware/include/ov5640cfg.h new file mode 100644 index 0000000..6360ffa --- /dev/null +++ b/lib/firmware/include/ov5640cfg.h @@ -0,0 +1,287 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _OV5640CFG_H +#define _OV5640CFG_H + +#include "ov5640.h" + +const uint16_t ov5640_init_reg_tbl[][2]= +{ + /* 24MHz input clock, 24MHz PCLK */ + 0x3008, 0x42, /* software power down, bit[6] */ + 0x3103, 0x03, /* system clock from PLL, bit[1] */ + 0x3017, 0xff, /* FREX, Vsync, HREF, PCLK, D[9:6] output enable */ + 0x3018, 0xff, /* D[5:0], GPIO[1:0] output enable */ + 0x3034, 0x1a, /* MIPI 10-bit*/ + 0x3035, 0x31, /* PLL */ + 0x3036, 0x80, /* PLL */ + 0x3037, 0x13, /* PLL root divider, bit[4], PLL pre-divider, bit[3:0] */ + 0x3108, 0x01, /* PCLK root divider, bit[5:4], SCLK2x root divider, bit[3:2] */ + /* SCLK root divider, bit[1:0] */ + 0x3630, 0x36, + 0x3631, 0x0e, + 0x3632, 0xe2, + 0x3633, 0x12, + 0x3621, 0xe0, + 0x3704, 0xa0, + 0x3703, 0x5a, + 0x3715, 0x78, + 0x3717, 0x01, + 0x370b, 0x60, + 0x3705, 0x1a, + 0x3905, 0x02, + 0x3906, 0x10, + 0x3901, 0x0a, + 0x3731, 0x12, + 0x3600, 0x08, /* VCM control */ + 0x3601, 0x33, /* VCM control */ + 0x302d, 0x60, /* system control */ + 0x3620, 0x52, + 0x371b, 0x20, + 0x471c, 0x50, + 0x3a13, 0x43, /* pre-gain = 1.047x */ + 0x3a18, 0x00, /* gain ceiling */ + 0x3a19, 0xf8, /* gain ceiling = 15.5x */ + 0x3635, 0x13, + 0x3636, 0x03, + 0x3634, 0x40, + 0x3622, 0x01, + /* 50/60Hz detection 50/60Hz */ + 0x3c01, 0x34, /* Band auto, bit[7] */ + 0x3c04, 0x28, /* threshold low sum */ + 0x3c05, 0x98, /* threshold high sum */ + 0x3c06, 0x00, /* light meter 1 threshold[15:8] */ + 0x3c07, 0x07, /* light meter 1 threshold[7:0] */ + 0x3c08, 0x00, /* light meter 2 threshold[15:8] */ + 0x3c09, 0x1c, /* light meter 2 threshold[7:0] */ + 0x3c0a, 0x9c, /* sample number[15:8] */ + 0x3c0b, 0x40, /* sample number[7:0] */ + 0x3810, 0x00, /* Timing Hoffset[11:8] */ + 0x3811, 0x10, /* Timing Hoffset[7:0] */ + 0x3812, 0x00, /* Timing Voffset[10:8] */ + 0x3708, 0x64, + 0x4001, 0x02, /* BLC start from line 2 */ + 0x4005, 0x1a, /* BLC always update */ + 0x3000, 0x00, /* enable blocks */ + 0x3004, 0xff, /* enable clocks */ + 0x300e, 0x58, /* MIPI power down, DVP enable */ + 0x302e, 0x00, + 0x4300, 0x61, + 0X501F, 0x01, + 0x3820, 0x46, /* flip */ + 0x3821, 0x00, /* mirror */ + 0x3800, 0x00, /* HS */ + 0x3801, 0x00, /* HS */ + 0x3802, 0x00, /* VS */ + 0x3803, 0x00, /* VS */ + 0x3804, 0x0a, /* HW (HE) */ + 0x3805, 0x3f, /* HW (HE) */ + 0x3806, 0x06, /* VH (VE) */ + 0x3807, 0xa9, /* VH (VE) */ + 0x3814, 0x31, /* timing X inc */ + 0x3815, 0x31, /* timing Y inc */ + 0x3808, (320 >> 8), /* DVPHO */ + 0x3809, (320 & 0xff), /* DVPHO */ + 0x380a, (240 >> 8), /* DVPVO */ + 0x380b, (240 & 0xff), /* DVPVO */ + 0x380c, 0x05, /* HTS */ + 0x380d, 0xF8, /* HTS */ + 0x380e, 0x03, /* VTS */ + 0x380f, 0x84, /* VTS */ + 0x3810, 0x00, /* HTS */ + 0x3811, 0x00, /* HTS */ + 0x3812, 0x00, /* VTS */ + 0x3813, 0x00, /* VTS */ + 0x3618, 0x00, + 0x3612, 0x29, + 0x3709, 0x52, + 0x370c, 0x03, + 0x3a02, 0x02, /* 60Hz max exposure */ + 0x3a03, 0xe0, /* 60Hz max exposure */ + 0x3a14, 0x02, /* 50Hz max exposure */ + 0x3a15, 0xe0, /* 50Hz max exposure */ + 0x4004, 0x02, /* BLC line number */ + 0x3002, 0x1c, /* reset JFIFO, SFIFO, JPG */ + 0x3006, 0xc3, /* disable clock of JPEG2x, JPEG */ + 0x4713, 0x03, /* JPEG mode 3 */ + 0x4407, 0x04, /* Quantization scale */ + 0x460b, 0x37, + 0x460c, 0x20, + 0x4837, 0x16, /* MIPI global timing */ + 0x3824, 0x04, /* PCLK manual divider */ + 0x5001, 0xA3, /* SDE on, scale on, UV average off, color matrix on, AWB on */ + 0x3503, 0x00, /* AEC/AGC on */ + 0x440e, 0x00, + 0x5000, 0xa7, /* Lenc on, raw gamma on, BPC on, WPC on, CIP on */ + /* AEC target*/ + 0x3a0f, 0x30, /* stable range in high */ + 0x3a10, 0x28, /* stable range in low */ + 0x3a1b, 0x30, /* stable range out high */ + 0x3a1e, 0x26, /* stable range out low */ + 0x3a11, 0x60, /* fast zone high */ + 0x3a1f, 0x14, /* fast zone low */ + /* Lens correction for */ + 0x5800, 0x23, + 0x5801, 0x14, + 0x5802, 0x0f, + 0x5803, 0x0f, + 0x5804, 0x12, + 0x5805, 0x26, + 0x5806, 0x0c, + 0x5807, 0x08, + 0x5808, 0x05, + 0x5809, 0x05, + 0x580a, 0x08, + 0x580b, 0x0d, + 0x580c, 0x08, + 0x580d, 0x03, + 0x580e, 0x00, + 0x580f, 0x00, + 0x5810, 0x03, + 0x5811, 0x09, + 0x5812, 0x07, + 0x5813, 0x03, + 0x5814, 0x00, + 0x5815, 0x01, + 0x5816, 0x03, + 0x5817, 0x08, + 0x5818, 0x0d, + 0x5819, 0x08, + 0x581a, 0x05, + 0x581b, 0x06, + 0x581c, 0x08, + 0x581d, 0x0e, + 0x581e, 0x29, + 0x581f, 0x17, + 0x5820, 0x11, + 0x5821, 0x11, + 0x5822, 0x15, + 0x5823, 0x28, + 0x5824, 0x46, + 0x5825, 0x26, + 0x5826, 0x08, + 0x5827, 0x26, + 0x5828, 0x64, + 0x5829, 0x26, + 0x582a, 0x24, + 0x582b, 0x22, + 0x582c, 0x24, + 0x582d, 0x24, + 0x582e, 0x06, + 0x582f, 0x22, + 0x5830, 0x40, + 0x5831, 0x42, + 0x5832, 0x24, + 0x5833, 0x26, + 0x5834, 0x24, + 0x5835, 0x22, + 0x5836, 0x22, + 0x5837, 0x26, + 0x5838, 0x44, + 0x5839, 0x24, + 0x583a, 0x26, + 0x583b, 0x28, + 0x583c, 0x42, + 0x583d, 0xce, /* lenc BR offset */ + /* AWB */ + 0x5180, 0xff, /* AWB B block */ + 0x5181, 0xf2, /* AWB control */ + 0x5182, 0x00, /* [7:4] max local counter, [3:0] max fast counter */ + 0x5183, 0x14, /* AWB advanced */ + 0x5184, 0x25, + 0x5185, 0x24, + 0x5186, 0x09, + 0x5187, 0x09, + 0x5188, 0x09, + 0x5189, 0x75, + 0x518a, 0x54, + 0x518b, 0xe0, + 0x518c, 0xb2, + 0x518d, 0x42, + 0x518e, 0x3d, + 0x518f, 0x56, + 0x5190, 0x46, + 0x5191, 0xf8, /* AWB top limit */ + 0x5192, 0x04, /* AWB bottom limit */ + 0x5193, 0x70, /* red limit */ + 0x5194, 0xf0, /* green limit */ + 0x5195, 0xf0, /* blue limit */ + 0x5196, 0x03, /* AWB control*/ + 0x5197, 0x01, /* local limit */ + 0x5198, 0x04, + 0x5199, 0x12, + 0x519a, 0x04, + 0x519b, 0x00, + 0x519c, 0x06, + 0x519d, 0x82, + 0x519e, 0x38, /* AWB control */ + /* Gamma */ + 0x5480, 0x01, /* Gamma bias plus on, bit[0] */ + 0x5481, 0x08, + 0x5482, 0x14, + 0x5483, 0x28, + 0x5484, 0x51, + 0x5485, 0x65, + 0x5486, 0x71, + 0x5487, 0x7d, + 0x5488, 0x87, + 0x5489, 0x91, + 0x548a, 0x9a, + 0x548b, 0xaa, + 0x548c, 0xb8, + 0x548d, 0xcd, + 0x548e, 0xdd, + 0x548f, 0xea, + 0x5490, 0x1d, + /* color matrix */ + 0x5381, 0x1e, /* CMX1 for Y */ + 0x5382, 0x5b, /* CMX2 for Y */ + 0x5383, 0x08, /* CMX3 for Y */ + 0x5384, 0x0a, /* CMX4 for U */ + 0x5385, 0x7e, /* CMX5 for U */ + 0x5386, 0x88, /* CMX6 for U */ + 0x5387, 0x7c, /* CMX7 for V */ + 0x5388, 0x6c, /* CMX8 for V */ + 0x5389, 0x10, /* CMX9 for V */ + 0x538a, 0x01, /* sign[9] */ + 0x538b, 0x98, /* sign[8:1] */ + /* UV adjust UV */ + 0x5580, 0x06, /* saturation on, bit[1] */ + 0x5583, 0x40, + 0x5584, 0x10, + 0x5589, 0x10, + 0x558a, 0x00, + 0x558b, 0xf8, + 0x501d, 0x40, /* enable manual offset of contrast */ + /* CIP */ + 0x5300, 0x08, /* CIP sharpen MT threshold 1 */ + 0x5301, 0x30, /* CIP sharpen MT threshold 2 */ + 0x5302, 0x10, /* CIP sharpen MT offset 1 */ + 0x5303, 0x00, /* CIP sharpen MT offset 2 */ + 0x5304, 0x08, /* CIP DNS threshold 1 */ + 0x5305, 0x30, /* CIP DNS threshold 2 */ + 0x5306, 0x08, /* CIP DNS offset 1 */ + 0x5307, 0x16, /* CIP DNS offset 2 */ + 0x5309, 0x08, /* CIP sharpen TH threshold 1 */ + 0x530a, 0x30, /* CIP sharpen TH threshold 2 */ + 0x530b, 0x04, /* CIP sharpen TH offset 1 */ + 0x530c, 0x06, /* CIP sharpen TH offset 2 */ + 0x5025, 0x00, + 0x3008, 0x02, /* wake up from standby, bit[6] */ + 0x4740, 0X21, /*VSYNC active HIGH */ +}; + +#endif + diff --git a/lib/firmware/include/sd3068.h b/lib/firmware/include/sd3068.h new file mode 100644 index 0000000..f34eca1 --- /dev/null +++ b/lib/firmware/include/sd3068.h @@ -0,0 +1,47 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _SD3068_H +#define _SD3068_H + +#include + +#define SD3068_ADDR 0x32 +#define SD3068_ADDR_LENTH 7 + +struct time_t +{ + uint32_t year:6; + uint32_t month:4; + uint32_t day:5; + uint32_t hour:5; + uint32_t min:6; + uint32_t sec:6; +} __attribute__((packed, aligned(4))); + +void sd3068_init(uint8_t sel); +int sd3068_write_enable(void); +int sd3068_write_disable(void); +int sd3068_set_time(struct time_t time); +int sd3068_get_time(struct time_t *time); +int sd3068_write_data(uint8_t addr, uint8_t *data_buf, uint8_t length); +int sd3068_read_data(uint8_t addr, uint8_t *data_buf, uint8_t length); +int sd3068_set_time_dma(struct time_t time); +int sd3068_write_enable_dma(void); +int sd3068_get_time_dma(struct time_t *time); +int sd3068_read_data_dma(uint8_t addr, uint8_t *data_buf, uint8_t length); +int sd3068_write_data_dma(uint8_t addr, uint8_t *data_buf, uint8_t length); + +#endif + diff --git a/lib/firmware/include/w25qxx.h b/lib/firmware/include/w25qxx.h new file mode 100644 index 0000000..b6dd1e5 --- /dev/null +++ b/lib/firmware/include/w25qxx.h @@ -0,0 +1,113 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _W25QXX_H +#define _W25QXX_H + +#include + +/* clang-format off */ +#define DATALENGTH 8 + +#define SPI_SLAVE_SELECT (0x01) + +#define w25qxx_FLASH_PAGE_SIZE 256 +#define w25qxx_FLASH_SECTOR_SIZE 4096 +#define w25qxx_FLASH_PAGE_NUM_PER_SECTOR 16 +#define w25qxx_FLASH_CHIP_SIZE (16777216 UL) + +#define WRITE_ENABLE 0x06 +#define WRITE_DISABLE 0x04 +#define READ_REG1 0x05 +#define READ_REG2 0x35 +#define READ_REG3 0x15 +#define WRITE_REG1 0x01 +#define WRITE_REG2 0x31 +#define WRITE_REG3 0x11 +#define READ_DATA 0x03 +#define FAST_READ 0x0B +#define FAST_READ_DUAL_OUTPUT 0x3B +#define FAST_READ_QUAL_OUTPUT 0x6B +#define FAST_READ_DUAL_IO 0xBB +#define FAST_READ_QUAL_IO 0xEB +#define DUAL_READ_RESET 0xFFFF +#define QUAL_READ_RESET 0xFF +#define PAGE_PROGRAM 0x02 +#define QUAD_PAGE_PROGRAM 0x32 +#define SECTOR_ERASE 0x20 +#define BLOCK_32K_ERASE 0x52 +#define BLOCK_64K_ERASE 0xD8 +#define CHIP_ERASE 0x60 +#define READ_ID 0x90 +#define ENABLE_QPI 0x38 +#define EXIT_QPI 0xFF +#define ENABLE_RESET 0x66 +#define RESET_DEVICE 0x99 + +#define REG1_BUSY_MASK 0x01 +#define REG2_QUAL_MASK 0x02 + +#define LETOBE(x) ((x >> 24) | ((x & 0x00FF0000) >> 8) | ((x & 0x0000FF00) << 8) | (x << 24)) +/* clang-format on */ + +/** + * @brief w25qxx operating status enumerate + */ +enum w25qxx_status_t +{ + W25QXX_OK = 0, + W25QXX_BUSY, + W25QXX_ERROR, +}; + +/** + * @brief w25qxx read operating enumerate + */ +enum w25qxx_read_t +{ + W25QXX_STANDARD = 0, + W25QXX_STANDARD_FAST, + W25QXX_DUAL, + W25QXX_DUAL_FAST, + W25QXX_QUAD, + W25QXX_QUAD_FAST, +}; + +enum w25qxx_status_t w25qxx_init(uint8_t spi_index, uint8_t spi_ss); +enum w25qxx_status_t w25qxx_is_busy(void); +enum w25qxx_status_t w25qxx_chip_erase(void); +enum w25qxx_status_t w25qxx_enable_quad_mode(void); +enum w25qxx_status_t w25qxx_disable_quad_mode(void); +enum w25qxx_status_t w25qxx_sector_erase(uint32_t addr); +enum w25qxx_status_t w25qxx_32k_block_erase(uint32_t addr); +enum w25qxx_status_t w25qxx_64k_block_erase(uint32_t addr); +enum w25qxx_status_t w25qxx_read_status_reg1(uint8_t *reg_data); +enum w25qxx_status_t w25qxx_read_status_reg2(uint8_t *reg_data); +enum w25qxx_status_t w25qxx_write_status_reg(uint8_t reg1_data, uint8_t reg2_data); +enum w25qxx_status_t w25qxx_read_id(uint8_t *manuf_id, uint8_t *device_id); +enum w25qxx_status_t w25qxx_write_data(uint32_t addr, uint8_t *data_buf, uint32_t length); +enum w25qxx_status_t w25qxx_write_data_direct(uint32_t addr, uint8_t *data_buf, uint32_t length); +enum w25qxx_status_t w25qxx_read_data(uint32_t addr, uint8_t *data_buf, uint32_t length, enum w25qxx_read_t mode); +enum w25qxx_status_t w25qxx_enable_xip_mode(void); +enum w25qxx_status_t w25qxx_disable_xip_mode(void); +enum w25qxx_status_t w25qxx_read_id_dma(uint8_t *manuf_id, uint8_t *device_id); +enum w25qxx_status_t w25qxx_sector_erase_dma(uint32_t addr); +enum w25qxx_status_t w25qxx_init_dma(uint8_t spi_index, uint8_t spi_ss); +enum w25qxx_status_t w25qxx_write_data_direct_dma(uint32_t addr, uint8_t *data_buf, uint32_t length); +enum w25qxx_status_t w25qxx_read_data_dma(uint32_t addr, uint8_t *data_buf, uint32_t length, enum w25qxx_read_t mode); +enum w25qxx_status_t w25qxx_is_busy_dma(void); +enum w25qxx_status_t w25qxx_enable_quad_mode_dma(void); + +#endif + diff --git a/lib/firmware/lcd.c b/lib/firmware/lcd.c new file mode 100644 index 0000000..9176b69 --- /dev/null +++ b/lib/firmware/lcd.c @@ -0,0 +1,210 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include "lcd.h" +#include "nt35310.h" +#include "font.h" +#include "common.h" +#include "sleep.h" + +static lcd_ctl_t lcd_ctl; + +void lcd_polling_enable(void) +{ + lcd_ctl.mode = 0; +} + +void lcd_interrupt_enable(void) +{ + lcd_ctl.mode = 1; + +} + +void lcd_init(void) +{ + uint8_t data = 0; + + tft_hard_init(); + /*soft reset*/ + tft_write_command(SOFTWARE_RESET); + msleep(100); + /*exit sleep*/ + tft_write_command(SLEEP_OFF); + msleep(100); + /*pixel format*/ + tft_write_command(PIXEL_FORMAT_SET); + data = 0x55; + tft_write_byte(&data, 1); + lcd_set_direction(DIR_XY_RLUD); + /*display on*/ + tft_write_command(DISPALY_ON); + lcd_polling_enable(); +} + +void lcd_set_direction(enum lcd_dir_t dir) +{ + lcd_ctl.dir = dir; + if (dir & DIR_XY_MASK) + { + lcd_ctl.width = LCD_Y_MAX - 1; + lcd_ctl.height = LCD_X_MAX - 1; + } + else + { + lcd_ctl.width = LCD_X_MAX - 1; + lcd_ctl.height = LCD_Y_MAX - 1; + } + + tft_write_command(MEMORY_ACCESS_CTL); + tft_write_byte((uint8_t *)&dir, 1); +} + +void lcd_set_area(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) +{ + uint8_t data[4] = {0}; + + data[0] = (uint8_t)(x1 >> 8); + data[1] = (uint8_t)(x1); + data[2] = (uint8_t)(x2 >> 8); + data[3] = (uint8_t)(x2); + tft_write_command(HORIZONTAL_ADDRESS_SET); + tft_write_byte(data, 4); + + data[0] = (uint8_t)(y1 >> 8); + data[1] = (uint8_t)(y1); + data[2] = (uint8_t)(y2 >> 8); + data[3] = (uint8_t)(y2); + tft_write_command(VERTICAL_ADDRESS_SET); + tft_write_byte(data, 4); + + tft_write_command(MEMORY_WRITE); +} + +void lcd_draw_point(uint16_t x, uint16_t y, uint16_t color) +{ + lcd_set_area(x, y, x, y); + tft_write_half(&color, 1); +} + +void lcd_draw_char(uint16_t x, uint16_t y, char c, uint16_t color) +{ + uint8_t i = 0; + uint8_t j = 0; + uint8_t data = 0; + + for (i = 0; i < 16; i++) + { + data = ascii0816[c * 16 + i]; + for (j = 0; j < 8; j++) + { + if (data & 0x80) + lcd_draw_point(x + j, y, color); + data <<= 1; + } + y++; + } +} + +void lcd_draw_string(uint16_t x, uint16_t y, char *str, uint16_t color) +{ + while (*str) + { + lcd_draw_char(x, y, *str, color); + str++; + x += 8; + } +} + +void lcd_ram_draw_string(char *str, uint32_t *ptr, uint16_t font_color, uint16_t bg_color) +{ + uint8_t i = 0; + uint8_t j = 0; + uint8_t data = 0; + uint8_t *pdata = NULL; + uint16_t width = 0; + uint32_t *pixel = NULL; + + width = 4 * strlen(str); + while (*str) + { + pdata = (uint8_t *)&ascii0816[(*str) * 16]; + for (i = 0; i < 16; i++) + { + data = *pdata++; + pixel = ptr + i * width; + for (j = 0; j < 4; j++) + { + switch (data >> 6) + { + case 0: + *pixel = ((uint32_t)bg_color << 16) | bg_color; + break; + case 1: + *pixel = ((uint32_t)bg_color << 16) | font_color; + break; + case 2: + *pixel = ((uint32_t)font_color << 16) | bg_color; + break; + case 3: + *pixel = ((uint32_t)font_color << 16) | font_color; + break; + default: + *pixel = 0; + break; + } + data <<= 2; + pixel++; + } + } + str++; + ptr += 4; + } +} + +void lcd_clear(uint16_t color) +{ + uint32_t data = ((uint32_t)color << 16) | (uint32_t)color; + + lcd_set_area(0, 0, lcd_ctl.width, lcd_ctl.height); + tft_fill_data(&data, LCD_X_MAX * LCD_Y_MAX / 2); +} + +void lcd_draw_rectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t width, uint16_t color) +{ + uint32_t data_buf[640] = {0}; + uint32_t *p = data_buf; + uint32_t data = color; + uint32_t index = 0; + + data = (data << 16) | data; + for (index = 0; index < 160 * width; index++) + *p++ = data; + + lcd_set_area(x1, y1, x2, y1 + width - 1); + tft_write_word(data_buf, ((x2 - x1 + 1) * width + 1) / 2, 0); + lcd_set_area(x1, y2 - width + 1, x2, y2); + tft_write_word(data_buf, ((x2 - x1 + 1) * width + 1) / 2, 0); + lcd_set_area(x1, y1, x1 + width - 1, y2); + tft_write_word(data_buf, ((y2 - y1 + 1) * width + 1) / 2, 0); + lcd_set_area(x2 - width + 1, y1, x2, y2); + tft_write_word(data_buf, ((y2 - y1 + 1) * width + 1) / 2, 0); +} + +void lcd_draw_picture(uint16_t x1, uint16_t y1, uint16_t width, uint16_t height, uint32_t *ptr) +{ + lcd_set_area(x1, y1, x1 + width - 1, y1 + height - 1); + tft_write_word(ptr, width * height / 2, lcd_ctl.mode ? 2 : 0); +} + diff --git a/lib/firmware/nt35310.c b/lib/firmware/nt35310.c new file mode 100644 index 0000000..fc01395 --- /dev/null +++ b/lib/firmware/nt35310.c @@ -0,0 +1,115 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "nt35310.h" +#include "sysctl.h" +#include "fpioa.h" +#include "gpiohs.h" +#include "spi.h" +#include "dmac.h" +#include "plic.h" +#include + +#define __SPI_SYSCTL(x, y) SYSCTL_##x##_SPI##y +#define _SPI_SYSCTL(x, y) __SPI_SYSCTL(x, y) +#define SPI_SYSCTL(x) _SPI_SYSCTL(x, SPI_CHANNEL) +#define __SPI_SS(x, y) FUNC_SPI##x##_SS##y +#define _SPI_SS(x, y) __SPI_SS(x, y) +#define SPI_SS _SPI_SS(SPI_CHANNEL, SPI_SLAVE_SELECT) +#define __SPI(x, y) FUNC_SPI##x##_##y +#define _SPI(x, y) __SPI(x, y) +#define SPI(x) _SPI(SPI_CHANNEL, x) + +void init_dcx(void) +{ + gpiohs_init(); + fpioa_set_function(DCX_IO, FUNC_GPIOHS0 + DCX_GPIONUM);/*dcx*/ + gpiohs_set_drive_mode(DCX_GPIONUM, GPIO_DM_Output); + gpiohs_set_pin_value(DCX_GPIONUM, GPIO_PV_High); +} + +void set_dcx_control(void) +{ + gpiohs_set_pin_value(DCX_GPIONUM, GPIO_PV_Low); +} + +void set_dcx_data(void) +{ + gpiohs_set_pin_value(DCX_GPIONUM, GPIO_PV_High); +} + +void pin_mux_init(void) +{ + fpioa_set_function(31, SPI_SS); + fpioa_set_function(32, SPI(SCLK)); + sysctl->misc.reserved0 = 1; +} + +void tft_hard_init(void) +{ + init_dcx(); + pin_mux_init(); + spi_master_config(SPI_CHANNEL, SPI_MODE_2, SPI_FF_OCTAL, 8); +} + +void tft_write_command(uint8_t cmd) +{ + set_dcx_control(); + spi_set_tmod(SPI_CHANNEL, SPI_TMOD_TRANS); + spi_set_frame_format(SPI_CHANNEL, SPI_FF_OCTAL); + spi_set_frame_size(SPI_CHANNEL, 8); + spi_trans_config(SPI_CHANNEL, 8/*instrction length*/, 0/*address length*/, 0/*wait cycles*/, SPI_AITM_AS_FRAME_FORMAT/*spi address trans mode*/); + spi_normal_send_dma(DMAC_CHANNEL0, SPI_CHANNEL, 1 << SPI_SLAVE_SELECT, (uint8_t *)(&cmd), 1,SPI_TRANS_CHAR); +} + +void tft_write_byte(uint8_t *data_buf, uint32_t length) +{ + set_dcx_data(); + spi_set_tmod(SPI_CHANNEL, SPI_TMOD_TRANS); + spi_set_frame_format(SPI_CHANNEL, SPI_FF_OCTAL); + spi_set_frame_size(SPI_CHANNEL, 8); + spi_trans_config(SPI_CHANNEL, 8/*instrction length*/, 0/*address length*/, 0/*wait cycles*/, SPI_AITM_AS_FRAME_FORMAT/*spi address trans mode*/); + spi_normal_send_dma(DMAC_CHANNEL0, SPI_CHANNEL, 1 << SPI_SLAVE_SELECT, data_buf, length, SPI_TRANS_CHAR); +} + +void tft_write_half(uint16_t *data_buf, uint32_t length) +{ + set_dcx_data(); + spi_set_tmod(SPI_CHANNEL, SPI_TMOD_TRANS); + spi_set_frame_format(SPI_CHANNEL, SPI_FF_OCTAL); + spi_set_frame_size(SPI_CHANNEL, 16); + spi_trans_config(SPI_CHANNEL, 16/*instrction length*/, 0/*address length*/, 0/*wait cycles*/, SPI_AITM_AS_FRAME_FORMAT/*spi address trans mode*/); + spi_normal_send_dma(DMAC_CHANNEL0, SPI_CHANNEL, 1 << SPI_SLAVE_SELECT,data_buf, length, SPI_TRANS_SHORT); +} + +void tft_write_word(uint32_t *data_buf, uint32_t length, uint32_t flag) +{ + set_dcx_data(); + spi_set_tmod(SPI_CHANNEL, SPI_TMOD_TRANS); + spi_set_frame_format(SPI_CHANNEL, SPI_FF_OCTAL); + spi_set_frame_size(SPI_CHANNEL, 32); + spi_trans_config(SPI_CHANNEL, 0/*instrction length*/, 32/*address length*/, 0/*wait cycles*/, SPI_AITM_AS_FRAME_FORMAT/*spi address trans mode*/); + spi_normal_send_dma(DMAC_CHANNEL0, SPI_CHANNEL, 1 << SPI_SLAVE_SELECT,data_buf, length, SPI_TRANS_INT); +} + +void tft_fill_data(uint32_t *data_buf, uint32_t length) +{ + set_dcx_data(); + spi_set_tmod(SPI_CHANNEL, SPI_TMOD_TRANS); + spi_set_frame_format(SPI_CHANNEL, SPI_FF_OCTAL); + spi_set_frame_size(SPI_CHANNEL, 32); + spi_trans_config(SPI_CHANNEL, 0/*instrction length*/, 32/*address length*/, 0/*wait cycles*/, SPI_AITM_AS_FRAME_FORMAT/*spi address trans mode*/); + spi_fill_dma(DMAC_CHANNEL0, SPI_CHANNEL, 1 << SPI_SLAVE_SELECT,data_buf, length); +} + diff --git a/lib/firmware/ov2640.c b/lib/firmware/ov2640.c new file mode 100644 index 0000000..c91a9dd --- /dev/null +++ b/lib/firmware/ov2640.c @@ -0,0 +1,243 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include "ov2640.h" +#include "dvp.h" +#include "plic.h" + +/* QVGA Window Size */ +static const uint8_t ov2640_config[][2] = +{ + {0xff, 0x00}, + {0x2c, 0xff}, + {0x2e, 0xdf}, + {0xff, 0x01}, + {0x3c, 0x32}, + {0x11, 0x00}, + {0x09, 0x00}, + {0x04, 0x28}, + {0x13, 0xe5}, + {0x14, 0xa8}, + {0x15, 0x00}, + {0x2c, 0x0c}, + {0x33, 0x78}, + {0x3a, 0x33}, + {0x3b, 0xfb}, + {0x3e, 0x00}, + {0x43, 0x11}, + {0x16, 0x10}, + {0x39, 0x92}, + {0x35, 0xda}, + {0x22, 0x1a}, + {0x23, 0x00}, + {0x34, 0xc0}, + {0x06, 0x88}, + {0x07, 0xc0}, + {0x0d, 0x87}, + {0x0e, 0x41}, + {0x4c, 0x00}, + {0x48, 0x00}, + {0x5b, 0x00}, + {0x42, 0x03}, + {0x4a, 0x81}, + {0x21, 0x99}, + {0x24, 0x40}, + {0x25, 0x38}, + {0x26, 0x82}, + {0x5c, 0x00}, + {0x63, 0x00}, + {0x61, 0x70}, + {0x62, 0x80}, + {0x7c, 0x05}, + {0x20, 0x80}, + {0x28, 0x30}, + {0x6c, 0x00}, + {0x6d, 0x80}, + {0x6e, 0x00}, + {0x70, 0x02}, + {0x71, 0x94}, + {0x73, 0xc1}, + {0x0c, 0x3c}, + {0x5d, 0x55}, + {0x5e, 0x7d}, + {0x5f, 0x7d}, + {0x60, 0x55}, + {0x12, 0x40}, + {0x32, 0x09}, + {0x17, 0x11}, + {0x18, 0x43}, + {0x19, 0x00}, + {0x1a, 0x97}, + {0x32, 0x09}, + {0x37, 0x42}, + {0x4f, 0xbb}, + {0x50, 0x9c}, + {0x6d, 0x80}, + {0x35, 0x88}, + {0x22, 0x0a}, + {0x6d, 0x80}, + {0x3d, 0xe1}, + {0xff, 0x00}, + {0xe5, 0x7f}, + {0xf9, 0xc0}, + {0x41, 0x24}, + {0x44, 0x06}, + {0xe0, 0x14}, + {0x76, 0xff}, + {0x33, 0xa0}, + {0x42, 0x20}, + {0x43, 0x18}, + {0x4c, 0x00}, + {0x87, 0xd0}, + {0x88, 0x3f}, + {0xd7, 0x03}, + {0xd9, 0x10}, + {0xd3, 0x82}, + {0xc8, 0x08}, + {0xc9, 0x80}, + {0x7c, 0x00}, + {0x7d, 0x00}, + {0x7c, 0x03}, + {0x7d, 0x48}, + {0x7d, 0x48}, + {0x7c, 0x08}, + {0x7d, 0x20}, + {0x7d, 0x10}, + {0x7d, 0x0e}, + {0x90, 0x00}, + {0x91, 0x0e}, + {0x91, 0x1a}, + {0x91, 0x31}, + {0x91, 0x5a}, + {0x91, 0x69}, + {0x91, 0x75}, + {0x91, 0x7e}, + {0x91, 0x88}, + {0x91, 0x8f}, + {0x91, 0x96}, + {0x91, 0xa3}, + {0x91, 0xaf}, + {0x91, 0xc4}, + {0x91, 0xd7}, + {0x91, 0xe8}, + {0x91, 0x20}, + {0x92, 0x00}, + {0x93, 0x06}, + {0x93, 0xe3}, + {0x93, 0x03}, + {0x93, 0x03}, + {0x93, 0x00}, + {0x93, 0x02}, + {0x93, 0x00}, + {0x93, 0x00}, + {0x93, 0x00}, + {0x93, 0x00}, + {0x93, 0x00}, + {0x93, 0x00}, + {0x93, 0x00}, + {0x96, 0x00}, + {0x97, 0x08}, + {0x97, 0x19}, + {0x97, 0x02}, + {0x97, 0x0c}, + {0x97, 0x24}, + {0x97, 0x30}, + {0x97, 0x28}, + {0x97, 0x26}, + {0x97, 0x02}, + {0x97, 0x98}, + {0x97, 0x80}, + {0x97, 0x00}, + {0x97, 0x00}, + {0xa4, 0x00}, + {0xa8, 0x00}, + {0xc5, 0x11}, + {0xc6, 0x51}, + {0xbf, 0x80}, + {0xc7, 0x10}, + {0xb6, 0x66}, + {0xb8, 0xa5}, + {0xb7, 0x64}, + {0xb9, 0x7c}, + {0xb3, 0xaf}, + {0xb4, 0x97}, + {0xb5, 0xff}, + {0xb0, 0xc5}, + {0xb1, 0x94}, + {0xb2, 0x0f}, + {0xc4, 0x5c}, + {0xa6, 0x00}, + {0xa7, 0x20}, + {0xa7, 0xd8}, + {0xa7, 0x1b}, + {0xa7, 0x31}, + {0xa7, 0x00}, + {0xa7, 0x18}, + {0xa7, 0x20}, + {0xa7, 0xd8}, + {0xa7, 0x19}, + {0xa7, 0x31}, + {0xa7, 0x00}, + {0xa7, 0x18}, + {0xa7, 0x20}, + {0xa7, 0xd8}, + {0xa7, 0x19}, + {0xa7, 0x31}, + {0xa7, 0x00}, + {0xa7, 0x18}, + {0xe0, 0x04}, + {0xc0, 0x64}, + {0xc1, 0x4b}, + {0x86, 0x3d}, + {0x50, 0x80}, + {0x51, 0xc8}, + {0x52, 0x96}, + {0x53, 0x00}, + {0x54, 0x00}, + {0x55, 0x00}, + {0x57, 0x00}, + {0x5a, 0x50}, + {0x5b, 0x3c}, + {0x5c, 0x00}, + {0xd3, 0x04}, + {0xe0, 0x00}, + {0xc3, 0xef}, + {0x7f, 0x00}, + {0xda, 0x08}, + {0xe5, 0x1f}, + {0xe1, 0x67}, + {0xdd, 0x7f}, + {0x05, 0x00}, + {0x98, 0x00}, + {0x99, 0x00}, + {0x00, 0x00}, +}; + +int ov2640_init(void) +{ + uint16_t index = 0; + for (index = 0; ov2640_config[index][0]; index++) + dvp_sccb_write(OV2640_ADDR, ov2640_config[index][0], ov2640_config[index][1]); + return 0; +} + +int ov2640_read_id(uint16_t *manuf_id, uint16_t *device_id) +{ + dvp_sccb_write(OV2640_ADDR, 0xFF, 0x01); + *manuf_id = (dvp_sccb_read(OV2640_ADDR, 0x1C) << 8) | dvp_sccb_read(OV2640_ADDR, 0x1D); + *device_id = (dvp_sccb_read(OV2640_ADDR, 0x0A) << 8) | dvp_sccb_read(OV2640_ADDR, 0x0B); + return 0; +} + diff --git a/lib/firmware/ov5640.c b/lib/firmware/ov5640.c new file mode 100644 index 0000000..69926c2 --- /dev/null +++ b/lib/firmware/ov5640.c @@ -0,0 +1,82 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "ov5640.h" +#include "ov5640cfg.h" +#include +#include "ov2640.h" +#include "dvp.h" +#include "plic.h" + +extern void mdelay(uint32_t ms); + +void hal_delay(uint32_t delay) +{ + mdelay(delay); +} + +uint8_t ov5640_wr_reg(uint16_t reg,uint8_t data) +{ + dvp_sccb_write(OV5640_ADDR, reg, data); + return 0; +} + +uint8_t ov5640_rd_reg(uint16_t reg) +{ + return dvp_sccb_read(OV5640_ADDR, reg); +} + +uint8_t ov5640_init(void) +{ + uint16_t i = 0; + uint16_t reg = 0; + + reg = ov5640_rd_reg(OV5640_CHIPIDH); + reg <<= 8; + reg |= ov5640_rd_reg(OV5640_CHIPIDL); + printf("ID: %X \r\n", reg); + if(reg != OV5640_ID) + { + printf("ID: %d \r\n", reg); + return 1; + } + + ov5640_wr_reg(0x3103,0X11); /*system clock from pad, bit[1]*/ + ov5640_wr_reg(0X3008,0X82); + hal_delay(10); + + for(i = 0; i +#include "sd3068.h" +#include "fpioa.h" +#include "common.h" +#include "sysctl.h" +#include "i2c.h" + +uint8_t i2c_bus_no = 0; + +void sd3068_init(uint8_t sel) +{ + i2c_bus_no = sel; +} + +static int sd3068_write_reg(uint8_t reg, uint8_t *data_buf, uint8_t length) +{ + i2c_write_reg(i2c_bus_no, reg, data_buf, length); + return 0; +} + +static int sd3068_write_reg_dma(uint8_t reg, uint8_t *data_buf, uint8_t length) +{ + i2c_write_reg_dma(DMAC_CHANNEL0, i2c_bus_no, reg, data_buf, length); + return 0; +} + +static int sd3068_read_reg(uint8_t reg, uint8_t *data_buf, uint8_t length) +{ + i2c_read_reg(i2c_bus_no, reg, data_buf, length); + return 0; +} + +static int sd3068_read_reg_dma(uint8_t reg, uint8_t *data_buf, uint8_t length) +{ + i2c_read_reg_dma(DMAC_CHANNEL0, DMAC_CHANNEL1, i2c_bus_no, reg, data_buf, length); + return 0; +} + +static uint8_t hex2bcd(uint8_t data) +{ + return data / 10 * 16 + data % 10; +} + +static uint8_t bcd2hex(uint8_t data) +{ + return data / 16 * 10 + data % 16; +} + +int sd3068_write_enable(void) +{ + uint8_t data[2] = {0}; + + data[0] = 0xFF; + data[1] = 0x80; + sd3068_write_reg(0x10, &data[1], 1); + sd3068_write_reg(0x0F, &data[0], 1); + + return 0; +} + +int sd3068_write_enable_dma(void) +{ + uint8_t data[2] = {0}; + + data[0] = 0xFF; + data[1] = 0x80; + sd3068_write_reg_dma(0x10, &data[1], 1); + sd3068_write_reg_dma(0x0F, &data[0], 1); + + return 0; +} + +int sd3068_write_disable(void) +{ + uint8_t data[2] = {0}; + + data[0] = 0x7B; + data[1] = 0; + sd3068_write_reg(0x0F, data, 2); + + return 0; +} + +int sd3068_write_data(uint8_t addr, uint8_t *data_buf, uint8_t length) +{ + addr = ((addr <= 69) ? addr : 69); + length = ((length <= 70 - addr) ? length : 70 - addr); + sd3068_write_reg(0x2C + addr, data_buf, length); + + return 0; +} + +int sd3068_write_data_dma(uint8_t addr, uint8_t *data_buf, uint8_t length) +{ + addr = ((addr <= 69) ? addr : 69); + length = ((length <= 70 - addr) ? length : 70 - addr); + sd3068_write_reg_dma(0x2C + addr, data_buf, length); + + return 0; +} + +int sd3068_read_data(uint8_t addr, uint8_t *data_buf, uint8_t length) +{ + addr = ((addr <= 69) ? addr : 69); + length = ((length <= 70 - addr) ? length : 70 - addr); + sd3068_read_reg(0x2C + addr, data_buf, length); + + return 0; +} + +int sd3068_read_data_dma(uint8_t addr, uint8_t *data_buf, uint8_t length) +{ + addr = ((addr <= 69) ? addr : 69); + length = length <= 70 - addr ? length : 70 - addr; + sd3068_read_reg_dma(0x2C + addr, data_buf, length); + + return 0; +} + +int sd3068_set_time(struct time_t time) +{ + uint8_t data[7] = {0}; + + data[0] = hex2bcd(time.sec); + data[1] = hex2bcd(time.min); + data[2] = hex2bcd(time.hour) | 0x80; + data[3] = hex2bcd(5); + data[4] = hex2bcd(time.day); + data[5] = hex2bcd(time.month); + data[6] = hex2bcd(time.year); + sd3068_write_reg(0x00, data, 7); + + return 0; +} + +int sd3068_set_time_dma(struct time_t time) +{ + uint8_t data[7] = {0}; + + data[0] = hex2bcd(time.sec); + data[1] = hex2bcd(time.min); + data[2] = hex2bcd(time.hour) | 0x80; + data[3] = hex2bcd(5); + data[4] = hex2bcd(time.day); + data[5] = hex2bcd(time.month); + data[6] = hex2bcd(time.year); + sd3068_write_reg_dma(0x00, data, 7); + + return 0; +} + +int sd3068_get_time(struct time_t *time) +{ + uint8_t data[7] = {0}; + + sd3068_read_reg(0x00, data, 7); + time->sec = bcd2hex(data[0]); + time->min = bcd2hex(data[1]); + time->hour = bcd2hex(data[2] & 0x7F); + time->day = bcd2hex(data[4]); + time->month = bcd2hex(data[5]); + time->year = bcd2hex(data[6]); + + return 0; +} + +int sd3068_get_time_dma(struct time_t *time) +{ + uint8_t data[7] = {0}; + + sd3068_read_reg_dma(0x00, data, 7); + time->sec = bcd2hex(data[0]); + time->min = bcd2hex(data[1]); + time->hour = bcd2hex(data[2] & 0x7F); + time->day = bcd2hex(data[4]); + time->month = bcd2hex(data[5]); + time->year = bcd2hex(data[6]); + + return 0; +} + diff --git a/lib/firmware/w25qxx.c b/lib/firmware/w25qxx.c new file mode 100644 index 0000000..3fb5672 --- /dev/null +++ b/lib/firmware/w25qxx.c @@ -0,0 +1,660 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "w25qxx.h" +#include "fpioa.h" +#include "spi.h" +#include "sysctl.h" +#include "dmac.h" + +uint8_t spi_bus_no = 0; +uint8_t spi_chip_select = 0; +static volatile struct spi_t *spi_handle; + +enum w25qxx_status_t (*w25qxx_page_program_fun)(uint32_t addr, uint8_t *data_buf, uint32_t length); +enum w25qxx_status_t (*w25qxx_read_fun)(uint32_t addr, uint8_t *data_buf, uint32_t length); +static enum w25qxx_status_t w25qxx_stand_read_data(uint32_t addr, uint8_t *data_buf, uint32_t length); +static enum w25qxx_status_t w25qxx_quad_read_data(uint32_t addr, uint8_t *data_buf, uint32_t length); +static enum w25qxx_status_t w25qxx_page_program(uint32_t addr, uint8_t *data_buf, uint32_t length); +static enum w25qxx_status_t w25qxx_quad_page_program(uint32_t addr, uint8_t *data_buf, uint32_t length); +static enum w25qxx_status_t w25qxx_page_program_dma(uint32_t addr, uint8_t *data_buf, uint32_t length); +static enum w25qxx_status_t w25qxx_quad_page_program_dma(uint32_t addr, uint8_t *data_buf, uint32_t length); + +static enum w25qxx_status_t w25qxx_receive_data(uint8_t *cmd_buff, uint8_t cmd_len, uint8_t *rx_buff, uint32_t rx_len) +{ + spi_set_tmod(spi_bus_no, SPI_TMOD_EEROM); + spi_receive_data(spi_bus_no, spi_chip_select, cmd_buff, cmd_len, rx_buff, rx_len); + return W25QXX_OK; +} + +static enum w25qxx_status_t w25qxx_receive_data_dma(uint8_t *cmd_buff, uint8_t cmd_len, uint8_t *rx_buff, uint32_t rx_len) +{ + spi_set_tmod(spi_bus_no, SPI_TMOD_EEROM); + spi_receive_data_dma(DMAC_CHANNEL0, DMAC_CHANNEL1, spi_bus_no, spi_chip_select, cmd_buff, cmd_len, rx_buff, rx_len); + return W25QXX_OK; +} + +static enum w25qxx_status_t w25qxx_send_data(uint8_t *cmd_buff, uint8_t cmd_len, uint8_t *tx_buff, uint32_t tx_len) +{ + spi_set_tmod(spi_bus_no, SPI_TMOD_TRANS); + spi_send_data(spi_bus_no, spi_chip_select, cmd_buff, cmd_len, tx_buff, tx_len); + return W25QXX_OK; +} + +static enum w25qxx_status_t w25qxx_send_data_dma(uint8_t *cmd_buff, uint8_t cmd_len, uint8_t *tx_buff, uint32_t tx_len) +{ + spi_set_tmod(spi_bus_no, SPI_TMOD_TRANS); + spi_send_data_dma(DMAC_CHANNEL0, spi_bus_no, spi_chip_select, cmd_buff, cmd_len, tx_buff, tx_len); + return W25QXX_OK; +} + +static enum w25qxx_status_t w25qxx_receive_data_enhanced(uint32_t *cmd_buff, uint8_t cmd_len, uint8_t *rx_buff, uint32_t rx_len) +{ + spi_special_receive_data(spi_bus_no, spi_chip_select, cmd_buff, cmd_len, rx_buff, rx_len); + return W25QXX_OK; +} + +static enum w25qxx_status_t w25qxx_receive_data_enhanced_dma(uint32_t *cmd_buff, uint8_t cmd_len, uint8_t *rx_buff, uint32_t rx_len) +{ + spi_special_receive_data_dma(DMAC_CHANNEL0, DMAC_CHANNEL1, spi_bus_no, spi_chip_select, cmd_buff, cmd_len, rx_buff, rx_len); + return W25QXX_OK; +} + +static enum w25qxx_status_t w25qxx_send_data_enhanced(uint32_t *cmd_buff, uint8_t cmd_len, uint8_t *tx_buff, uint32_t tx_len) +{ + spi_special_send_data(spi_bus_no, spi_chip_select, cmd_buff, cmd_len, tx_buff, tx_len); + return W25QXX_OK; +} + +static enum w25qxx_status_t w25qxx_send_data_enhanced_dma(uint32_t *cmd_buff, uint8_t cmd_len, uint8_t *tx_buff, uint32_t tx_len) +{ + spi_special_send_data_dma(DMAC_CHANNEL0, spi_bus_no, spi_chip_select, cmd_buff, cmd_len, tx_buff, tx_len); + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_init(uint8_t spi_index, uint8_t spi_ss) +{ + spi_bus_no = spi_index; + spi_chip_select = spi_ss; + spi_master_config(spi_bus_no, SPI_MODE_0, SPI_FF_STANDARD, DATALENGTH); + w25qxx_page_program_fun = w25qxx_page_program; + w25qxx_read_fun = w25qxx_stand_read_data; + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_init_dma(uint8_t spi_index, uint8_t spi_ss) +{ + spi_bus_no = spi_index; + spi_chip_select = spi_ss; + spi_master_config(spi_bus_no, SPI_MODE_0, SPI_FF_STANDARD, DATALENGTH); + w25qxx_page_program_fun = w25qxx_page_program_dma; + w25qxx_read_fun = w25qxx_stand_read_data; + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_read_id(uint8_t *manuf_id, uint8_t *device_id) +{ + uint8_t cmd[4] = {READ_ID, 0x00, 0x00, 0x00}; + uint8_t data[2] = {0}; + + w25qxx_receive_data(cmd, 4, data, 2); + *manuf_id = data[0]; + *device_id = data[1]; + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_read_id_dma(uint8_t *manuf_id, uint8_t *device_id) +{ + uint8_t cmd[4] = {READ_ID, 0x00, 0x00, 0x00}; + uint8_t data[2] = {0}; + + w25qxx_receive_data_dma(cmd, 4, data, 2); + *manuf_id = data[0]; + *device_id = data[1]; + return W25QXX_OK; +} + +static enum w25qxx_status_t w25qxx_write_enable(void) +{ + uint8_t cmd[1] = {WRITE_ENABLE}; + + w25qxx_send_data(cmd, 1, 0, 0); + return W25QXX_OK; +} + +static enum w25qxx_status_t w25qxx_write_enable_dma(void) +{ + uint8_t cmd[1] = {WRITE_ENABLE}; + + w25qxx_send_data_dma(cmd, 1, 0, 0); + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_write_status_reg(uint8_t reg1_data, uint8_t reg2_data) +{ + uint8_t cmd[3] = {WRITE_REG1, reg1_data, reg2_data}; + + w25qxx_write_enable(); + w25qxx_send_data(cmd, 3, 0, 0); + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_write_status_reg_dma(uint8_t reg1_data, uint8_t reg2_data) +{ + uint8_t cmd[3] = {WRITE_REG1, reg1_data, reg2_data}; + + w25qxx_write_enable_dma(); + w25qxx_send_data_dma(cmd, 3, 0, 0); + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_read_status_reg1(uint8_t *reg_data) +{ + uint8_t cmd[1] = {READ_REG1}; + uint8_t data[1] = {0}; + + w25qxx_receive_data(cmd, 1, data, 1); + *reg_data = data[0]; + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_read_status_reg1_dma(uint8_t *reg_data) +{ + uint8_t cmd[1] = {READ_REG1}; + uint8_t data[1] = {0}; + + w25qxx_receive_data_dma(cmd, 1, data, 1); + *reg_data = data[0]; + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_read_status_reg2(uint8_t *reg_data) +{ + uint8_t cmd[1] = {READ_REG2}; + uint8_t data[1] = {0}; + + w25qxx_receive_data(cmd, 1, data, 1); + *reg_data = data[0]; + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_read_status_reg2_dma(uint8_t *reg_data) +{ + uint8_t cmd[1] = {READ_REG2}; + uint8_t data[1] = {0}; + + w25qxx_receive_data_dma(cmd, 1, data, 1); + *reg_data = data[0]; + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_is_busy(void) +{ + uint8_t status = 0; + + w25qxx_read_status_reg1(&status); + if (status & REG1_BUSY_MASK) + return W25QXX_BUSY; + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_is_busy_dma(void) +{ + uint8_t status = 0; + + w25qxx_read_status_reg1_dma(&status); + if (status & REG1_BUSY_MASK) + return W25QXX_BUSY; + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_sector_erase(uint32_t addr) +{ + uint8_t cmd[4] = {SECTOR_ERASE}; + + cmd[1] = (uint8_t)(addr >> 16); + cmd[2] = (uint8_t)(addr >> 8); + cmd[3] = (uint8_t)(addr); + w25qxx_write_enable(); + w25qxx_send_data(cmd, 4, 0, 0); + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_sector_erase_dma(uint32_t addr) +{ + uint8_t cmd[4] = {SECTOR_ERASE}; + + cmd[1] = (uint8_t)(addr >> 16); + cmd[2] = (uint8_t)(addr >> 8); + cmd[3] = (uint8_t)(addr); + w25qxx_write_enable_dma(); + w25qxx_send_data_dma(cmd, 4, 0, 0); + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_32k_block_erase(uint32_t addr) +{ + uint8_t cmd[4] = {BLOCK_32K_ERASE}; + + cmd[1] = (uint8_t)(addr >> 16); + cmd[2] = (uint8_t)(addr >> 8); + cmd[3] = (uint8_t)(addr); + w25qxx_write_enable(); + w25qxx_send_data(cmd, 4, 0, 0); + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_64k_block_erase(uint32_t addr) +{ + uint8_t cmd[4] = {BLOCK_64K_ERASE}; + + cmd[1] = (uint8_t)(addr >> 16); + cmd[2] = (uint8_t)(addr >> 8); + cmd[3] = (uint8_t)(addr); + w25qxx_write_enable(); + w25qxx_send_data(cmd, 4, 0, 0); + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_chip_erase(void) +{ + uint8_t cmd[1] = {CHIP_ERASE}; + + w25qxx_write_enable(); + w25qxx_send_data(cmd, 1, 0, 0); + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_enable_quad_mode(void) +{ + uint8_t reg_data = 0; + + w25qxx_read_status_reg2(®_data); + if (!(reg_data & REG2_QUAL_MASK)) + { + reg_data |= REG2_QUAL_MASK; + w25qxx_write_status_reg(0x00, reg_data); + } + w25qxx_page_program_fun = w25qxx_quad_page_program; + w25qxx_read_fun = w25qxx_quad_read_data; + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_enable_quad_mode_dma(void) +{ + uint8_t reg_data = 0; + + w25qxx_read_status_reg2_dma(®_data); + if (!(reg_data & REG2_QUAL_MASK)) + { + reg_data |= REG2_QUAL_MASK; + w25qxx_write_status_reg_dma(0x00, reg_data); + } + w25qxx_page_program_fun = w25qxx_quad_page_program_dma; + w25qxx_read_fun = w25qxx_quad_read_data; + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_disable_quad_mode(void) +{ + uint8_t reg_data = 0; + + w25qxx_read_status_reg2(®_data); + if (reg_data & REG2_QUAL_MASK) + { + reg_data &= (~REG2_QUAL_MASK); + w25qxx_write_status_reg(0x00, reg_data); + } + w25qxx_page_program_fun = w25qxx_page_program; + w25qxx_read_fun = w25qxx_stand_read_data; + return W25QXX_OK; +} + +static enum w25qxx_status_t w25qxx_page_program(uint32_t addr, uint8_t *data_buf, uint32_t length) +{ + uint8_t cmd[4] = {PAGE_PROGRAM}; + + cmd[1] = (uint8_t)(addr >> 16); + cmd[2] = (uint8_t)(addr >> 8); + cmd[3] = (uint8_t)(addr); + w25qxx_write_enable(); + w25qxx_send_data(cmd, 4, data_buf, length); + while (w25qxx_is_busy() == W25QXX_BUSY) + ; + return W25QXX_OK; +} + +static enum w25qxx_status_t w25qxx_page_program_dma(uint32_t addr, uint8_t *data_buf, uint32_t length) +{ + uint8_t cmd[4] = {PAGE_PROGRAM}; + + cmd[1] = (uint8_t)(addr >> 16); + cmd[2] = (uint8_t)(addr >> 8); + cmd[3] = (uint8_t)(addr); + w25qxx_write_enable_dma(); + w25qxx_send_data_dma(cmd, 4, data_buf, length); + while (w25qxx_is_busy_dma() == W25QXX_BUSY) + ; + return W25QXX_OK; +} + +static enum w25qxx_status_t w25qxx_quad_page_program(uint32_t addr, uint8_t *data_buf, uint32_t length) +{ + uint32_t cmd[2] = {0}; + + cmd[0] = QUAD_PAGE_PROGRAM; + cmd[1] = addr; + w25qxx_write_enable(); + spi_set_tmod(spi_bus_no, SPI_TMOD_TRANS); + spi_set_frame_format(spi_bus_no, SPI_FF_QUAD); + spi_trans_config(spi_bus_no, 8/*instrction length*/, 24/*address length*/, 0/*wait cycles*/, SPI_AITM_STANDARD/*spi address trans mode*/); + w25qxx_send_data_enhanced(cmd, 2, data_buf, length); + spi_set_frame_format(spi_bus_no, SPI_FF_STANDARD); + while (w25qxx_is_busy() == W25QXX_BUSY) + ; + return W25QXX_OK; +} + +static enum w25qxx_status_t w25qxx_quad_page_program_dma(uint32_t addr, uint8_t *data_buf, uint32_t length) +{ + uint32_t cmd[2] = {0}; + + cmd[0] = QUAD_PAGE_PROGRAM; + cmd[1] = addr; + w25qxx_write_enable_dma(); + spi_set_tmod(spi_bus_no, SPI_TMOD_TRANS); + spi_set_frame_format(spi_bus_no, SPI_FF_QUAD); + spi_trans_config(spi_bus_no, 8/*instrction length*/, 24/*address length*/, 0/*wait cycles*/, SPI_AITM_STANDARD/*spi address trans mode*/); + w25qxx_send_data_enhanced_dma(cmd, 2, data_buf, length); + spi_set_frame_format(spi_bus_no, SPI_FF_STANDARD); + while (w25qxx_is_busy_dma() == W25QXX_BUSY) + ; + return W25QXX_OK; +} + +static enum w25qxx_status_t w25qxx_sector_program(uint32_t addr, uint8_t *data_buf) +{ + uint8_t index = 0; + + for (index = 0; index < w25qxx_FLASH_PAGE_NUM_PER_SECTOR; index++) + { + w25qxx_page_program_fun(addr, data_buf, w25qxx_FLASH_PAGE_SIZE); + addr += w25qxx_FLASH_PAGE_SIZE; + data_buf += w25qxx_FLASH_PAGE_SIZE; + } + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_write_data(uint32_t addr, uint8_t *data_buf, uint32_t length) +{ + uint32_t sector_addr = 0; + uint32_t sector_offset = 0; + uint32_t sector_remain = 0; + uint32_t write_len = 0; + uint32_t index = 0; + uint8_t *pread = NULL; + uint8_t *pwrite = NULL; + uint8_t swap_buf[w25qxx_FLASH_SECTOR_SIZE] = {0}; + + while (length) + { + sector_addr = addr & (~(w25qxx_FLASH_SECTOR_SIZE - 1)); + sector_offset = addr & (w25qxx_FLASH_SECTOR_SIZE - 1); + sector_remain = w25qxx_FLASH_SECTOR_SIZE - sector_offset; + write_len = ((length < sector_remain) ? length : sector_remain); + w25qxx_read_fun(sector_addr, swap_buf, w25qxx_FLASH_SECTOR_SIZE); + pread = swap_buf + sector_offset; + pwrite = data_buf; + for (index = 0; index < write_len; index++) + { + if ((*pwrite) != ((*pwrite) & (*pread))) + { + w25qxx_sector_erase(sector_addr); + while (w25qxx_is_busy() == W25QXX_BUSY) + ; + break; + } + pwrite++; + pread++; + } + if (write_len == w25qxx_FLASH_SECTOR_SIZE) + { + w25qxx_sector_program(sector_addr, data_buf); + } + else + { + pread = swap_buf + sector_offset; + pwrite = data_buf; + for (index = 0; index < write_len; index++) + *pread++ = *pwrite++; + w25qxx_sector_program(sector_addr, swap_buf); + } + length -= write_len; + addr += write_len; + data_buf += write_len; + } + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_write_data_direct(uint32_t addr, uint8_t *data_buf, uint32_t length) +{ + uint32_t page_remain = 0; + uint32_t write_len = 0; + + while (length) + { + page_remain = w25qxx_FLASH_PAGE_SIZE - (addr & (w25qxx_FLASH_PAGE_SIZE - 1)); + write_len = ((length < page_remain) ? length : page_remain); + w25qxx_page_program_fun(addr, data_buf, write_len); + length -= write_len; + addr += write_len; + data_buf += write_len; + } + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_write_data_direct_dma(uint32_t addr, uint8_t *data_buf, uint32_t length) +{ + uint32_t page_remain = 0; + uint32_t write_len = 0; + + while (length) + { + page_remain = w25qxx_FLASH_PAGE_SIZE - (addr & (w25qxx_FLASH_PAGE_SIZE - 1)); + write_len = ((length < page_remain) ? length : page_remain); + w25qxx_page_program_fun(addr, data_buf, write_len); + length -= write_len; + addr += write_len; + data_buf += write_len; + } + return W25QXX_OK; +} + +static enum w25qxx_status_t _w25qxx_read_data(uint32_t addr, uint8_t *data_buf, uint32_t length, enum w25qxx_read_t mode) +{ + uint32_t cmd[2] = {0}; + + switch (mode) + { + case W25QXX_STANDARD: + *(((uint8_t *)cmd) + 0) = READ_DATA; + *(((uint8_t *)cmd) + 1) = (uint8_t)(addr >> 16); + *(((uint8_t *)cmd) + 2) = (uint8_t)(addr >> 8); + *(((uint8_t *)cmd) + 3) = (uint8_t)(addr >> 0); + w25qxx_receive_data((uint8_t *)cmd, 4, data_buf, length); + break; + case W25QXX_STANDARD_FAST: + *(((uint8_t *)cmd) + 0) = FAST_READ; + *(((uint8_t *)cmd) + 1) = (uint8_t)(addr >> 16); + *(((uint8_t *)cmd) + 2) = (uint8_t)(addr >> 8); + *(((uint8_t *)cmd) + 3) = (uint8_t)(addr >> 0); + *(((uint8_t *)cmd) + 4) = 0xFF; + w25qxx_receive_data((uint8_t *)cmd, 5, data_buf, length); + break; + case W25QXX_DUAL: + cmd[0] = FAST_READ_DUAL_OUTPUT; + cmd[1] = addr; + spi_set_tmod(spi_bus_no, SPI_TMOD_RECV); + spi_set_frame_format(spi_bus_no, SPI_FF_DUAL); + spi_trans_config(spi_bus_no, 8/*instrction length*/, 24/*address length*/, 8/*wait cycles*/, SPI_AITM_STANDARD/*spi address trans mode*/); + w25qxx_receive_data_enhanced(cmd, 2, data_buf, length); + break; + case W25QXX_DUAL_FAST: + cmd[0] = FAST_READ_DUAL_IO; + cmd[1] = addr << 8; + spi_set_tmod(spi_bus_no, SPI_TMOD_RECV); + spi_set_frame_format(spi_bus_no, SPI_FF_DUAL); + spi_trans_config(spi_bus_no, 8/*instrction length*/, 32/*address length*/, 0/*wait cycles*/, SPI_AITM_STANDARD/*spi address trans mode*/); + w25qxx_receive_data_enhanced(cmd, 2, data_buf, length); + break; + case W25QXX_QUAD: + cmd[0] = FAST_READ_QUAL_OUTPUT; + cmd[1] = addr; + spi_set_tmod(spi_bus_no, SPI_TMOD_RECV); + spi_set_frame_format(spi_bus_no, SPI_FF_QUAD); + spi_trans_config(spi_bus_no, 8/*instrction length*/, 24/*address length*/, 8/*wait cycles*/, SPI_AITM_STANDARD/*spi address trans mode*/); + w25qxx_receive_data_enhanced(cmd, 2, data_buf, length); + break; + case W25QXX_QUAD_FAST: + cmd[0] = FAST_READ_QUAL_IO; + cmd[1] = addr << 8; + spi_set_tmod(spi_bus_no, SPI_TMOD_RECV); + spi_set_frame_format(spi_bus_no, SPI_FF_QUAD); + spi_trans_config(spi_bus_no, 8/*instrction length*/, 32/*address length*/, 4/*wait cycles*/, SPI_AITM_STANDARD/*spi address trans mode*/); + w25qxx_receive_data_enhanced(cmd, 2, data_buf, length); + break; + } + spi_set_frame_format(spi_bus_no, SPI_AITM_STANDARD); + return W25QXX_OK; +} + +static enum w25qxx_status_t w25qxx_read_data_dma_less_1000bytes(uint32_t addr, uint8_t *data_buf, uint32_t length, enum w25qxx_read_t mode) +{ + uint32_t cmd[2] = {0}; + + switch (mode) { + case W25QXX_STANDARD: + *(((uint8_t *)cmd) + 0) = READ_DATA; + *(((uint8_t *)cmd) + 1) = (uint8_t)(addr >> 16); + *(((uint8_t *)cmd) + 2) = (uint8_t)(addr >> 8); + *(((uint8_t *)cmd) + 3) = (uint8_t)(addr >> 0); + w25qxx_receive_data_dma((uint8_t *)cmd, 4, data_buf, length); + break; + case W25QXX_STANDARD_FAST: + *(((uint8_t *)cmd) + 0) = FAST_READ; + *(((uint8_t *)cmd) + 1) = (uint8_t)(addr >> 16); + *(((uint8_t *)cmd) + 2) = (uint8_t)(addr >> 8); + *(((uint8_t *)cmd) + 3) = (uint8_t)(addr >> 0); + *(((uint8_t *)cmd) + 4) = 0xFF; + w25qxx_receive_data_dma((uint8_t *)cmd, 5, data_buf, length); + break; + case W25QXX_DUAL: + cmd[0] = FAST_READ_DUAL_OUTPUT; + cmd[1] = addr; + spi_set_tmod(spi_bus_no, SPI_TMOD_RECV); + spi_set_frame_format(spi_bus_no, SPI_FF_DUAL); + spi_trans_config(spi_bus_no, 8/*instrction length*/, 24/*address length*/, 8/*wait cycles*/, SPI_AITM_STANDARD/*spi address trans mode*/); + w25qxx_receive_data_enhanced_dma(cmd, 2, data_buf, length); + break; + case W25QXX_DUAL_FAST: + cmd[0] = FAST_READ_DUAL_IO; + cmd[1] = addr << 8; + spi_set_tmod(spi_bus_no, SPI_TMOD_RECV); + spi_set_frame_format(spi_bus_no, SPI_FF_DUAL); + spi_trans_config(spi_bus_no, 8/*instrction length*/, 32/*address length*/, 0/*wait cycles*/, SPI_AITM_ADDR_STANDARD/*spi address trans mode*/); + w25qxx_receive_data_enhanced_dma(cmd, 2, data_buf, length); + break; + case W25QXX_QUAD: + cmd[0] = FAST_READ_QUAL_OUTPUT; + cmd[1] = addr; + spi_set_tmod(spi_bus_no, SPI_TMOD_RECV); + spi_set_frame_format(spi_bus_no, SPI_FF_QUAD); + spi_trans_config(spi_bus_no, 8/*instrction length*/, 24/*address length*/, 8/*wait cycles*/, SPI_AITM_STANDARD/*spi address trans mode*/); + w25qxx_receive_data_enhanced_dma(cmd, 2, data_buf, length); + + break; + case W25QXX_QUAD_FAST: + cmd[0] = FAST_READ_QUAL_IO; + cmd[1] = addr << 8; + spi_set_tmod(spi_bus_no, SPI_TMOD_RECV); + spi_set_frame_format(spi_bus_no, SPI_FF_QUAD); + spi_trans_config(spi_bus_no, 8/*instrction length*/, 32/*address length*/, 4/*wait cycles*/, SPI_AITM_ADDR_STANDARD/*spi address trans mode*/); + w25qxx_receive_data_enhanced_dma(cmd, 2, data_buf, length); + break; + } + spi_set_frame_format(spi_bus_no, SPI_FF_STANDARD); + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_read_data(uint32_t addr, uint8_t *data_buf, uint32_t length, enum w25qxx_read_t mode) +{ + uint32_t len = 0; + + while (length) + { + len = ((length >= 0x010000) ? 0x010000 : length); + _w25qxx_read_data(addr, data_buf, len, mode); + addr += len; + data_buf += len; + length -= len; + } + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_read_data_dma(uint32_t addr, uint8_t *data_buf, uint32_t length, enum w25qxx_read_t mode) +{ + uint32_t len = 0; + + while (length) + { + len = ((length >= 0x010000) ? 0x010000 : length); + w25qxx_read_data_dma_less_1000bytes(addr, data_buf, len, mode); + addr += len; + data_buf += len; + length -= len; + } + return W25QXX_OK; +} + +static enum w25qxx_status_t w25qxx_stand_read_data(uint32_t addr, uint8_t *data_buf, uint32_t length) +{ + return w25qxx_read_data(addr, data_buf, length, W25QXX_STANDARD_FAST); +} + +static enum w25qxx_status_t w25qxx_quad_read_data(uint32_t addr, uint8_t *data_buf, uint32_t length) +{ + return w25qxx_read_data(addr, data_buf, length, W25QXX_QUAD_FAST); +} + +enum w25qxx_status_t w25qxx_enable_xip_mode(void) +{ + if (spi_handle != spi[3]) + return W25QXX_ERROR; + + spi_handle->xip_ctrl = (0x01 << 29) | (0x02 << 26) | (0x01 << 23) | (0x01 << 22) | (0x04 << 13) | + (0x01 << 12) | (0x02 << 9) | (0x06 << 4) | (0x01 << 2) | 0x02; + spi_handle->xip_incr_inst = 0xEB; + spi_handle->xip_mode_bits = 0x00; + spi_handle->xip_ser = 0x01; + spi_handle->ssienr = 0x01; + sysctl->peri.spi3_xip_en = 1; + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_disable_xip_mode(void) +{ + sysctl->peri.spi3_xip_en = 0; + return W25QXX_OK; +} + diff --git a/lib/math/fastexp.c b/lib/math/fastexp.c new file mode 100644 index 0000000..9745391 --- /dev/null +++ b/lib/math/fastexp.c @@ -0,0 +1,71 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "fastexp.h" +#include + +static inline float _fast_exp2f(float in) +{ + static const float p1 = 0.0f; + static const float p2 = 0.0f; + static const float p3 = 0.0f; + static const float p4 = 0.0f; + static const float p5 = 0.0f; + + float x1 = in; + float x2 = x1 * in; + float x3 = x2 * in; + float x4 = x3 * in; + + return x4 * p1 + x3 * p2 + x2 * p3 + x1 * p4 + p5; +} + + +float fast_exp2f(float x) +{ + union _float { + float f; + struct { + uint32_t frac : 23; + uint32_t expo : 8; + uint32_t sign : 1; + } data; + }; + + if (x < 0) + return 1.0f / fast_exp2f(-x); + + union _float f = {.f = 1.0f}; + + f.data.expo = (int)x + 127; + + return _fast_exp2f(x - (int)x) * f.f; +} + + +float fast_expf(float x) +{ + extern float __ieee754_expf(float x); + + return __ieee754_expf(x); +} + + +float fast_powf(float base, float expo) +{ + extern float __ieee754_powf(float base, float expo); + + return __ieee754_powf(base, expo); +} diff --git a/lib/math/fastexp.h b/lib/math/fastexp.h new file mode 100644 index 0000000..6db48e6 --- /dev/null +++ b/lib/math/fastexp.h @@ -0,0 +1,116 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef KENDRYTE_FAST_EXP +#define KENDRYTE_FAST_EXP + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * calc exp2f(x) + **/ +float fast_exp2f(float x); + +/** + * calc expf(x) + **/ +float fast_expf(float x); + +/** + * calc powf(base,expo) + **/ +float fast_powf(float base, float expo); + +/** + * calc exp2(x) + **/ +static inline double fast_exp2(double x) +{ + return fast_exp2f((float)x); +} + +/** + * calc exp(x) + **/ +static inline double fast_exp(double x) +{ + return fast_expf((float)x); +} + +/** + * calc pow(base,expo) + **/ +static inline double fast_pow(double base, double expo) +{ + return fast_powf((float)base, (float)expo); +} + +#ifdef __cplusplus +} +#endif + +#ifdef __cplusplus +#include +namespace std{ + template < typename... Args > + auto fast_pow(Args && ... args)->decltype(::fast_pow(std::forward < Args > (args)...)) { + return ::fast_pow(std::forward < Args > (args)...); + } + + template < typename... Args > + auto fast_powf(Args && ... args)->decltype(::fast_powf(std::forward < Args > (args)...)) { + return ::fast_powf(std::forward < Args > (args)...); + } + + template < typename... Args > + auto fast_exp(Args && ... args)->decltype(::fast_exp(std::forward < Args > (args)...)) { + return ::fast_exp(std::forward < Args > (args)...); + } + + template < typename... Args > + auto fast_expf(Args && ... args)->decltype(::fast_expf(std::forward < Args > (args)...)) { + return ::fast_expf(std::forward < Args > (args)...); + } + + template < typename... Args > + auto fast_exp2(Args && ... args)->decltype(fast_exp2(std::forward < Args > (args)...)) { + return ::fast_exp2(std::forward < Args > (args)...); + } + + template < typename... Args > + auto fast_exp2f(Args && ... args)->decltype(::fast_exp2f(std::forward < Args > (args)...)) { + return ::fast_exp2f(std::forward < Args > (args)...); + } +} +#endif + + + +#ifdef CONFIG_FAST_EXP_OVERRIDE +#define pow fast_pow +#define powf fast_powf +#define exp fast_exp +#define expf fast_expf +#define exp2 fast_exp2 +#define exp2f fast_exp2f + + +#endif + +#endif diff --git a/lib/utils/include/syslog.h b/lib/utils/include/syslog.h new file mode 100644 index 0000000..bea8dfa --- /dev/null +++ b/lib/utils/include/syslog.h @@ -0,0 +1,140 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _SYSLOG_H +#define _SYSLOG_H + +#include +#include +#include "printf.h" +#include "env/encoding.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Logging library + * + * Log library has two ways of managing log verbosity: compile time, set via + * menuconfig + * + * At compile time, filtering is done using CONFIG_LOG_DEFAULT_LEVEL macro, set via + * menuconfig. All logging statments for levels higher than CONFIG_LOG_DEFAULT_LEVEL + * will be removed by the preprocessor. + * + * + * How to use this library: + * + * In each C file which uses logging functionality, define TAG variable like this: + * + * static const char *TAG = "MODULE_NAME"; + * + * then use one of logging macros to produce output, e.g: + * + * LOGW(TAG, "Interrupt error %d", error); + * + * Several macros are available for different verbosity levels: + * + * LOGE - error + * LOGW - warning + * LOGI - info + * LOGD - debug + * LOGV - verbose + * + * To override default verbosity level at file or component scope, define LOG_LEVEL macro. + * At file scope, define it before including esp_log.h, e.g.: + * + * #define LOG_LEVEL LOG_VERBOSE + * #include "dxx_log.h" + * + * At component scope, define it in component makefile: + * + * CFLAGS += -D LOG_LEVEL=LOG_DEBUG + * + * + */ + +/* clang-format off */ +enum kendryte_log_level_e { + LOG_NONE, /*!< No log output */ + LOG_ERROR, /*!< Critical errors, software module can not recover on its own */ + LOG_WARN, /*!< Error conditions from which recovery measures have been taken */ + LOG_INFO, /*!< Information messages which describe normal flow of events */ + LOG_DEBUG, /*!< Extra information which is not necessary for normal use (values, pointers, sizes, etc). */ + LOG_VERBOSE /*!< Bigger chunks of debugging information, or frequent messages which can potentially flood the output. */ +}; +/* clang-format on */ + +/* clang-format off */ +#if CONFIG_LOG_COLORS +#define LOG_COLOR_BLACK "30" +#define LOG_COLOR_RED "31" +#define LOG_COLOR_GREEN "32" +#define LOG_COLOR_BROWN "33" +#define LOG_COLOR_BLUE "34" +#define LOG_COLOR_PURPLE "35" +#define LOG_COLOR_CYAN "36" +#define LOG_COLOR(COLOR) "\033[0;" COLOR "m" +#define LOG_BOLD(COLOR) "\033[1;" COLOR "m" +#define LOG_RESET_COLOR "\033[0m" +#define LOG_COLOR_E LOG_COLOR(LOG_COLOR_RED) +#define LOG_COLOR_W LOG_COLOR(LOG_COLOR_BROWN) +#define LOG_COLOR_I LOG_COLOR(LOG_COLOR_GREEN) +#define LOG_COLOR_D +#define LOG_COLOR_V +#else /* CONFIG_LOG_COLORS */ +#define LOG_COLOR_E +#define LOG_COLOR_W +#define LOG_COLOR_I +#define LOG_COLOR_D +#define LOG_COLOR_V +#define LOG_RESET_COLOR +#endif /* CONFIG_LOG_COLORS */ +/* clang-format on */ + +#define LOG_FORMAT(letter, format) LOG_COLOR_ ## letter #letter " (%lu) %s: " format LOG_RESET_COLOR "\n" + +#ifdef LOG_LEVEL +#undef CONFIG_LOG_LEVEL +#define CONFIG_LOG_LEVEL LOG_LEVEL +#endif + +#ifdef LOG_KERNEL +#define LOG_PRINTF printk +#else +#define LOG_PRINTF printf +#endif + +#ifdef CONFIG_LOG_ENABLE +#define LOGE(tag, format, ...) do {if (CONFIG_LOG_LEVEL >= LOG_ERROR) LOG_PRINTF(LOG_FORMAT(E, format), read_csr(mcycle), tag, ##__VA_ARGS__); } while (0) +#define LOGW(tag, format, ...) do {if (CONFIG_LOG_LEVEL >= LOG_WARN) LOG_PRINTF(LOG_FORMAT(W, format), read_csr(mcycle), tag, ##__VA_ARGS__); } while (0) +#define LOGI(tag, format, ...) do {if (CONFIG_LOG_LEVEL >= LOG_INFO) LOG_PRINTF(LOG_FORMAT(I, format), read_csr(mcycle), tag, ##__VA_ARGS__); } while (0) +#define LOGD(tag, format, ...) do {if (CONFIG_LOG_LEVEL >= LOG_DEBUG) LOG_PRINTF(LOG_FORMAT(D, format), read_csr(mcycle), tag, ##__VA_ARGS__); } while (0) +#define LOGV(tag, format, ...) do {if (CONFIG_LOG_LEVEL >= LOG_VERBOSE) LOG_PRINTF(LOG_FORMAT(V, format), read_csr(mcycle), tag, ##__VA_ARGS__); } while (0) +#else +#define LOGE(tag, format, ...) +#define LOGW(tag, format, ...) +#define LOGI(tag, format, ...) +#define LOGD(tag, format, ...) +#define LOGV(tag, format, ...) +#endif /* LOG_ENABLE */ + +#ifdef __cplusplus +} +#endif + + +#endif /* _SYSLOG_H */ + diff --git a/src/hello_world/main.c b/src/hello_world/main.c new file mode 100644 index 0000000..866e88c --- /dev/null +++ b/src/hello_world/main.c @@ -0,0 +1,32 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include "sleep.h" +int main() +{ + uint64_t core_id = read_csr(mhartid); + if (core_id == 0) + { + printf("Core 0 Hello, world!\n"); + } + else + { + msleep(100); + printf("Core 1 Hello, world!\n"); + } + while (1) + ; + return 0; +}