first commit
commit
685084c40a
|
@ -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-*
|
|
@ -0,0 +1,7 @@
|
|||
Changelog for Kendryte K210
|
||||
======
|
||||
|
||||
## 0.1.0
|
||||
|
||||
Kendryte K210 first SDK with FreeRTOS, have fun.
|
||||
|
|
@ -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)
|
||||
|
|
@ -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.
|
|
@ -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=<ProjectName> -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 <ProjectName>.bin to your flash.
|
||||
|
||||
This is very important, don't make a mistake in files.
|
|
@ -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)
|
|
@ -0,0 +1,3 @@
|
|||
prepend `common.cmake` before
|
||||
|
||||
append `executable.cmake` after
|
|
@ -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)
|
|
@ -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 ()
|
||||
|
|
@ -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("")
|
|
@ -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)
|
|
@ -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}")
|
|
@ -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()
|
|
@ -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()
|
|
@ -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 ()
|
|
@ -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 );
|
||||
}
|
||||
|
|
@ -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)
|
|
@ -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,
|
||||
|
||||
}
|
||||
};
|
||||
|
|
@ -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 <fpioa.h>
|
||||
|
||||
#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
|
||||
|
|
@ -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:
|
||||
|
|
@ -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.
|
||||
*/
|
||||
}
|
||||
|
|
@ -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 <stdlib.h>
|
||||
#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);
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#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 */
|
||||
|
|
@ -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 <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#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 */
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/* 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 <forward_list>
|
||||
namespace std
|
||||
{
|
||||
template <typename... Args>
|
||||
auto tfp_printf(Args&&... args) -> decltype(::tfp_printf(std::forward<Args>(args)...))
|
||||
{
|
||||
return ::tfp_printf(std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int printk(const char *format, ...) _TFP_SPECIFY_PRINTF_FMT(1, 2);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _BSP_PRINTF_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 */
|
||||
|
|
@ -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 <machine/syscall.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#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 */
|
||||
|
|
@ -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 <stdint.h>
|
||||
#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 <stdio.h>
|
||||
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 */
|
||||
|
|
@ -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 <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#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);
|
||||
}
|
||||
|
|
@ -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 <stddef.h>
|
||||
#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_<type>__ 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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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 <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/unistd.h>
|
||||
#include <machine/syscall.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#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);
|
||||
}
|
||||
|
|
@ -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 <stddef.h>
|
||||
#include <stdint.h>
|
||||
#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;
|
||||
}
|
||||
}
|
|
@ -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 <stddef.h>
|
||||
#include <stdint.h>
|
||||
#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");
|
||||
}
|
|
@ -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 <stddef.h>
|
||||
#include <stdint.h>
|
||||
#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;
|
||||
}
|
||||
|
|
@ -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 <stddef.h>
|
||||
#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);
|
||||
}
|
|
@ -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 <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#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 */
|
||||
}
|
|
@ -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 <stddef.h>
|
||||
#include <stdint.h>
|
||||
#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;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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 <stddef.h>
|
||||
#include <stdint.h>
|
||||
#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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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 <stddef.h>
|
||||
#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;
|
||||
}
|
|
@ -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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
#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;
|
||||
}
|
||||
|
|
@ -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 <stdint.h>
|
||||
#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 */
|
|
@ -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 */
|
|
@ -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 <stddef.h>
|
||||
#include <stdint.h>
|
||||
#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 */
|
||||
|
|
@ -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 <cstdbool>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#else /* __cplusplus */
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#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 */
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -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 */
|
|
@ -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 <stdint.h>
|
||||
#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 */
|
||||
|
|
@ -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 <inttypes.h>
|
||||
#include <stddef.h>
|
||||
#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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 <stdint.h>
|
||||
#include "platform.h"
|
||||
#include <stddef.h>
|
||||
#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 */
|
||||
|
|
@ -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 <stdint.h>
|
||||
#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 */
|
||||
|
|
@ -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 <stdint.h>
|
||||
#include <stddef.h>
|
||||
#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 */
|
File diff suppressed because it is too large
Load Diff
|
@ -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 <stdint.h>
|
||||
|
||||
#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 */
|
|
@ -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 <stdint.h>
|
||||
|
||||
/* 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
|
|
@ -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 <stdint.h>
|
||||
#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 */
|
|
@ -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 <stdint.h>
|
||||
#include <time.h>
|
||||
#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 */
|
|
@ -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 <stdint.h>
|
||||
#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
|
|
@ -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 <stdint.h>
|
||||
#include <stddef.h>
|
||||
#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 */
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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 <stdint.h>
|
||||
#include <stddef.h>
|
||||
#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 */
|
|
@ -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 <stdint.h>
|
||||
#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 */
|
|
@ -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 <stdint.h>
|
||||
#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 */
|
|
@ -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 <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <plic.h>
|
||||
|
||||
#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 */
|
|
@ -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;
|
||||
}
|
|
@ -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 <stddef.h>
|
||||
#include <stdint.h>
|
||||
#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;
|
||||
}
|
|
@ -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 <stdint.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#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;
|
||||
}
|
|
@ -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 <stddef.h>
|
||||
#include <stdint.h>
|
||||
#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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#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);
|
||||
}
|
|
@ -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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
#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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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 <stdint.h>
|
||||
|
||||
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
|
||||
|
|
@ -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 <stdint.h>
|
||||
|
||||
/* 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
|
||||
|
|
@ -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 <stdint.h>
|
||||
|
||||
/* 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
|
||||
|
|
@ -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 <stdint.h>
|
||||
|
||||
#define OV2640_ADDR 0x60
|
||||
|
||||
int ov2640_init(void);
|
||||
int ov2640_read_id(uint16_t *manuf_id, uint16_t *device_id);
|
||||
|
||||
#endif /* _OV2640_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 <stdint.h>
|
||||
|
||||
#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
|
||||
|
|
@ -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
|
||||
|
|
@ -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 <stdint.h>
|
||||
|
||||
#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
|
||||
|
|
@ -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 <stdint.h>
|
||||
|
||||
/* 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
|
||||
|
|
@ -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 <string.h>
|
||||
#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);
|
||||
}
|
||||
|
|
@ -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 <common.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
|
@ -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 <stdio.h>
|
||||
#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;
|
||||
}
|
||||
|
|
@ -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 <stdio.h>
|
||||
#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<sizeof(ov5640_init_reg_tbl) / 4; i++)
|
||||
{
|
||||
ov5640_wr_reg(ov5640_init_reg_tbl[i][0], ov5640_init_reg_tbl[i][1]);
|
||||
}
|
||||
|
||||
hal_delay(50);
|
||||
/* Test for flash light*/
|
||||
ov5640_flash_lamp(1);
|
||||
hal_delay(50);
|
||||
ov5640_flash_lamp(0);
|
||||
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void ov5640_flash_lamp(uint8_t sw)
|
||||
{
|
||||
ov5640_wr_reg(0x3016, 0X02);
|
||||
ov5640_wr_reg(0x301C, 0X02);
|
||||
if(sw)
|
||||
ov5640_wr_reg(0X3019, 0X02);
|
||||
else
|
||||
ov5640_wr_reg(0X3019, 0X00);
|
||||
}
|
||||
|
|
@ -0,0 +1,195 @@
|
|||
/* 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 <stdio.h>
|
||||
#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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 <stdint.h>
|
||||
|
||||
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);
|
||||
}
|
|
@ -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 <math.h>
|
||||
|
||||
#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 <forward_list>
|
||||
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
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue