├── .cproject ├── .gitignore ├── .project ├── LICENSE ├── Makefile ├── README.md ├── bsp ├── bootloader.lds └── settings.mk ├── debug.mk ├── release.mk └── src ├── boot ├── bootmain.c └── start.S ├── common ├── clkgen_ctrl_macro.h ├── comdef.h ├── div64.h ├── encoding.h ├── ezGPIO_fullMux_ctrl_macro.h ├── platform.h ├── rstgen_ctrl_macro.h ├── serial_printf.c ├── serial_printf.h ├── sys.c ├── sys.h ├── syscon_iopad_ctrl_macro.h ├── syscon_sysmain_ctrl_macro.h └── vic_module_reset_clkgen.h └── driver ├── spi ├── cadence_qspi.c ├── cadence_qspi.h ├── cadence_qspi_apb.c ├── spi.c ├── spi.h ├── spi_flash.c ├── spi_flash.h ├── spi_flash_internal.h └── spi_probe.c ├── timer ├── timer.c └── timer.h ├── uart ├── uart.c └── uart.h └── xmodem ├── crc16.c ├── crc16.h └── xmodem.c /.cproject: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /debug/ 2 | /release/ 3 | /.settings/ 4 | /docs/ -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | fw7110 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.cdt.managedbuilder.core.genmakebuilder 10 | clean,full,incremental, 11 | 12 | 13 | 14 | 15 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder 16 | full,incremental, 17 | 18 | 19 | 20 | 21 | 22 | org.eclipse.cdt.core.cnature 23 | org.eclipse.cdt.core.ccnature 24 | org.eclipse.cdt.managedbuilder.core.managedBuildNature 25 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature 26 | 27 | 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 Shanghai StarFive Technology Co., Ltd. 2 | SPDX-License-Identifier: GPL-2.0-or-later 3 | 4 | This code may be used, at your choice, under the terms of the GNU 5 | General Public License version 2.0 or later, available at 6 | https://www.gnu.org/licenses 7 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | # Copyright (c) 2020 StarFiveTech, Inc. 3 | 4 | EMPTY := 5 | SPACE := $(EMPTY) $(EMPTY) 6 | PROGRAM = jh7100_recovery_boot 7 | 8 | SUFFIX=$(shell date +%y%m%d) 9 | GIT_VERSION=$(shell git show -s --pretty=format:%h) 10 | VERSION=$(SUFFIX)-$(GIT_VERSION) 11 | 12 | ############################################################# 13 | # Makefile Arguments 14 | ############################################################# 15 | 16 | # The configuration defaults to Debug. Valid choices are: 17 | # - debug 18 | # - release 19 | CONFIGURATION ?= debug 20 | BSP_DIR ?= bsp 21 | 22 | ############################################################# 23 | # BSP loading 24 | ############################################################# 25 | 26 | # There must be a settings makefile fragment in the BSP's board directory. 27 | ifeq ($(wildcard $(BSP_DIR)/settings.mk),) 28 | $(error Unable to find BSP for $(TARGET), expected to find $(BSP_DIR)/settings.mk) 29 | endif 30 | 31 | # Include the BSP settings 32 | include $(BSP_DIR)/settings.mk 33 | 34 | # Check that settings.mk sets RISCV_ARCH and RISCV_ABI 35 | ifeq ($(RISCV_ARCH),) 36 | $(error $(BSP_DIR)/settings.mk must set RISCV_ARCH, the RISC-V ISA string to target) 37 | endif 38 | 39 | ifeq ($(RISCV_ABI),) 40 | $(error $(BSP_DIR)/settings.mk must set RISCV_ABI, the ABI to target) 41 | endif 42 | 43 | ifeq ($(RISCV_CMODEL),) 44 | RISCV_CMODEL = medany 45 | endif 46 | 47 | ifeq ($(LINK_TARGET),) 48 | LINK_TARGET = bootloader 49 | endif 50 | 51 | LINKER_SCRIPT = $(BSP_DIR)/$(LINK_TARGET).lds 52 | 53 | # Determines the XLEN from the toolchain tuple 54 | ifeq ($(patsubst rv32%,rv32,$(RISCV_ARCH)),rv32) 55 | RISCV_XLEN := 32 56 | else ifeq ($(patsubst rv64%,rv64,$(RISCV_ARCH)),rv64) 57 | RISCV_XLEN := 64 58 | else 59 | $(error Unable to determine XLEN from $(RISCV_ARCH)) 60 | endif 61 | 62 | ############################################################# 63 | # Toolchain 64 | ############################################################# 65 | 66 | # Allow users to select a different cross compiler. 67 | CROSS_COMPILE = riscv64-unknown-elf- 68 | 69 | # If users don't specify RISCV_PATH then assume that the tools will just be in 70 | # their path. 71 | ifeq ($(RISCV_PATH),) 72 | CC := $(CROSS_COMPILE)gcc 73 | CXX := $(CROSS_COMPILE)g++ 74 | OBJDUMP := $(CROSS_COMPILE)objdump 75 | OBJCOPY := $(CROSS_COMPILE)objcopy 76 | GDB := $(CROSS_COMPILE)gdb 77 | AR := $(CROSS_COMPILE)ar 78 | SIZE := $(CROSS_COMPILE)size 79 | else 80 | CC := $(abspath $(RISCV_PATH)/bin/$(CROSS_COMPILE)gcc) 81 | CXX := $(abspath $(RISCV_PATH)/bin/$(CROSS_COMPILE)g++) 82 | OBJDUMP := $(abspath $(RISCV_PATH)/bin/$(CROSS_COMPILE)objdump) 83 | OBJCOPY := $(abspath $(RISCV_PATH)/bin/$(CROSS_COMPILE)objcopy) 84 | GDB := $(abspath $(RISCV_PATH)/bin/$(CROSS_COMPILE)gdb) 85 | AR := $(abspath $(RISCV_PATH)/bin/$(CROSS_COMPILE)ar) 86 | SIZE := $(abspath $(RISCV_PATH)/bin/$(CROSS_COMPILE)size) 87 | PATH := $(abspath $(RISCV_PATH)/bin):$(PATH) 88 | endif 89 | 90 | ############################################################# 91 | # Software Flags 92 | ############################################################# 93 | 94 | # Set the arch, ABI, and code model 95 | CCASFLAGS += -march=$(RISCV_ARCH) -mabi=$(RISCV_ABI) -mcmodel=$(RISCV_CMODEL) -DVERSION=\"$(VERSION)\" -DCONFIGURATION=\"$(CONFIGURATION)\" 96 | CFLAGS += -march=$(RISCV_ARCH) -mabi=$(RISCV_ABI) -mcmodel=$(RISCV_CMODEL) -DVERSION=\"$(VERSION)\" -DCONFIGURATION=\"$(CONFIGURATION)\" 97 | CXXFLAGS += -march=$(RISCV_ARCH) -mabi=$(RISCV_ABI) -mcmodel=$(RISCV_CMODEL) -DVERSION=\"$(VERSION)\" -DCONFIGURATION=\"$(CONFIGURATION)\" 98 | ASFLAGS += -march=$(RISCV_ARCH) -mabi=$(RISCV_ABI) -mcmodel=$(RISCV_CMODEL) -DVERSION=\"$(VERSION)\" -DCONFIGURATION=\"$(CONFIGURATION)\" 99 | # Prune unused functions and data 100 | CFLAGS += -ffunction-sections -fdata-sections 101 | CXXFLAGS += -ffunction-sections -fdata-sections 102 | # Use newlib-nano 103 | CCASFLAGS += --specs=nano.specs 104 | CFLAGS += --specs=nano.specs 105 | CXXFLAGS += --specs=nano.specs 106 | LDFLAGS += --specs=nano.specs 107 | # DDR speed config for c code 108 | CFLAGS += -DDDR_SPEED=$(DDR_SPEED) 109 | 110 | # Set the arch, ABI, and code model 111 | LDFLAGS += -march=$(RISCV_ARCH) -mabi=$(RISCV_ABI) -mcmodel=$(RISCV_CMODEL) 112 | # Turn on garbage collection for unused sections 113 | LDFLAGS += -Wl,--gc-sections 114 | # Turn off the C standard library 115 | LDFLAGS += -nostartfiles -nostdlib 116 | # Find the linker scripts 117 | LDFLAGS += -T$(filter %.lds,$^) 118 | 119 | # Link to the relevant libraries 120 | LDLIBS += -Wl,--start-group -lc -lgcc -lm -Wl,--end-group 121 | 122 | # Load the configuration Makefile 123 | CONFIGURATION_FILE = $(wildcard $(CONFIGURATION).mk) 124 | ifeq ($(words $(CONFIGURATION_FILE)),0) 125 | $(error Unable to find the Makefile $(CONFIGURATION).mk for CONFIGURATION=$(CONFIGURATION)) 126 | endif 127 | include $(CONFIGURATION).mk 128 | 129 | ############################################################# 130 | # Software 131 | ############################################################# 132 | OUT_DIR = $(CONFIGURATION) 133 | OBJ_DIR = $(OUT_DIR)/objs 134 | PROGRAM_ELF = $(OUT_DIR)/$(PROGRAM).elf 135 | PROGRAM_BIN = $(OUT_DIR)/$(PROGRAM).bin 136 | PROGRAM_LST = $(OUT_DIR)/$(PROGRAM).lst 137 | 138 | ############################################################# 139 | # Makefile Functions 140 | ############################################################# 141 | 142 | # fn_srcfiles(dirs,ext) 143 | fn_srcfiles = $(foreach d,$(1),$(wildcard $(d)/*.$(2))) 144 | 145 | # fn_depfiles(dirs,ext) 146 | fn_depfiles = $(foreach f,$(call fn_srcfiles,$(1),$(2)),$(OBJ_DIR)/$(patsubst %.$(2),%.d,$(f))) 147 | 148 | # fn_objfiles(dirs,ext) 149 | fn_objfiles = $(foreach f,$(call fn_srcfiles,$(1),$(2)),$(OBJ_DIR)/$(patsubst %.$(2),%.o,$(f))) 150 | 151 | # fn_includes(dirs) 152 | fn_includes = $(addprefix -I,$(1)) 153 | 154 | ############################################################# 155 | # Include and Source Dirs 156 | ############################################################# 157 | INCLUDE_DIRS += \ 158 | src/boot \ 159 | src/common \ 160 | src/driver/uart \ 161 | src/driver/spi \ 162 | src/driver/gpio \ 163 | src/driver/timer \ 164 | 165 | SOURCE_DIRS += \ 166 | src/boot \ 167 | src/common \ 168 | src/driver/uart \ 169 | src/driver/spi \ 170 | src/driver/gpio \ 171 | src/driver/timer \ 172 | src/driver/xmodem \ 173 | 174 | INCLUDES = $(call fn_includes,$(INCLUDE_DIRS)) 175 | 176 | PROGRAM_SRCS = \ 177 | $(call fn_srcfiles,$(SOURCE_DIRS),S) \ 178 | $(call fn_srcfiles,$(SOURCE_DIRS),c) \ 179 | 180 | PROGRAM_OBJS = \ 181 | $(call fn_objfiles,$(SOURCE_DIRS),S) \ 182 | $(call fn_objfiles,$(SOURCE_DIRS),c) \ 183 | 184 | #VPATH := $(subst $(SPACE),:,$(SOURCE_DIRS) $(INCLUDE_DIRS)) 185 | 186 | ############################################################# 187 | # Makefile Targets 188 | ############################################################# 189 | all: $(PROGRAM_ELF) 190 | 191 | 192 | ############################################################# 193 | # Depenences 194 | ############################################################# 195 | PROGRAM_DEPS = \ 196 | $(call fn_depfiles,$(SOURCE_DIRS),S) \ 197 | $(call fn_depfiles,$(SOURCE_DIRS),c) \ 198 | 199 | ifneq ($(strip $(PROGRAM_DEPS)),) 200 | sinclude $(PROGRAM_DEPS) 201 | endif 202 | 203 | ############################################################# 204 | # Makefile Rules 205 | ############################################################# 206 | 207 | $(PROGRAM_ELF): $(PROGRAM_OBJS) $(LINKER_SCRIPT) 208 | @echo Building target: $@, VERSION=$(VERSION) 209 | @echo Invoking: GNU RISC-V Cross C Linker 210 | @if [ ! -d "$(@D)" ]; then mkdir -p "$(@D)"; fi 211 | $(CC) $(LDFLAGS) -Wl,-Map,"$(@:%.elf=%.map)" $(filter %.o,$^) $(LDLIBS) -o $@ 212 | @echo Finished building target: $@ 213 | @$(OBJDUMP) --source --all-headers --demangle --line-numbers --wide $@ > $(PROGRAM_LST) 214 | @$(OBJCOPY) -O binary $@ $(PROGRAM_BIN) 215 | 216 | $(OBJ_DIR)/%.o: %.c 217 | @if [ ! -d "$(@D)" ]; then mkdir -p "$(@D)"; fi 218 | @echo cc $< 219 | $(CC) $(CFLAGS) $(INCLUDES) -MMD -MP -MF"$(@:%.o=%.d)" -MT"$@" -c -o $@ $< 220 | 221 | $(OBJ_DIR)/%.o: %.S 222 | @if [ ! -d "$(@D)" ]; then mkdir -p "$(@D)"; fi 223 | @echo cc $< 224 | $(CC) $(CFLAGS) $(INCLUDES) -MMD -MP -MF"$(@:%.o=%.d)" -MT"$@" -c -o $@ $< 225 | 226 | .PHONY: debug 227 | debug: 228 | @echo ----- INCLUDES: 229 | @echo $(INCLUDES) 230 | @echo ----- PROGRAM_SRCS: 231 | @echo $(PROGRAM_SRCS) 232 | @echo ----- PROGRAM_ELF: 233 | @echo $(PROGRAM_ELF) 234 | @echo ----- PROGRAM_DEPS: 235 | @echo $(PROGRAM_DEPS) 236 | @echo ----- PROGRAM_OBJS: 237 | @echo $(PROGRAM_OBJS) 238 | 239 | .PHONY: clean 240 | clean: 241 | rm -rf $(OUT_DIR) 242 | 243 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cross Compile 2 | Download compiler according to your enviroment as the below link: 3 | 4 | https://github.com/sifive/freedom-tools/releases/tag/v2020.12.0 5 | 6 | Add the compiler to your PATH: 7 | 8 | export PATH=/home/user/compiler/bin:$PATH 9 | 10 | # Build 11 | Enter the project directory, generate the jh7100_recovery_boot.bin file in debug directory after make 12 | 13 | # Upgrade 14 | Follow the recovery tools and instruction as the below link to recover the bootloader 15 | https://github.com/kprasadvnsi/JH71xx-tools 16 | -------------------------------------------------------------------------------- /bsp/bootloader.lds: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | /* Copyright (c) 2020 StarFiveTech, Inc */ 3 | OUTPUT_ARCH( "riscv" ) 4 | 5 | ENTRY( _start ) 6 | 7 | MEMORY 8 | { 9 | rom (rxai!w) : ORIGIN = 0x18000000, LENGTH = 32K 10 | ram (wxa!ri) : ORIGIN = 0x18008000, LENGTH = 32K 11 | } 12 | 13 | PHDRS 14 | { 15 | rom PT_LOAD; 16 | ram_init PT_LOAD; 17 | ram PT_NULL; 18 | } 19 | 20 | SECTIONS 21 | { 22 | __stack_size = DEFINED(__stack_size) ? __stack_size : 2K; 23 | 24 | .init : 25 | { 26 | KEEP (*(SORT_NONE(.init))) 27 | } >rom AT>rom :rom 28 | 29 | .text : 30 | { 31 | *(.text.unlikely .text.unlikely.*) 32 | *(.text.startup .text.startup.*) 33 | *(.text .text.*) 34 | *(.gnu.linkonce.t.*) 35 | } >rom AT>rom :rom 36 | 37 | .fini : 38 | { 39 | KEEP (*(SORT_NONE(.fini))) 40 | } >rom AT>rom :rom 41 | 42 | PROVIDE (__etext = .); 43 | PROVIDE (_etext = .); 44 | PROVIDE (etext = .); 45 | 46 | .rodata : 47 | { 48 | *(.rdata) 49 | *(.rodata .rodata.*) 50 | *(.gnu.linkonce.r.*) 51 | } >rom AT>rom :rom 52 | 53 | . = ALIGN(4); 54 | 55 | .preinit_array : 56 | { 57 | PROVIDE_HIDDEN (__preinit_array_start = .); 58 | KEEP (*(.preinit_array)) 59 | PROVIDE_HIDDEN (__preinit_array_end = .); 60 | } >rom AT>rom :rom 61 | 62 | .init_array : 63 | { 64 | PROVIDE_HIDDEN (__init_array_start = .); 65 | KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) 66 | KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) 67 | PROVIDE_HIDDEN (__init_array_end = .); 68 | } >rom AT>rom :rom 69 | 70 | .fini_array : 71 | { 72 | PROVIDE_HIDDEN (__fini_array_start = .); 73 | KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) 74 | KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) 75 | PROVIDE_HIDDEN (__fini_array_end = .); 76 | } >rom AT>rom :rom 77 | 78 | .ctors : 79 | { 80 | /* gcc uses crtbegin.o to find the start of 81 | the constructors, so we make sure it is 82 | first. Because this is a wildcard, it 83 | doesn't matter if the user does not 84 | actually link against crtbegin.o; the 85 | linker won't look for a file to match a 86 | wildcard. The wildcard also means that it 87 | doesn't matter which directory crtbegin.o 88 | is in. */ 89 | KEEP (*crtbegin.o(.ctors)) 90 | KEEP (*crtbegin?.o(.ctors)) 91 | /* We don't want to include the .ctor section from 92 | the crtend.o file until after the sorted ctors. 93 | The .ctor section from the crtend file contains the 94 | end of ctors marker and it must be last */ 95 | KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) 96 | KEEP (*(SORT(.ctors.*))) 97 | KEEP (*(.ctors)) 98 | } >rom AT>rom :rom 99 | 100 | .dtors : 101 | { 102 | KEEP (*crtbegin.o(.dtors)) 103 | KEEP (*crtbegin?.o(.dtors)) 104 | KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) 105 | KEEP (*(SORT(.dtors.*))) 106 | KEEP (*(.dtors)) 107 | } >rom AT>rom :rom 108 | 109 | .lalign : 110 | { 111 | . = ALIGN(4); 112 | PROVIDE( _data_lma = . ); 113 | } >ram AT>rom :rom 114 | 115 | .dalign : 116 | { 117 | . = ALIGN(4); 118 | PROVIDE( _data = . ); 119 | } >ram AT>rom :rom 120 | 121 | .data : 122 | { 123 | *(.data .data.*) 124 | *(.gnu.linkonce.d.*) 125 | . = ALIGN(8); 126 | PROVIDE( __global_pointer$ = . + 0x800 ); 127 | *(.sdata .sdata.*) 128 | *(.gnu.linkonce.s.*) 129 | . = ALIGN(8); 130 | *(.srodata.cst16) 131 | *(.srodata.cst8) 132 | *(.srodata.cst4) 133 | *(.srodata.cst2) 134 | *(.srodata .srodata.*) 135 | } >ram AT>rom :ram_init 136 | 137 | . = ALIGN(4); 138 | PROVIDE( _edata = . ); 139 | PROVIDE( edata = . ); 140 | 141 | PROVIDE( _fbss = . ); 142 | PROVIDE( __bss_start = . ); 143 | .bss : 144 | { 145 | *(.sbss*) 146 | *(.gnu.linkonce.sb.*) 147 | *(.bss .bss.*) 148 | *(.gnu.linkonce.b.*) 149 | *(COMMON) 150 | . = ALIGN(4); 151 | } >ram AT>ram :ram 152 | 153 | . = ALIGN(8); 154 | PROVIDE( _end = . ); 155 | PROVIDE( end = . ); 156 | 157 | .stack ORIGIN(ram) + LENGTH(ram) - __stack_size : 158 | { 159 | PROVIDE( _heap_end = . ); 160 | . = __stack_size; 161 | PROVIDE( _sp = . ); 162 | } >ram AT>ram :ram 163 | } 164 | -------------------------------------------------------------------------------- /bsp/settings.mk: -------------------------------------------------------------------------------- 1 | # Copyright 2019 SiFive, Inc # 2 | # SPDX-License-Identifier: Apache-2.0 # 3 | # ----------------------------------- # 4 | # ----------------------------------- # 5 | 6 | RISCV_ARCH=rv64imafdc 7 | RISCV_ABI=lp64d 8 | #RISCV_ABI=lp64f 9 | RISCV_CMODEL=medany 10 | RISCV_SERIES=sifive-7-series 11 | 12 | TARGET_TAGS=board openocd 13 | TARGET_DHRY_ITERS=20000000 14 | TARGET_CORE_ITERS=5000 15 | -------------------------------------------------------------------------------- /debug.mk: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0-or-later 2 | # Copyright (c) 2020 StarFiveTech, Inc 3 | ################################################### 4 | # Build Flags for the Debug Configuration 5 | ################################################### 6 | 7 | # Set the optimization level 8 | ASFLAGS += -O0 9 | CFLAGS += -O0 10 | CXXFLAGS += -O0 11 | 12 | # Enable debug 13 | ASFLAGS += -g 14 | CFLAGS += -g 15 | CXXFLAGS += -g 16 | 17 | -------------------------------------------------------------------------------- /release.mk: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0-or-later 2 | # Copyright (c) 2020 StarFiveTech, Inc 3 | ################################################### 4 | # Build Flags for the Release Configuration 5 | ################################################### 6 | 7 | # Set the optimization level 8 | ASFLAGS += -Os 9 | CFLAGS += -Os 10 | CXXFLAGS += -Os 11 | -------------------------------------------------------------------------------- /src/boot/bootmain.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | /** 3 | ****************************************************************************** 4 | * @file bootmain.c 5 | * @author StarFive Technology 6 | * @version V1.0 7 | * @date 07/24/2020 8 | * @brief 9 | ****************************************************************************** 10 | * @copy 11 | * 12 | * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS 13 | * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE 14 | * TIME. AS A RESULT, STARFIVE SHALL NOT BE HELD LIABLE FOR ANY 15 | * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING 16 | * FROM THE CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE 17 | * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. 18 | * 19 | * COPYRIGHT 2020 Shanghai StarFive Technology Co., Ltd. 20 | */ 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #define PRINT(fmt, ...) serial_printf(fmt, ##__VA_ARGS__) 32 | #define ERROR(fmt, ...) serial_printf("ERROR %s() ln %d:" fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__) 33 | 34 | extern unsigned int receive_count; 35 | int spi_flash_erases(struct spi_flash *spi_flash_local, u32 start_addr, int num_block) 36 | { 37 | int ret; 38 | int l = 0;; 39 | int k, j, page_par_block = 0; 40 | u32 len = 0, offset_new = start_addr; 41 | u32 i, block_size,page_size; 42 | 43 | block_size = spi_flash_local->block_size; 44 | page_size = spi_flash_local->page_size; 45 | len = page_size; 46 | page_par_block = block_size/page_size; 47 | for(l = 0; l < num_block; l++) 48 | { 49 | ret = spi_flash_local->erase(spi_flash_local, offset_new, block_size, 64); 50 | if(ret != 0) 51 | { 52 | return ret; 53 | } 54 | offset_new += block_size; 55 | 56 | } 57 | return ret; 58 | 59 | } 60 | 61 | int spi_flash_writes(struct spi_flash* spi_flash_local, u32 start_addr,u8 *data_buff, u32 page_num) 62 | { 63 | int k = 0,i = 0,j = 0,ret = 0; 64 | u32 offset_new = start_addr; 65 | unsigned char *data = (unsigned char *)data_buff; 66 | int spi_write = 1; // or 4 67 | 68 | int len = spi_flash_local->page_size; 69 | 70 | for(k = 0; k < page_num; k++) 71 | { 72 | ret = spi_flash_local->write(spi_flash_local, offset_new, len, (void*)data, spi_write); 73 | if(ret != 0) 74 | { 75 | return -1; 76 | } 77 | offset_new = offset_new + len; 78 | data = data + len; 79 | 80 | } 81 | return ret; 82 | } 83 | int updata_flash(u32 flash_addr) 84 | { 85 | int ret = 0; 86 | struct spi_flash* flash; 87 | u32 len = 0; 88 | int erase_block = 0; 89 | unsigned int page_count; 90 | unsigned int file_size = 0; 91 | // receive_count = 0; 92 | rlSendString("send a file by xmodem\r\n"); 93 | // replace xmodem_recv_file, which may have too many errors to receive the file 94 | ret = xmodemReceive((unsigned char *)DEFAULT_BOOT_LOAD_ADDR, 192*1024); 95 | if(ret <= 0) 96 | return -1; 97 | file_size = ret; 98 | 99 | cadence_qspi_init(0, 1); 100 | flash = spi_flash_probe(0, 0, 10000000, 0, (u32)SPI_DATAMODE_8); 101 | if (!flash) { 102 | rlSendString("spi_flash_probe fail\r\n"); 103 | return -1; 104 | } 105 | erase_block = (file_size + flash->block_size - 1) / flash->block_size; 106 | page_count = (file_size + flash->page_size - 1) / flash->page_size; 107 | 108 | ret = spi_flash_erases(flash, flash_addr, erase_block); 109 | if(ret < 0) 110 | { 111 | rlSendString("spi_flash_erases fail\r\n"); 112 | return -1; 113 | } 114 | 115 | ret = spi_flash_writes(flash, flash_addr, (u8 *)DEFAULT_BOOT_LOAD_ADDR, page_count); 116 | if(ret < 0) 117 | { 118 | rlSendString("spi_flash_writes fail\r\n"); 119 | return -1; 120 | } 121 | else 122 | { 123 | rlSendString("updata flash ok\r\n"); 124 | } 125 | return 0; 126 | } 127 | 128 | static int updata_flash_code(unsigned int updata_num) 129 | { 130 | int ret = 0; 131 | switch (updata_num){ 132 | case 0: 133 | ret = updata_flash(FLASH_SECONDBOOT_START_ADDR); 134 | break; 135 | case 1: 136 | ret = updata_flash(FLASH_DDRINIT_START_ADDR); 137 | break; 138 | default: 139 | break; 140 | 141 | } 142 | 143 | return ret; 144 | 145 | } 146 | static void chip_clk_init() 147 | { 148 | _SWITCH_CLOCK_clk_cpundbus_root_SOURCE_clk_pll0_out_; 149 | _SWITCH_CLOCK_clk_dla_root_SOURCE_clk_pll1_out_; 150 | _SWITCH_CLOCK_clk_dsp_root_SOURCE_clk_pll2_out_; 151 | _SWITCH_CLOCK_clk_perh0_root_SOURCE_clk_pll0_out_; 152 | } 153 | void BootMain(void) 154 | { 155 | int boot_mode = 0; 156 | s32 usel; 157 | int i; 158 | char str[128]; 159 | int ret = 0; 160 | int bootdelay = SECONDBOOTDELAY; 161 | unsigned long ts; 162 | int abort = 0; 163 | 164 | chip_clk_init(); 165 | 166 | _SET_SYSCON_REG_register50_SCFG_funcshare_pad_ctrl_18(0x00c000c0); 167 | 168 | _CLEAR_RESET_rstgen_rstn_usbnoc_axi_; 169 | _CLEAR_RESET_rstgen_rstn_hifi4noc_axi_; 170 | 171 | _ENABLE_CLOCK_clk_x2c_axi_; 172 | _CLEAR_RESET_rstgen_rstn_x2c_axi_; 173 | 174 | _CLEAR_RESET_rstgen_rstn_dspx2c_axi_; 175 | _CLEAR_RESET_rstgen_rstn_dma1p_axi_; 176 | 177 | _ENABLE_CLOCK_clk_msi_apb_; 178 | _CLEAR_RESET_rstgen_rstn_msi_apb_; 179 | 180 | _ASSERT_RESET_rstgen_rstn_x2c_axi_; 181 | _CLEAR_RESET_rstgen_rstn_x2c_axi_; 182 | 183 | uart_init(3); 184 | 185 | PRINT("\r\nVIC second boot, version:%s %s\n", VERSION, CONFIGURATION); 186 | while(1) 187 | { 188 | rlSendString("***************************************************\r\n"); 189 | rlSendString("***************JH7100 recovery boot ***************\r\n"); 190 | rlSendString("***************************************************\r\n"); 191 | 192 | rlSendString("0:updata bootloader\r\n"); 193 | rlSendString("1:updata ddr init\r\n"); 194 | again: 195 | rlSendString("Select the function to test : "); 196 | serial_gets(str); 197 | 198 | if(str[0] == 0) 199 | goto again; 200 | 201 | usel = atoi(str); 202 | if(usel > 2) 203 | { 204 | rlSendString("error select,try again\r\n"); 205 | goto again; 206 | } 207 | PRINT("\r\nselect %d\n", usel); 208 | ret = updata_flash_code(usel); 209 | if(ret < 0) 210 | rlSendString("updata fail\r\n"); 211 | else 212 | { 213 | rlSendString("updata success\r\n"); 214 | } 215 | 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /src/boot/start.S: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | /** 3 | ****************************************************************************** 4 | * @file start.S 5 | * @author StarFive Technology 6 | * @version V1.0 7 | * @date 07/29/2020 8 | * @brief 9 | ****************************************************************************** 10 | * @copy 11 | * 12 | * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS 13 | * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE 14 | * TIME. AS A RESULT, STARFIVE SHALL NOT BE HELD LIABLE FOR ANY 15 | * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING 16 | * FROM THE CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE 17 | * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. 18 | * 19 | * COPYRIGHT 2020 Shanghai StarFive Technology Co., Ltd. 20 | */ 21 | #include "encoding.h" 22 | 23 | /* This is defined in sifive/platform.h, but that can't be included from 24 | * assembly. */ 25 | .section .init 26 | .globl _start 27 | .type _start,@function 28 | 29 | _start: 30 | .cfi_startproc 31 | .cfi_undefined ra 32 | .option push 33 | .option norelax 34 | la gp, __global_pointer$ 35 | .option pop 36 | la sp, _sp 37 | 38 | csrr a0, mhartid 39 | li a1, 0 40 | li a2, 0 41 | /* Increment by hartid number of stack sizes */ 42 | li t0, 0 43 | la t1, __stack_size 44 | 1: 45 | beq t0, a0, 1f 46 | add sp, sp, t1 47 | addi t0, t0, 1 48 | j 1b 49 | 1: 50 | andi sp, sp, -16 51 | 52 | csrr a0, mhartid 53 | bnez a0, hart1_loop 54 | j start_boot_main 55 | 56 | hart1_loop: 57 | /* j hart1_loop */ 58 | li a2, MIP_MSIP 59 | csrw mie, a2 60 | wfi 61 | /*call second_main */ 62 | 63 | start_boot_main: 64 | #if 0 65 | /* Load data section */ 66 | la t0, _data_lma 67 | la t1, _data 68 | la t2, _edata 69 | bgeu t1, t2, 2f 70 | 1: 71 | ld a0, 0(t0) 72 | addi t0, t0, 8 73 | sd a0, 0(t1) 74 | addi t1, t1, 8 75 | blt t1, t2, 1b 76 | 2: 77 | #endif 78 | /* Clear bss section */ 79 | la t1, __bss_start 80 | la t2, _end 81 | bgeu t1, t2, 2f 82 | 1: 83 | sd x0, 0(t1) 84 | addi t1, t1, 8 85 | blt t1, t2, 1b 86 | 2: 87 | 88 | /* Call global constructors */ 89 | //la a0, __libc_fini_array 90 | //call atexit 91 | //call __libc_init_array 92 | 93 | #ifndef __riscv_float_abi_soft 94 | /* Enable FPU */ 95 | li t0, MSTATUS_FS 96 | csrs mstatus, t0 97 | csrr t1, mstatus 98 | and t1, t1, t0 99 | beqz t1, 1f 100 | fssr x0 101 | 1: 102 | #endif 103 | 104 | #if defined(ENABLE_SMP) 105 | smp_resume(t0, t1) 106 | 107 | csrr a0, mhartid 108 | bnez a0, 2f 109 | #endif 110 | 111 | auipc ra, 0 112 | addi sp, sp, -16 113 | #if __riscv_xlen == 32 114 | sw ra, 8(sp) 115 | #else 116 | sd ra, 8(sp) 117 | #endif 118 | 119 | /* argc = argv = 0 */ 120 | li a0, 0 121 | li a1, 0 122 | call BootMain 123 | //tail exit 124 | 1: 125 | j 1b 126 | 127 | .cfi_endproc 128 | -------------------------------------------------------------------------------- /src/common/comdef.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | /** 3 | ****************************************************************************** 4 | * @file comdef.h 5 | * @author StarFive Technology 6 | * @version V1.0 7 | * @date 07/20/2020 8 | * @brief 9 | ****************************************************************************** 10 | * @copy 11 | * 12 | * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS 13 | * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE 14 | * TIME. AS A RESULT, STARFIVE SHALL NOT BE HELD LIABLE FOR ANY 15 | * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING 16 | * FROM THE CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE 17 | * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. 18 | * 19 | * COPYRIGHT 2020 Shanghai StarFive Technology Co., Ltd. 20 | */ 21 | 22 | 23 | #ifndef _COMDEF_H_ 24 | #define _COMDEF_H_ 25 | 26 | typedef unsigned char UINT8; 27 | typedef unsigned char UCHAR; 28 | typedef unsigned short UINT16; 29 | typedef unsigned int UINT32; 30 | typedef unsigned short int WCHAR; 31 | typedef unsigned short int UNICODE; 32 | typedef unsigned long UINT64; 33 | typedef int INT64; 34 | typedef int INT32; 35 | typedef short int INT16; 36 | typedef char INT8; 37 | typedef char CHAR; 38 | typedef unsigned short int bool; 39 | typedef unsigned short int STATUS_T; 40 | typedef signed char s8; 41 | typedef unsigned char u8; 42 | typedef signed short s16; 43 | typedef unsigned short u16; 44 | typedef signed int s32; 45 | typedef unsigned int u32; 46 | typedef unsigned long u64; 47 | //typedef int ssize_t; 48 | typedef unsigned char uint8_t; 49 | typedef unsigned short uint16_t; 50 | typedef unsigned int uint32_t; 51 | typedef unsigned long uintptr_t; 52 | typedef unsigned long uint64_t; 53 | typedef signed long s64; 54 | typedef unsigned long long u128; 55 | #define NULL 0 56 | 57 | #define FALSE 0 58 | #define TRUE 1 59 | #define typeof __typeof__ 60 | 61 | #define ARCH_DMA_MINALIGN 32 62 | 63 | 64 | #define BIT_0 0x00000001 65 | #define BIT_1 0x00000002 66 | #define BIT_2 0x00000004 67 | #define BIT_3 0x00000008 68 | #define BIT_4 0x00000010 69 | #define BIT_5 0x00000020 70 | #define BIT_6 0x00000040 71 | #define BIT_7 0x00000080 72 | #define BIT_8 0x00000100 73 | #define BIT_9 0x00000200 74 | #define BIT_10 0x00000400 75 | #define BIT_11 0x00000800 76 | #define BIT_12 0x00001000 77 | #define BIT_13 0x00002000 78 | #define BIT_14 0x00004000 79 | #define BIT_15 0x00008000 80 | #define BIT_16 0x00010000 81 | #define BIT_17 0x00020000 82 | #define BIT_18 0x00040000 83 | #define BIT_19 0x00080000 84 | #define BIT_20 0x00100000 85 | #define BIT_21 0x00200000 86 | #define BIT_22 0x00400000 87 | #define BIT_23 0x00800000 88 | #define BIT_24 0x01000000 89 | #define BIT_25 0x02000000 90 | #define BIT_26 0x04000000 91 | #define BIT_27 0x08000000 92 | #define BIT_28 0x10000000 93 | #define BIT_29 0x20000000 94 | #define BIT_30 0x40000000 95 | #define BIT_31 0x80000000 96 | 97 | #define RSP_SUCCESS 0 98 | #define RSP_GENERAL_FAIL 1 99 | 100 | #ifndef BIT 101 | #define BIT(x) (1UL << (x)) 102 | #endif 103 | 104 | #ifndef writeq 105 | static inline void writeq(u64 val, volatile void *addr) 106 | { 107 | asm volatile("sd %0, 0(%1)" : : "r" (val), "r" (addr)); 108 | } 109 | #endif 110 | 111 | #ifndef readq 112 | static inline u64 readq(volatile void *addr) 113 | { 114 | u64 val; 115 | 116 | asm volatile("ld %0, 0(%1)" : "=r" (val) : "r" (addr)); 117 | return val; 118 | } 119 | #endif 120 | 121 | #ifndef writel 122 | static inline void writel(u32 val, volatile void *addr) 123 | { 124 | asm volatile("sw %0, 0(%1)" : : "r" (val), "r" (addr)); 125 | } 126 | #endif 127 | 128 | #ifndef readl 129 | static inline u32 readl(volatile void *addr) 130 | { 131 | u32 val; 132 | 133 | asm volatile("lw %0, 0(%1)" : "=r" (val) : "r" (addr)); 134 | return val; 135 | } 136 | #endif 137 | 138 | #ifndef writew 139 | 140 | static inline void writew(u16 val, volatile void *addr) 141 | { 142 | asm volatile("sh %0, 0(%1)" : : "r" (val), "r" (addr)); 143 | } 144 | #endif 145 | 146 | #ifndef readw 147 | static inline u16 readw(const volatile void *addr) 148 | { 149 | u16 val; 150 | 151 | asm volatile("lh %0, 0(%1)" : "=r" (val) : "r" (addr)); 152 | return val; 153 | } 154 | #endif 155 | 156 | 157 | #define inpb(port) (*((volatile UINT8 *) (port))) 158 | #define inph(port) (*((volatile UINT16*) (port))) 159 | #define inpw(port) (*((volatile UINT32*) (port))) 160 | 161 | #define outpb(port, val) (*((volatile UINT8 *) (port)) = ((UINT8 ) (val))) 162 | #define outph(port, val) (*((volatile UINT16*) (port)) = ((UINT16) (val))) 163 | #define outpw(port, val) (*((volatile UINT32*) (port)) = ((UINT32) (val))) 164 | 165 | #define MA_INB( io ) (UINT8 ) inpb( io ) 166 | #define MA_INH( io ) (UINT16) inph( io ) 167 | #define MA_INW( io ) (UINT32) inpw( io ) 168 | 169 | #define MA_INBM( io, mask ) ( inpb( io ) & (mask) ) 170 | #define MA_INHM( io, mask ) ( inph( io ) & (mask) ) 171 | #define MA_INWM( io, mask ) ( inpw( io ) & (mask) ) 172 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 173 | /* The `const' in roundup() prevents gcc-3.3 from calling __divdi3 */ 174 | #define roundup(x, y) ( \ 175 | { \ 176 | const typeof(y) __y = y; \ 177 | (((x) + (__y - 1)) / __y) * __y; \ 178 | } \ 179 | ) 180 | #define LOG2(x) (((x & 0xaaaaaaaa) ? 1 : 0) + ((x & 0xcccccccc) ? 2 : 0) + \ 181 | ((x & 0xf0f0f0f0) ? 4 : 0) + ((x & 0xff00ff00) ? 8 : 0) + \ 182 | ((x & 0xffff0000) ? 16 : 0)) 183 | 184 | #define ___swab32(x) \ 185 | ((u32)( \ 186 | (((u32)(x) & (u32)0x000000ffUL) << 24) | \ 187 | (((u32)(x) & (u32)0x0000ff00UL) << 8) | \ 188 | (((u32)(x) & (u32)0x00ff0000UL) >> 8) | \ 189 | (((u32)(x) & (u32)0xff000000UL) >> 24) )) 190 | #define __be32_to_cpu(x) ___swab32((u32)(x)) 191 | #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) 192 | 193 | #define MA_OUTB( io, val )\ 194 | {\ 195 | outpb( io, val );\ 196 | } 197 | 198 | #define MA_OUTH( io, val )\ 199 | {\ 200 | outph( io, val );\ 201 | } 202 | 203 | #define MA_OUTW( io, val )\ 204 | {\ 205 | outpw( io, val );\ 206 | } 207 | 208 | #define MA_OUTBM( io, mask, val ) \ 209 | {\ 210 | UINT8 temp;\ 211 | (temp) =(((MA_INW(io) & (UINT8)(~(mask))) | ((UINT8)((val) & (mask)))));\ 212 | outpb( io, temp );\ 213 | } 214 | 215 | #define MA_OUTHM( io, mask, val ) \ 216 | {\ 217 | UINT16 temp;\ 218 | (temp) =(((MA_INH(io) & (UINT16)(~(mask))) |((UINT16)((val) & (mask)))));\ 219 | outph( io, temp );\ 220 | } 221 | 222 | #define MA_OUTWM( io, mask, val ) \ 223 | {\ 224 | UINT32 temp;\ 225 | (temp) =(((MA_INW(io) & (UINT32)(~(mask))) |((UINT32)((val) & (mask)))));\ 226 | outpw( io, temp );\ 227 | } 228 | #define min(x,y) ((x)<(y)?(x):(y)) 229 | #define min3(x, y, z) min(min(x, y), z) 230 | 231 | #define max(x, y) ((x)>(y)?(x):(y)) 232 | 233 | #define ROUND(a,b) (((a) + (b) - 1) & ~((b) - 1)) 234 | 235 | #define apb_write(addr, data) ((*(volatile unsigned int *) (addr)) = ((u32)data)) 236 | #define apb_read(addr) (*((volatile unsigned int*) (addr))) 237 | 238 | #define ALIGN(x,a) __ALIGN_MASK((x),(typeof(x))(a)-1) 239 | #define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask)) 240 | 241 | #define PAD_COUNT(s, pad) (((s) - 1) / (pad) + 1) 242 | #define PAD_SIZE(s, pad) (PAD_COUNT(s, pad) * pad) 243 | #define ALLOC_ALIGN_BUFFER_PAD(type, name, size, align, pad) \ 244 | char __##name[ROUND(PAD_SIZE((size) * sizeof(type), pad), align) \ 245 | + (align - 1)]; \ 246 | type *name = (type *)ALIGN((uintptr_t)__##name, align) 247 | #define ALLOC_ALIGN_BUFFER(type, name, size, align) \ 248 | ALLOC_ALIGN_BUFFER_PAD(type, name, size, align, 1) 249 | #define ALLOC_CACHE_ALIGN_BUFFER_PAD(type, name, size, pad) \ 250 | ALLOC_ALIGN_BUFFER_PAD(type, name, size, ARCH_DMA_MINALIGN, pad) 251 | #define ALLOC_CACHE_ALIGN_BUFFER(type, name, size) \ 252 | ALLOC_ALIGN_BUFFER(type, name, size, ARCH_DMA_MINALIGN) 253 | 254 | #ifndef false 255 | #define false (0) 256 | #endif 257 | 258 | #ifndef true 259 | #define true (1) 260 | #endif 261 | static void delay(unsigned int timer) 262 | { 263 | int i; 264 | for(i = 0; i < timer; i++); 265 | } 266 | 267 | #endif 268 | -------------------------------------------------------------------------------- /src/common/div64.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASM_GENERIC_DIV64_H 2 | #define _ASM_GENERIC_DIV64_H 3 | /* 4 | * Copyright (C) 2003 Bernardo Innocenti 5 | * Based on former asm-ppc/div64.h and asm-m68knommu/div64.h 6 | * 7 | * The semantics of do_div() are: 8 | * 9 | * u32 do_div(UINT64 *n, u32 base) 10 | * { 11 | * u32 remainder = *n % base; 12 | * *n = *n / base; 13 | * return remainder; 14 | * } 15 | * 16 | * NOTE: macro parameter n is evaluated multiple times, 17 | * beware of side effects! 18 | */ 19 | 20 | //#include 21 | #include 22 | 23 | static unsigned int __div64_32(UINT64 *n, unsigned int base) 24 | { 25 | UINT64 rem = *n; 26 | UINT64 b = base; 27 | UINT64 res, d = 1; 28 | unsigned int high = rem >> 32; 29 | 30 | /* Reduce the thing a bit first */ 31 | res = 0; 32 | if (high >= base) { 33 | high /= base; 34 | res = (UINT64) high << 32; 35 | rem -= (UINT64) (high*base) << 32; 36 | } 37 | 38 | while ((s64)b > 0 && b < rem) { 39 | b = b+b; 40 | d = d+d; 41 | } 42 | 43 | do { 44 | if (rem >= b) { 45 | rem -= b; 46 | res += d; 47 | } 48 | b >>= 1; 49 | d >>= 1; 50 | } while (d); 51 | 52 | *n = res; 53 | return rem; 54 | } 55 | 56 | /* The unnecessary pointer compare is there 57 | * to check for type safety (n must be 64bit) 58 | */ 59 | # define do_div(n,base) ({ \ 60 | u32 __base = (base); \ 61 | u32 __rem; \ 62 | (void)(((typeof((n)) *)0) == ((UINT64 *)0)); \ 63 | if (((n) >> 32) == 0) { \ 64 | __rem = (u32)(n) % __base; \ 65 | (n) = (u32)(n) / __base; \ 66 | } else \ 67 | __rem = __div64_32(&(n), __base); \ 68 | __rem; \ 69 | }) 70 | 71 | /* Wrapper for do_div(). Doesn't modify dividend and returns 72 | * the result, not reminder. 73 | */ 74 | static inline UINT64 lldiv(UINT64 dividend, u32 divisor) 75 | { 76 | UINT64 __res = dividend; 77 | do_div(__res, divisor); 78 | return(__res); 79 | } 80 | 81 | static inline UINT64 div_u64_rem(UINT64 dividend, u32 divisor, u32 *remainder) 82 | { 83 | *remainder = dividend % divisor; 84 | return dividend / divisor; 85 | } 86 | 87 | #endif /* _ASM_GENERIC_DIV64_H */ 88 | -------------------------------------------------------------------------------- /src/common/platform.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | /** 3 | ****************************************************************************** 4 | * @file platform.h 5 | * @author StarFive Technology 6 | * @version V1.0 7 | * @date 07/20/2020 8 | * @brief 9 | ****************************************************************************** 10 | * @copy 11 | * 12 | * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS 13 | * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE 14 | * TIME. AS A RESULT, STARFIVE SHALL NOT BE HELD LIABLE FOR ANY 15 | * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING 16 | * FROM THE CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE 17 | * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. 18 | * 19 | * COPYRIGHT 2020 Shanghai StarFive Technology Co., Ltd. 20 | */ 21 | 22 | #ifndef PLATFORM_H_ 23 | #define PLATFORM_H_ 24 | 25 | #ifdef __ASSEMBLER__ 26 | #define _AC(X,Y) X 27 | #define _AT(T,X) X 28 | #else 29 | #define _AC(X,Y) (X##Y) 30 | #define _AT(T,X) ((T)(X)) 31 | #endif /* !__ASSEMBLER__*/ 32 | 33 | 34 | /**************************************************************************** 35 | * Platform definitions 36 | *****************************************************************************/ 37 | 38 | // CPU info 39 | #define NUM_CORES 2 40 | #define MAX_HART_ID 1 41 | 42 | // The hart that non-SMP tests should run on 43 | #ifndef NONSMP_HART 44 | #define NONSMP_HART 0 45 | #endif 46 | 47 | 48 | // Memory map 49 | #define CLINT_CTRL_ADDR _AC(0x2000000,UL) 50 | #define CLINT_CTRL_SIZE _AC(0x10000,UL) 51 | #define CLINT_CTRL_MTIME _AC(0x200BFF8,UL) 52 | #define CLINT_CTRL_HART0_MTIMECMP _AC(0x2004000,UL) 53 | #define CLINT_CTRL_HART1_MTIMECMP _AC(0x2004008,UL) 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /src/common/serial_printf.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | /** 3 | ****************************************************************************** 4 | * @file serial_printf.c 5 | * @author StarFive Technology 6 | * @version V1.0 7 | * @date 07/10/2021 8 | * @brief 9 | ****************************************************************************** 10 | * @copy 11 | * 12 | * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS 13 | * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE 14 | * TIME. AS A RESULT, STARFIVE SHALL NOT BE HELD LIABLE FOR ANY 15 | * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING 16 | * FROM THE CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE 17 | * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. 18 | * 19 | * COPYRIGHT 2020 Shanghai StarFive Technology Co., Ltd. 20 | */ 21 | 22 | #include 23 | #include 24 | #include "serial_printf.h" 25 | #include "comdef.h" 26 | #include "sys.h" 27 | 28 | #ifdef RTL_SIM 29 | static int putchar(int ch, void** data) 30 | { 31 | data = data; // unused param 32 | MA_OUTW(SYSCON_SIMU_TEST_BASE_ADDR + 0x4, ch); 33 | return 0; 34 | } 35 | 36 | #else 37 | static int putchar(int ch, void** data) 38 | { 39 | data = data; // unused param 40 | if (ch=='\n') 41 | _putc('\r'); 42 | return _putc(ch) == 0 ? ch : -1; 43 | } 44 | #endif 45 | 46 | static void sprintf_putch(int ch, void** data) 47 | { 48 | char** pstr = (char**)data; 49 | **pstr = ch; 50 | (*pstr)++; 51 | } 52 | 53 | static unsigned long getuint(va_list *ap, int lflag) 54 | { 55 | if (lflag) 56 | return va_arg(*ap, unsigned long); 57 | else 58 | return va_arg(*ap, unsigned int); 59 | } 60 | 61 | static long getint(va_list *ap, int lflag) 62 | { 63 | if (lflag) 64 | return va_arg(*ap, long); 65 | else 66 | return va_arg(*ap, int); 67 | } 68 | 69 | static inline void printnum(void (*putch)(int, void**), void **putdat, 70 | unsigned long num, unsigned base, int width, int padc) 71 | { 72 | unsigned digs[sizeof(num)*8]; 73 | int pos = 0; 74 | 75 | while (1) 76 | { 77 | digs[pos++] = num % base; 78 | if (num < base) 79 | break; 80 | num /= base; 81 | } 82 | 83 | while (width-- > pos) 84 | putch(padc, putdat); 85 | 86 | while (pos-- > 0) 87 | putch(digs[pos] + (digs[pos] >= 10 ? 'a' - 10 : '0'), putdat); 88 | } 89 | 90 | static inline void print_double(void (*putch)(int, void**), void **putdat, 91 | double num, int width, int prec) 92 | { 93 | union { 94 | double d; 95 | uint64_t u; 96 | } u; 97 | u.d = num; 98 | 99 | if (u.u & (1ULL << 63)) { 100 | putch('-', putdat); 101 | u.u &= ~(1ULL << 63); 102 | } 103 | 104 | for (int i = 0; i < prec; i++) 105 | u.d *= 10; 106 | 107 | char buf[32], *pbuf = buf; 108 | printnum(sprintf_putch, (void**)&pbuf, (unsigned long)u.d, 10, 0, 0); 109 | if (prec > 0) { 110 | for (int i = 0; i < prec; i++) { 111 | pbuf[-i] = pbuf[-i-1]; 112 | } 113 | pbuf[-prec] = '.'; 114 | pbuf++; 115 | } 116 | 117 | for (char* p = buf; p < pbuf; p++) 118 | putch(*p, putdat); 119 | } 120 | 121 | static void vprintfmt(void (*putch)(int, void**), void **putdat, const char *fmt, va_list ap) 122 | { 123 | register const char* p; 124 | const char* last_fmt; 125 | register int ch, err; 126 | unsigned long num; 127 | int base, lflag, width, precision, altflag; 128 | char padc; 129 | 130 | while (1) { 131 | while ((ch = *(unsigned char *) fmt) != '%') { 132 | if (ch == '\0') 133 | return; 134 | fmt++; 135 | putch(ch, putdat); 136 | } 137 | fmt++; 138 | 139 | // Process a %-escape sequence 140 | last_fmt = fmt; 141 | padc = ' '; 142 | width = -1; 143 | precision = -1; 144 | lflag = 0; 145 | altflag = 0; 146 | reswitch: 147 | switch (ch = *(unsigned char *) fmt++) { 148 | 149 | // flag to pad on the right 150 | case '-': 151 | padc = '-'; 152 | goto reswitch; 153 | 154 | // flag to pad with 0's instead of spaces 155 | case '0': 156 | padc = '0'; 157 | goto reswitch; 158 | 159 | // width field 160 | case '1': 161 | case '2': 162 | case '3': 163 | case '4': 164 | case '5': 165 | case '6': 166 | case '7': 167 | case '8': 168 | case '9': 169 | for (precision = 0; ; ++fmt) { 170 | precision = precision * 10 + ch - '0'; 171 | ch = *fmt; 172 | if (ch < '0' || ch > '9') 173 | break; 174 | } 175 | goto process_precision; 176 | 177 | case '*': 178 | precision = va_arg(ap, int); 179 | goto process_precision; 180 | 181 | case '.': 182 | if (width < 0) 183 | width = 0; 184 | goto reswitch; 185 | 186 | case '#': 187 | altflag = 1; 188 | goto reswitch; 189 | 190 | process_precision: 191 | if (width < 0) 192 | width = precision, precision = -1; 193 | goto reswitch; 194 | 195 | // long flag 196 | case 'l': 197 | if (lflag) 198 | goto bad; 199 | goto reswitch; 200 | 201 | // character 202 | case 'c': 203 | putch(va_arg(ap, int), putdat); 204 | break; 205 | 206 | // double 207 | case 'f': 208 | print_double(putch, putdat, va_arg(ap, double), width, precision); 209 | break; 210 | 211 | // string 212 | case 's': 213 | if ((p = va_arg(ap, char *)) == NULL) 214 | p = "(null)"; 215 | if (width > 0 && padc != '-') 216 | for (width -= strnlen(p, precision); width > 0; width--) 217 | putch(padc, putdat); 218 | for (; (ch = *p) != '\0' && (precision < 0 || --precision >= 0); width--) { 219 | putch(ch, putdat); 220 | p++; 221 | } 222 | for (; width > 0; width--) 223 | putch(' ', putdat); 224 | break; 225 | 226 | // (signed) decimal 227 | case 'd': 228 | num = getint(&ap, lflag); 229 | if ((long) num < 0) { 230 | putch('-', putdat); 231 | num = -(long) num; 232 | } 233 | base = 10; 234 | goto signed_number; 235 | 236 | // unsigned decimal 237 | case 'u': 238 | base = 10; 239 | goto unsigned_number; 240 | 241 | // (unsigned) octal 242 | case 'o': 243 | // should do something with padding so it's always 3 octits 244 | base = 8; 245 | goto unsigned_number; 246 | 247 | // pointer 248 | case 'p': 249 | lflag = 1; 250 | putch('0', putdat); 251 | putch('x', putdat); 252 | /* fall through to 'x' */ 253 | 254 | // (unsigned) hexadecimal 255 | case 'x': 256 | base = 16; 257 | unsigned_number: 258 | num = getuint(&ap, lflag); 259 | signed_number: 260 | printnum(putch, putdat, num, base, width, padc); 261 | break; 262 | 263 | // escaped '%' character 264 | case '%': 265 | putch(ch, putdat); 266 | break; 267 | 268 | // unrecognized escape sequence - just print it literally 269 | default: 270 | bad: 271 | putch('%', putdat); 272 | fmt = last_fmt; 273 | break; 274 | } 275 | } 276 | } 277 | 278 | int serial_printf(const char* fmt, ...) 279 | { 280 | va_list ap; 281 | va_start(ap, fmt); 282 | 283 | vprintfmt((void*)putchar, 0, fmt, ap); 284 | 285 | va_end(ap); 286 | return 0; // incorrect return value, but who cares, anyway? 287 | } 288 | 289 | -------------------------------------------------------------------------------- /src/common/serial_printf.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | /** 3 | ****************************************************************************** 4 | * @file serial_printf.h 5 | * @author StarFive Technology 6 | * @version V1.0 7 | * @date 07/22/2020 8 | * @brief 9 | ****************************************************************************** 10 | * @copy 11 | * 12 | * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS 13 | * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE 14 | * TIME. AS A RESULT, STARFIVE SHALL NOT BE HELD LIABLE FOR ANY 15 | * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING 16 | * FROM THE CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE 17 | * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. 18 | * 19 | * COPYRIGHT 2020 Shanghai StarFive Technology Co., Ltd. 20 | */ 21 | #ifndef __SERIAL_PRINTF_H 22 | #define __SERIAL_PRINTF_H 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif /* __cplusplus */ 27 | 28 | int serial_printf(const char* fmt, ...); 29 | 30 | #ifdef __cplusplus 31 | } 32 | #endif /* __cplusplus */ 33 | 34 | #endif /* __SERIAL_PRINTF_H */ 35 | 36 | -------------------------------------------------------------------------------- /src/common/sys.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | /** 3 | ****************************************************************************** 4 | * @file sys.c 5 | * @author StarFive Technology 6 | * @version V1.0 7 | * @date 07/10/2021 8 | * @brief 9 | ****************************************************************************** 10 | * @copy 11 | * 12 | * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS 13 | * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE 14 | * TIME. AS A RESULT, STARFIVE SHALL NOT BE HELD LIABLE FOR ANY 15 | * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING 16 | * FROM THE CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE 17 | * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. 18 | * 19 | * COPYRIGHT 2020 Shanghai StarFive Technology Co., Ltd. 20 | */ 21 | #include "sys.h" 22 | #include "comdef.h" 23 | //unsigned int funcpll_432 = 0; 24 | //unsigned int osc_clk = 0; 25 | 26 | /*=========================================================================== 27 | FUNCTION: sys_memcpy 28 | 29 | DESCRIPTION: 30 | copy one block memory to another position 31 | 32 | INPUT PARAMETER: 33 | void *p_des: destination address 34 | const void * p_src: source address 35 | unsigned long size: length of memory to copy (unit is byte) 36 | 37 | OUTPUT PARAMETER: 38 | 39 | RETURN VALUE: 40 | ===========================================================================*/ 41 | void sys_memcpy(void *dest,const void * src,unsigned long count) 42 | { 43 | unsigned long *dl = (unsigned long *)dest, *sl = (unsigned long *)src; 44 | char *d8, *s8; 45 | 46 | if (src == dest) 47 | return dest; 48 | 49 | /* while all data is aligned (common case), copy a word at a time */ 50 | if ( (((unsigned long)dest | (unsigned long)src) & (sizeof(*dl) - 1)) == 0) { 51 | while (count >= sizeof(*dl)) { 52 | *dl++ = *sl++; 53 | count -= sizeof(*dl); 54 | } 55 | } 56 | /* copy the reset one byte at a time */ 57 | d8 = (char *)dl; 58 | s8 = (char *)sl; 59 | while (count--) 60 | *d8++ = *s8++; 61 | } 62 | int sys_memcmp(const void * cs,const void * ct,unsigned int count) 63 | { 64 | const unsigned char *su1, *su2; 65 | int res = 0; 66 | 67 | for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--) 68 | if ((res = *su1 - *su2) != 0) 69 | break; 70 | return res; 71 | } 72 | void * _memcpy(void * dest,const void *src,unsigned int count) 73 | { 74 | char *tmp = (char *) dest; 75 | const char *s = (char *) src; 76 | 77 | while (count--) 78 | *tmp++ = *s++; 79 | return dest; 80 | } 81 | /*=========================================================================== 82 | FUNCTION: sys_memcpy_32 83 | 84 | DESCRIPTION: 85 | copy one block memory to another position 86 | caller guarantee the src/des address are DWORD allign 87 | 88 | INPUT PARAMETER: 89 | void *p_des: destination address 90 | const void * p_src: source address 91 | unsigned long size: length of memory to copy (unit is DWORD) 92 | 93 | OUTPUT PARAMETER: 94 | 95 | RETURN VALUE: 96 | ===========================================================================*/ 97 | void sys_memcpy_32(void *p_des,const void * p_src,unsigned long size) 98 | { 99 | unsigned long i; 100 | for (i=0;i 4 | * 5 | * SPDX-License-Identifier: GPL-2.0+ 6 | */ 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | struct cadence_spi_slave 16 | { 17 | struct spi_slave slave; 18 | u32 base; 19 | int irq; 20 | }; 21 | 22 | struct spi_operation cadence_spi4x_func; 23 | struct cadence_spi_platdata cadence_plat; 24 | struct cadence_spi_priv spi_priv; 25 | struct cadence_spi_slave vic_spi_slave; 26 | 27 | #define CQSPI_STIG_READ 0 28 | #define CQSPI_STIG_WRITE 1 29 | #define CQSPI_INDIRECT_READ 2 30 | #define CQSPI_INDIRECT_WRITE 3 31 | #define CADENCE_QSPI_MAX_HZ QSPI_CLK 32 | #define CONFIG_CQSPI_REF_CLK QSPI_REF_CLK 33 | #define CONFIG_CQSPI_DECODER 0 34 | static int cadence_spi_write_speed(unsigned int hz) 35 | { 36 | struct cadence_spi_platdata *plat = &cadence_plat; 37 | struct cadence_spi_priv *priv = &spi_priv; 38 | 39 | cadence_qspi_apb_config_baudrate_div(priv->regbase, 40 | CONFIG_CQSPI_REF_CLK, hz); 41 | 42 | /* Reconfigure delay timing if speed is changed. */ 43 | cadence_qspi_apb_delay(priv->regbase, CONFIG_CQSPI_REF_CLK, hz, 44 | plat->tshsl_ns, plat->tsd2d_ns, 45 | plat->tchsh_ns, plat->tslch_ns); 46 | 47 | return 0; 48 | } 49 | 50 | /* Calibration sequence to determine the read data capture delay register */ 51 | static int spi_calibration(unsigned int hz, unsigned int cs) 52 | { 53 | struct cadence_spi_priv *priv = &spi_priv; 54 | void * base = priv->regbase; 55 | u8 opcode_rdid = 0x9F; 56 | unsigned int idcode = 0, temp = 0; 57 | int err = 0, i, range_lo = -1, range_hi = -1; 58 | 59 | /* start with slowest clock (1 MHz) */ 60 | cadence_spi_write_speed(500000); 61 | 62 | /* configure the read data capture delay register to 0 */ 63 | cadence_qspi_apb_readdata_capture(base, 1, 0); 64 | /* Enable QSPI */ 65 | cadence_qspi_apb_controller_enable(base); 66 | 67 | /* read the ID which will be our golden value */ 68 | err = cadence_qspi_apb_command_read(base, 1, &opcode_rdid, 69 | 3, (u8 *)&idcode); 70 | if (err) { 71 | //uart_printf("SF: Calibration failed (read)\n"); 72 | return err; 73 | } 74 | 75 | /* use back the intended clock and find low range */ 76 | cadence_spi_write_speed(hz); 77 | for (i = 0; i < CQSPI_READ_CAPTURE_MAX_DELAY; i++) { 78 | /* Disable QSPI */ 79 | cadence_qspi_apb_controller_disable(base); 80 | 81 | /* reconfigure the read data capture delay register */ 82 | cadence_qspi_apb_readdata_capture(base, 1, i); 83 | /* Enable back QSPI */ 84 | cadence_qspi_apb_controller_enable(base); 85 | 86 | /* issue a RDID to get the ID value */ 87 | err = cadence_qspi_apb_command_read(base, 1, &opcode_rdid, 88 | 3, (u8 *)&temp); 89 | if (err) { 90 | //uart_printf("SF: Calibration failed (read)\n"); 91 | return err; 92 | } 93 | 94 | /* search for range lo */ 95 | if (range_lo == -1 && temp == idcode) { 96 | range_lo = i; 97 | continue; 98 | } 99 | 100 | /* search for range hi */ 101 | if (range_lo != -1 && temp != idcode) { 102 | range_hi = i - 1; 103 | break; 104 | } 105 | range_hi = i; 106 | } 107 | 108 | if (range_lo == -1) { 109 | //uart_printf("SF: Calibration failed (low range)\n"); 110 | return err; 111 | } 112 | /* Disable QSPI for subsequent initialization */ 113 | cadence_qspi_apb_controller_disable(base); 114 | 115 | /* configure the final value for read data capture delay register */ 116 | cadence_qspi_apb_readdata_capture(base, 1, (range_hi + range_lo) / 2); 117 | //uart_printf("SF: Read data capture delay calibrated to %i (%i - %i)\n", 118 | //(range_hi + range_lo) / 2, range_lo, range_hi); 119 | 120 | /* just to ensure we do once only when speed or chip select change */ 121 | priv->qspi_calibrated_hz = hz; 122 | priv->qspi_calibrated_cs = cs; 123 | 124 | return 0; 125 | } 126 | 127 | struct spi_slave *cadence_spi4x_setup_slave(unsigned int bus, unsigned int cs, 128 | unsigned int max_hz, u32 mode, u32 fifo_width) 129 | { 130 | 131 | struct cadence_spi_slave *spi4slave; 132 | struct cadence_spi_platdata *plat = &cadence_plat; 133 | struct cadence_spi_priv *priv = &spi_priv; 134 | u32 base = 0; 135 | int err = 0; 136 | u32 clk_pol; 137 | u32 clk_pha; 138 | 139 | spi4slave = &vic_spi_slave; 140 | 141 | spi4slave->base = (void *)QSPI_BASE_ADDR; 142 | clk_pol = (mode & SPI_CPOL) ? 1 : 0; 143 | clk_pha = (mode & SPI_CPHA) ? 1 : 0; 144 | 145 | 146 | plat->regbase = (void *)QSPI_BASE_ADDR; 147 | plat->ahbbase = (void *)QSPI_BASE_AHB_ADDR; 148 | plat->max_hz = CADENCE_QSPI_MAX_HZ; 149 | 150 | 151 | /****default set, may change******/ 152 | plat->tshsl_ns = 200; 153 | plat->tsd2d_ns = 255; 154 | plat->tchsh_ns = 2; 155 | plat->tslch_ns = 20; 156 | plat->sram_size = 256; 157 | 158 | plat->block_size = 16; 159 | plat->page_size = 256; 160 | 161 | priv->regbase = plat->regbase; 162 | priv->ahbbase = plat->ahbbase; 163 | 164 | /* Disable QSPI */ 165 | cadence_qspi_apb_controller_disable(priv->regbase); 166 | 167 | /* Set SPI mode */ 168 | cadence_qspi_apb_set_clk_mode(priv->regbase, clk_pol, clk_pha); 169 | #if 0 170 | if (!priv->qspi_is_init) { 171 | cadence_qspi_apb_controller_init(plat); 172 | priv->qspi_is_init = 1; 173 | } 174 | #endif 175 | 176 | cadence_qspi_apb_controller_init(plat); 177 | 178 | if (max_hz > plat->max_hz) 179 | max_hz = plat->max_hz; 180 | 181 | /* 182 | * Calibration required for different current SCLK speed, requested 183 | * SCLK speed or chip select 184 | */ 185 | if (priv->previous_hz != max_hz || 186 | priv->qspi_calibrated_hz != max_hz || 187 | priv->qspi_calibrated_cs != cs) { 188 | err = spi_calibration(max_hz, cs); 189 | if (err) 190 | return NULL; 191 | 192 | /* prevent calibration run when same as previous request */ 193 | priv->previous_hz = max_hz; 194 | } 195 | 196 | /* Enable QSPI */ 197 | cadence_qspi_apb_controller_enable(priv->regbase); 198 | 199 | spi4slave->slave.bus = bus; 200 | spi4slave->slave.cs = cs; 201 | spi4slave->slave.bus_width= fifo_width; 202 | 203 | return &spi4slave->slave; 204 | 205 | 206 | } 207 | 208 | 209 | static int cadence_spi_xfer(struct spi_slave *slave, unsigned int bitlen, 210 | const void *dout, void *din, unsigned long flags) 211 | { 212 | struct cadence_spi_platdata *plat = &cadence_plat; 213 | struct cadence_spi_priv *priv = &spi_priv; 214 | void *base = priv->regbase; 215 | u8 *cmd_buf = priv->cmd_buf; 216 | unsigned int data_bytes = 0; 217 | int err = 0; 218 | u32 mode = CQSPI_STIG_WRITE; 219 | 220 | if (flags & SPI_XFER_BEGIN) { 221 | /* copy command to local buffer */ 222 | priv->cmd_len = bitlen / 8; 223 | sys_memcpy(cmd_buf, dout, priv->cmd_len); 224 | } 225 | 226 | if (flags == (SPI_XFER_BEGIN | SPI_XFER_END)) 227 | { 228 | /* if start and end bit are set, the data bytes is 0. */ 229 | data_bytes = 0; 230 | } 231 | else 232 | { 233 | data_bytes = bitlen / 8; 234 | } 235 | //uart_printf("%s: len=%d [bytes]\n", __func__, data_bytes); 236 | 237 | /* Set Chip select */ 238 | cadence_qspi_apb_chipselect(base, slave->cs, 239 | CONFIG_CQSPI_DECODER); 240 | 241 | if ((flags & SPI_XFER_END) || (flags == 0)) { 242 | if (priv->cmd_len == 0) { 243 | //uart_printf("QSPI: Error, command is empty.\n"); 244 | return -1; 245 | } 246 | 247 | if (din && data_bytes) { 248 | /* read */ 249 | /* Use STIG if no address. */ 250 | if (!CQSPI_IS_ADDR(priv->cmd_len)) 251 | mode = CQSPI_STIG_READ; 252 | else 253 | mode = CQSPI_INDIRECT_READ; 254 | } else if (dout && !(flags & SPI_XFER_BEGIN)) { 255 | /* write */ 256 | if (!CQSPI_IS_ADDR(priv->cmd_len)) 257 | mode = CQSPI_STIG_WRITE; 258 | else 259 | mode = CQSPI_INDIRECT_WRITE; 260 | } 261 | 262 | switch (mode) { 263 | case CQSPI_STIG_READ: 264 | err = cadence_qspi_apb_command_read( 265 | base, priv->cmd_len, cmd_buf, 266 | data_bytes, din); 267 | 268 | break; 269 | case CQSPI_STIG_WRITE: 270 | err = cadence_qspi_apb_command_write(base, 271 | priv->cmd_len, cmd_buf, 272 | data_bytes, dout); 273 | break; 274 | case CQSPI_INDIRECT_READ: 275 | err = cadence_qspi_apb_indirect_read_setup(plat, 276 | priv->cmd_len, cmd_buf); 277 | if (!err) { 278 | err = cadence_qspi_apb_indirect_read_execute 279 | (plat, data_bytes, din); 280 | } 281 | break; 282 | case CQSPI_INDIRECT_WRITE: 283 | err = cadence_qspi_apb_indirect_write_setup 284 | (plat, priv->cmd_len, cmd_buf); 285 | if (!err) { 286 | err = cadence_qspi_apb_indirect_write_execute 287 | (plat, data_bytes, dout); 288 | } 289 | break; 290 | default: 291 | err = -1; 292 | break; 293 | } 294 | 295 | if (flags & SPI_XFER_END) { 296 | /* clear command buffer */ 297 | sys_memset(cmd_buf, 0, sizeof(priv->cmd_buf)); 298 | priv->cmd_len = 0; 299 | } 300 | } 301 | 302 | return err; 303 | } 304 | 305 | void cadence_qspi_init(unsigned int bus, u32 mode) 306 | { 307 | struct spi_operation *func; 308 | struct cadence_spi_platdata *plat = &cadence_plat; 309 | 310 | /******************* reset ****************/ 311 | _ENABLE_CLOCK_clk_qspi_refclk_; 312 | _ENABLE_CLOCK_clk_qspi_apb_; 313 | _ENABLE_CLOCK_clk_qspi_ahb_; 314 | _ASSERT_RESET_rstgen_rstn_qspi_ahb_; 315 | _ASSERT_RESET_rstgen_rstn_qspi_core_; 316 | _ASSERT_RESET_rstgen_rstn_qspi_apb_; 317 | _CLEAR_RESET_rstgen_rstn_qspi_ahb_; 318 | _CLEAR_RESET_rstgen_rstn_qspi_core_; 319 | _CLEAR_RESET_rstgen_rstn_qspi_apb_; 320 | plat->bit_mode = mode; 321 | 322 | func = &cadence_spi4x_func; 323 | func->setup_slave = cadence_spi4x_setup_slave; 324 | func->spi_xfer = cadence_spi_xfer; 325 | 326 | spi_register(bus, func); 327 | 328 | return; 329 | } -------------------------------------------------------------------------------- /src/driver/spi/cadence_qspi.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 3 | * Altera Corporation 4 | * 5 | * SPDX-License-Identifier: GPL-2.0+ 6 | */ 7 | 8 | #ifndef __CADENCE_QSPI_H__ 9 | #define __CADENCE_QSPI_H__ 10 | 11 | #define CQSPI_IS_ADDR(cmd_len) (cmd_len > 1 ? 1 : 0) 12 | 13 | #define CQSPI_NO_DECODER_MAX_CS 4 14 | #define CQSPI_DECODER_MAX_CS 16 15 | #define CQSPI_READ_CAPTURE_MAX_DELAY 16 16 | 17 | struct cadence_spi_platdata { 18 | unsigned int max_hz; 19 | void *regbase; 20 | void *ahbbase; 21 | u32 int_num; 22 | 23 | u32 page_size; 24 | u32 block_size; 25 | u32 tshsl_ns; 26 | u32 tsd2d_ns; 27 | u32 tchsh_ns; 28 | u32 tslch_ns; 29 | u32 sram_size; 30 | u32 bit_mode; 31 | }; 32 | 33 | struct cadence_spi_priv { 34 | void *regbase; 35 | void *ahbbase; 36 | unsigned int cmd_len; 37 | u8 cmd_buf[32]; 38 | unsigned int data_len; 39 | 40 | int qspi_is_init; 41 | unsigned int qspi_calibrated_hz; 42 | unsigned int qspi_calibrated_cs; 43 | unsigned int previous_hz; 44 | }; 45 | 46 | /* Functions call declaration */ 47 | void cadence_qspi_apb_controller_init(struct cadence_spi_platdata *plat); 48 | void cadence_qspi_apb_controller_enable(void * reg_base_addr); 49 | void cadence_qspi_apb_controller_disable(void * reg_base_addr); 50 | 51 | int cadence_qspi_apb_command_read(void * reg_base_addr, 52 | unsigned int cmdlen, const u8 *cmdbuf, unsigned int rxlen, u8 *rxbuf); 53 | int cadence_qspi_apb_command_write(void * reg_base_addr, 54 | unsigned int cmdlen, const u8 *cmdbuf, 55 | unsigned int txlen, const u8 *txbuf); 56 | 57 | int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata *plat, 58 | unsigned int cmdlen, const u8 *cmdbuf); 59 | int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat, 60 | unsigned int rxlen, u8 *rxbuf); 61 | int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata *plat, 62 | unsigned int cmdlen, const u8 *cmdbuf); 63 | int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat, 64 | unsigned int txlen, const u8 *txbuf); 65 | 66 | void cadence_qspi_apb_chipselect(void * reg_base, 67 | unsigned int chip_select, unsigned int decoder_enable); 68 | void cadence_qspi_apb_set_clk_mode(void * reg_base_addr, 69 | unsigned int clk_pol, unsigned int clk_pha); 70 | void cadence_qspi_apb_config_baudrate_div(void * reg_base, 71 | unsigned int ref_clk_hz, unsigned int sclk_hz); 72 | void cadence_qspi_apb_delay(void * reg_base, 73 | unsigned int ref_clk, unsigned int sclk_hz, 74 | unsigned int tshsl_ns, unsigned int tsd2d_ns, 75 | unsigned int tchsh_ns, unsigned int tslch_ns); 76 | void cadence_qspi_apb_enter_xip(void * reg_base, char xip_dummy); 77 | void cadence_qspi_apb_readdata_capture(void * reg_base, 78 | unsigned int bypass, unsigned int delay); 79 | 80 | 81 | void cadence_qspi_init(unsigned int bus, u32 mode); 82 | 83 | #endif /* __CADENCE_QSPI_H__ */ 84 | -------------------------------------------------------------------------------- /src/driver/spi/cadence_qspi_apb.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Altera Corporation 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * - Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * - Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * - Neither the name of the Altera Corporation nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL ALTERA CORPORATION BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #define CQSPI_REG_POLL_US (1) /* 1us */ 34 | #define CQSPI_REG_RETRY (10000) 35 | #define CQSPI_POLL_IDLE_RETRY (3) 36 | 37 | #define CQSPI_FIFO_WIDTH (4) 38 | 39 | #define CQSPI_REG_SRAM_THRESHOLD_WORDS (50) 40 | 41 | /* Transfer mode */ 42 | #define CQSPI_INST_TYPE_SINGLE (0) 43 | #define CQSPI_INST_TYPE_DUAL (1) 44 | #define CQSPI_INST_TYPE_QUAD (2) 45 | 46 | #define CQSPI_STIG_DATA_LEN_MAX (8) 47 | //#define CQSPI_INDIRECTTRIGGER_ADDR_MASK (0xFFFFFFFF) 48 | #define CQSPI_INDIRECTTRIGGER_ADDR_MASK (0x0) //libo 49 | 50 | #define CQSPI_DUMMY_CLKS_PER_BYTE (8) 51 | #define CQSPI_DUMMY_BYTES_MAX (4) 52 | 53 | #define CONFIG_SPI_FLASH_QUAD (0) 54 | 55 | 56 | #define CQSPI_REG_SRAM_FILL_THRESHOLD \ 57 | ((CQSPI_REG_SRAM_SIZE_WORD / 2) * CQSPI_FIFO_WIDTH) 58 | /**************************************************************************** 59 | * Controller's configuration and status register (offset from QSPI_BASE) 60 | ****************************************************************************/ 61 | #define CQSPI_REG_CONFIG 0x00 62 | #define CQSPI_REG_CONFIG_CLK_POL_LSB 1 63 | #define CQSPI_REG_CONFIG_CLK_PHA_LSB 2 64 | #define CQSPI_REG_CONFIG_ENABLE_MASK BIT(0) 65 | #define CQSPI_REG_CONFIG_DIRECT_MASK BIT(7) 66 | #define CQSPI_REG_CONFIG_DECODE_MASK BIT(9) 67 | #define CQSPI_REG_CONFIG_XIP_IMM_MASK BIT(18) 68 | #define CQSPI_REG_CONFIG_CHIPSELECT_LSB 10 69 | #define CQSPI_REG_CONFIG_BAUD_LSB 19 70 | #define CQSPI_REG_CONFIG_IDLE_LSB 31 71 | #define CQSPI_REG_CONFIG_CHIPSELECT_MASK 0xF 72 | #define CQSPI_REG_CONFIG_BAUD_MASK 0xF 73 | 74 | #define CQSPI_REG_RD_INSTR 0x04 75 | #define CQSPI_REG_RD_INSTR_OPCODE_LSB 0 76 | #define CQSPI_REG_RD_INSTR_TYPE_INSTR_LSB 8 77 | #define CQSPI_REG_RD_INSTR_TYPE_ADDR_LSB 12 78 | #define CQSPI_REG_RD_INSTR_TYPE_DATA_LSB 16 79 | #define CQSPI_REG_RD_INSTR_MODE_EN_LSB 20 80 | #define CQSPI_REG_RD_INSTR_DUMMY_LSB 24 81 | #define CQSPI_REG_RD_INSTR_TYPE_INSTR_MASK 0x3 82 | #define CQSPI_REG_RD_INSTR_TYPE_ADDR_MASK 0x3 83 | #define CQSPI_REG_RD_INSTR_TYPE_DATA_MASK 0x3 84 | #define CQSPI_REG_RD_INSTR_DUMMY_MASK 0x1F 85 | 86 | 87 | 88 | #define CQSPI_REG_WR_INSTR 0x08 89 | #define CQSPI_REG_WR_INSTR_OPCODE_LSB 0 90 | #define CQSPI_REG_WR_INSTR_TYPE_INSTR_LSB 8 91 | #define CQSPI_REG_WR_INSTR_TYPE_ADDR_LSB 12 92 | #define CQSPI_REG_WR_INSTR_TYPE_DATA_LSB 16 93 | #define CQSPI_REG_WR_INSTR_MODE_EN_LSB 20 94 | #define CQSPI_REG_WR_INSTR_DUMMY_LSB 24 95 | #define CQSPI_REG_WR_INSTR_TYPE_INSTR_MASK 0x3 96 | #define CQSPI_REG_WR_INSTR_TYPE_ADDR_MASK 0x3 97 | #define CQSPI_REG_WR_INSTR_TYPE_DATA_MASK 0x3 98 | #define CQSPI_REG_WR_INSTR_DUMMY_MASK 0x1F 99 | 100 | #define CQSPI_REG_DELAY 0x0C 101 | #define CQSPI_REG_DELAY_TSLCH_LSB 0 102 | #define CQSPI_REG_DELAY_TCHSH_LSB 8 103 | #define CQSPI_REG_DELAY_TSD2D_LSB 16 104 | #define CQSPI_REG_DELAY_TSHSL_LSB 24 105 | #define CQSPI_REG_DELAY_TSLCH_MASK 0xFF 106 | #define CQSPI_REG_DELAY_TCHSH_MASK 0xFF 107 | #define CQSPI_REG_DELAY_TSD2D_MASK 0xFF 108 | #define CQSPI_REG_DELAY_TSHSL_MASK 0xFF 109 | 110 | #define CQSPI_READLCAPTURE 0x10 111 | #define CQSPI_READLCAPTURE_BYPASS_LSB 0 112 | #define CQSPI_READLCAPTURE_DELAY_LSB 1 113 | #define CQSPI_READLCAPTURE_DELAY_MASK 0xF 114 | 115 | #define CQSPI_REG_SIZE 0x14 116 | #define CQSPI_REG_SIZE_ADDRESS_LSB 0 117 | #define CQSPI_REG_SIZE_PAGE_LSB 4 118 | #define CQSPI_REG_SIZE_BLOCK_LSB 16 119 | #define CQSPI_REG_SIZE_ADDRESS_MASK 0xF 120 | #define CQSPI_REG_SIZE_PAGE_MASK 0xFFF 121 | #define CQSPI_REG_SIZE_BLOCK_MASK 0x3F 122 | 123 | #define CQSPI_REG_SRAMPARTITION 0x18 124 | #define CQSPI_REG_INDIRECTTRIGGER 0x1C 125 | 126 | #define CQSPI_REG_REMAP 0x24 127 | #define CQSPI_REG_MODE_BIT 0x28 128 | 129 | #define CQSPI_REG_SDRAMLEVEL 0x2C 130 | #define CQSPI_REG_SDRAMLEVEL_RD_LSB 0 131 | #define CQSPI_REG_SDRAMLEVEL_WR_LSB 16 132 | #define CQSPI_REG_SDRAMLEVEL_RD_MASK 0xFFFF 133 | #define CQSPI_REG_SDRAMLEVEL_WR_MASK 0xFFFF 134 | 135 | #define CQSPI_REG_IRQSTATUS 0x40 136 | #define CQSPI_REG_IRQMASK 0x44 137 | 138 | #define CQSPI_REG_INDIRECTRD 0x60 139 | #define CQSPI_REG_INDIRECTRD_START_MASK BIT(0) 140 | #define CQSPI_REG_INDIRECTRD_CANCEL_MASK BIT(1) 141 | #define CQSPI_REG_INDIRECTRD_INPROGRESS_MASK BIT(2) 142 | #define CQSPI_REG_INDIRECTRD_DONE_MASK BIT(5) 143 | 144 | #define CQSPI_REG_INDIRECTRDWATERMARK 0x64 145 | #define CQSPI_REG_INDIRECTRDSTARTADDR 0x68 146 | #define CQSPI_REG_INDIRECTRDBYTES 0x6C 147 | 148 | #define CQSPI_REG_INDIRECTTRI_ADDR_RANGE 0X80 149 | 150 | #define CQSPI_REG_CMDCTRL 0x90 151 | #define CQSPI_REG_CMDCTRL_EXECUTE_MASK BIT(0) 152 | #define CQSPI_REG_CMDCTRL_INPROGRESS_MASK BIT(1) 153 | #define CQSPI_REG_CMDCTRL_DUMMY_LSB 7 154 | #define CQSPI_REG_CMDCTRL_WR_BYTES_LSB 12 155 | #define CQSPI_REG_CMDCTRL_WR_EN_LSB 15 156 | #define CQSPI_REG_CMDCTRL_ADD_BYTES_LSB 16 157 | #define CQSPI_REG_CMDCTRL_ADDR_EN_LSB 19 158 | #define CQSPI_REG_CMDCTRL_RD_BYTES_LSB 20 159 | #define CQSPI_REG_CMDCTRL_RD_EN_LSB 23 160 | #define CQSPI_REG_CMDCTRL_OPCODE_LSB 24 161 | #define CQSPI_REG_CMDCTRL_DUMMY_MASK 0x1F 162 | #define CQSPI_REG_CMDCTRL_WR_BYTES_MASK 0x7 163 | #define CQSPI_REG_CMDCTRL_ADD_BYTES_MASK 0x3 164 | #define CQSPI_REG_CMDCTRL_RD_BYTES_MASK 0x7 165 | #define CQSPI_REG_CMDCTRL_OPCODE_MASK 0xFF 166 | 167 | #define CQSPI_REG_INDIRECTWR 0x70 168 | #define CQSPI_REG_INDIRECTWR_START_MASK BIT(0) 169 | #define CQSPI_REG_INDIRECTWR_CANCEL_MASK BIT(1) 170 | #define CQSPI_REG_INDIRECTWR_INPROGRESS_MASK BIT(2) 171 | #define CQSPI_REG_INDIRECTWR_DONE_MASK BIT(5) 172 | 173 | #define CQSPI_REG_INDIRECTWRWATERMARK 0x74 174 | #define CQSPI_REG_INDIRECTWRSTARTADDR 0x78 175 | #define CQSPI_REG_INDIRECTWRBYTES 0x7C 176 | 177 | #define CQSPI_REG_CMDADDRESS 0x94 178 | #define CQSPI_REG_CMDREADDATALOWER 0xA0 179 | #define CQSPI_REG_CMDREADDATAUPPER 0xA4 180 | #define CQSPI_REG_CMDWRITEDATALOWER 0xA8 181 | #define CQSPI_REG_CMDWRITEDATAUPPER 0xAC 182 | 183 | #define CQSPI_REG_IS_IDLE(base) \ 184 | ((readl(base + CQSPI_REG_CONFIG) >> \ 185 | CQSPI_REG_CONFIG_IDLE_LSB) & 0x1) 186 | 187 | #define CQSPI_CAL_DELAY(tdelay_ns, tref_ns, tsclk_ns) \ 188 | ((((tdelay_ns) - (tsclk_ns)) / (tref_ns))) 189 | 190 | #define CQSPI_GET_RD_SRAM_LEVEL(reg_base) \ 191 | (((readl(reg_base + CQSPI_REG_SDRAMLEVEL)) >> \ 192 | CQSPI_REG_SDRAMLEVEL_RD_LSB) & CQSPI_REG_SDRAMLEVEL_RD_MASK) 193 | 194 | #define CQSPI_GET_WR_SRAM_LEVEL(reg_base) \ 195 | (((readl(reg_base + CQSPI_REG_SDRAMLEVEL)) >> \ 196 | CQSPI_REG_SDRAMLEVEL_WR_LSB) & CQSPI_REG_SDRAMLEVEL_WR_MASK) 197 | 198 | static unsigned int cadence_qspi_apb_cmd2addr(const unsigned char *addr_buf, 199 | unsigned int addr_width) 200 | { 201 | unsigned int addr; 202 | 203 | addr = (addr_buf[0] << 16) | (addr_buf[1] << 8) | addr_buf[2]; 204 | 205 | if (addr_width == 4) 206 | addr = (addr << 8) | addr_buf[3]; 207 | 208 | return addr; 209 | } 210 | 211 | static void cadence_qspi_apb_read_fifo_data(void *dest, 212 | const void *src_ahb_addr, unsigned int bytes) 213 | { 214 | unsigned int temp; 215 | int remaining = bytes; 216 | unsigned int *dest_ptr = (unsigned int *)dest; 217 | unsigned int *src_ptr = (unsigned int *)src_ahb_addr; 218 | 219 | while (remaining >= 4) { 220 | *dest_ptr = readl(src_ptr); 221 | remaining -= 4; 222 | dest_ptr++; 223 | } 224 | if (remaining) { 225 | /* dangling bytes */ 226 | temp = readl(src_ptr); 227 | sys_memcpy(dest_ptr, &temp, remaining); 228 | } 229 | 230 | return; 231 | } 232 | 233 | static void cadence_qspi_apb_write_fifo_data(const void *dest_ahb_addr, 234 | const void *src, unsigned int bytes) 235 | { 236 | unsigned int temp = 0; 237 | int i; 238 | int remaining = bytes; 239 | unsigned int *dest_ptr = (unsigned int *)dest_ahb_addr; 240 | unsigned int *src_ptr = (unsigned int *)src; 241 | 242 | //uart_printf("src_ptr = 0x%x, src = 0x%x\r\n", src_ptr,src); 243 | //uart_printf("*src_ptr = 0x%x\r\n", *src_ptr); 244 | 245 | while (remaining >= CQSPI_FIFO_WIDTH) { 246 | for (i = CQSPI_FIFO_WIDTH/4 - 1; i >= 0; i--) 247 | writel(*(src_ptr+i), dest_ptr+i); 248 | //dest_ptr += CQSPI_FIFO_WIDTH/sizeof(src_ptr); 249 | src_ptr += CQSPI_FIFO_WIDTH/4; 250 | remaining -= CQSPI_FIFO_WIDTH; 251 | } 252 | if (remaining) { 253 | /* dangling bytes */ 254 | i = remaining/4; 255 | sys_memcpy(&temp, src_ptr+i, remaining % 4); 256 | writel(temp, dest_ptr+i); 257 | for (--i; i >= 0; i--) 258 | writel(*(src_ptr+i), dest_ptr+i); 259 | } 260 | return; 261 | } 262 | 263 | /* Read from SRAM FIFO with polling SRAM fill level. */ 264 | static int qspi_read_sram_fifo_poll(const void * reg_base, void *dest_addr, 265 | const void *src_addr, unsigned int num_bytes) 266 | { 267 | unsigned int remaining = num_bytes; 268 | unsigned int retry; 269 | unsigned int sram_level = 0; 270 | unsigned char *dest = (unsigned char *)dest_addr; 271 | 272 | while (remaining > 0) { 273 | retry = CQSPI_REG_RETRY; 274 | while (retry--) { 275 | sram_level = CQSPI_GET_RD_SRAM_LEVEL((u32)reg_base); 276 | if (sram_level) 277 | break; 278 | delay(100); 279 | } 280 | 281 | if (!retry) { 282 | //uart_printf("QSPI: No receive data after polling for %d times\n", 283 | //CQSPI_REG_RETRY); 284 | return -1; 285 | } 286 | 287 | sram_level *= CQSPI_FIFO_WIDTH; 288 | sram_level = sram_level > remaining ? remaining : sram_level; 289 | 290 | /* Read data from FIFO. */ 291 | cadence_qspi_apb_read_fifo_data(dest, src_addr, sram_level); 292 | dest += sram_level; 293 | remaining -= sram_level; 294 | delay(100); 295 | } 296 | return 0; 297 | } 298 | 299 | /* Write to SRAM FIFO with polling SRAM fill level. */ 300 | static int qpsi_write_sram_fifo_push(struct cadence_spi_platdata *plat, 301 | const void *src_addr, unsigned int num_bytes) 302 | { 303 | const void * reg_base = plat->regbase; 304 | void *dest_addr = plat->ahbbase; 305 | unsigned int retry = CQSPI_REG_RETRY; 306 | unsigned int sram_level; 307 | unsigned int wr_bytes; 308 | unsigned char *src = (unsigned char *)src_addr; 309 | int remaining = num_bytes; 310 | unsigned int page_size = plat->page_size; 311 | unsigned int sram_threshold_words = CQSPI_REG_SRAM_THRESHOLD_WORDS; 312 | 313 | while (remaining > 0) { 314 | retry = CQSPI_REG_RETRY; 315 | while (retry--) { 316 | sram_level = CQSPI_GET_WR_SRAM_LEVEL((u32)reg_base); 317 | if (sram_level <= sram_threshold_words) 318 | break; 319 | } 320 | if (!retry) { 321 | //uart_printf("QSPI: SRAM fill level (0x%08x) not hit lower expected level (0x%08x)", 322 | //sram_level, sram_threshold_words); 323 | return -1; 324 | } 325 | /* Write a page or remaining bytes. */ 326 | wr_bytes = (remaining > page_size) ? 327 | page_size : remaining; 328 | 329 | cadence_qspi_apb_write_fifo_data(dest_addr, src, wr_bytes); 330 | src += wr_bytes; 331 | remaining -= wr_bytes; 332 | } 333 | 334 | return 0; 335 | } 336 | 337 | void cadence_qspi_apb_controller_enable( void * reg_base) 338 | { 339 | unsigned int reg; 340 | reg = readl((u32)reg_base + CQSPI_REG_CONFIG); 341 | reg |= CQSPI_REG_CONFIG_ENABLE_MASK; 342 | writel(reg, (u32)reg_base + CQSPI_REG_CONFIG); 343 | return; 344 | } 345 | 346 | void cadence_qspi_apb_controller_disable(void * reg_base) 347 | { 348 | unsigned int reg; 349 | reg = readl((u32)reg_base + CQSPI_REG_CONFIG); 350 | reg &= ~CQSPI_REG_CONFIG_ENABLE_MASK; 351 | writel(reg, (u32)reg_base + CQSPI_REG_CONFIG); 352 | return; 353 | } 354 | 355 | /* Return 1 if idle, otherwise return 0 (busy). */ 356 | static unsigned int cadence_qspi_wait_idle(void * reg_base) 357 | { 358 | unsigned int start = 5000, count = 0; 359 | /* timeout in unit of ms */ 360 | unsigned int timeout = 5000; 361 | #if 0 362 | start = get_timer(0); 363 | for ( ; get_timer(start) < timeout ; ) { 364 | if (CQSPI_REG_IS_IDLE((u32)reg_base)) 365 | count++; 366 | else 367 | count = 0; 368 | /* 369 | * Ensure the QSPI controller is in true idle state after 370 | * reading back the same idle status consecutively 371 | */ 372 | if (count >= CQSPI_POLL_IDLE_RETRY) 373 | { 374 | 375 | //uart_printf("count = %d, get_timer(start) = %d\n, ", count , get_timer(start)); 376 | return 1; 377 | 378 | } 379 | 380 | } 381 | #endif 382 | while(1) { 383 | if (CQSPI_REG_IS_IDLE((u32)reg_base)) 384 | return 1; 385 | else 386 | { 387 | count++; 388 | //return 0; 389 | } 390 | /* 391 | * Ensure the QSPI controller is in true idle state after 392 | * reading back the same idle status consecutively 393 | */ 394 | if (count >= CQSPI_REG_RETRY) 395 | { 396 | 397 | //uart_printf("count = %d\r\n, ", count); 398 | return 1; 399 | 400 | } 401 | 402 | } 403 | /* Timeout, still in busy mode. */ 404 | //uart_printf("QSPI: QSPI is still busy after poll for %d times.\n", 405 | //CQSPI_REG_RETRY); 406 | return 0; 407 | } 408 | 409 | void cadence_qspi_apb_readdata_capture(void * reg_base, 410 | unsigned int bypass, unsigned int delay) 411 | { 412 | unsigned int reg; 413 | cadence_qspi_apb_controller_disable(reg_base); 414 | 415 | reg = readl((u32)reg_base + CQSPI_READLCAPTURE); 416 | 417 | if (bypass) 418 | reg |= (1 << CQSPI_READLCAPTURE_BYPASS_LSB); 419 | else 420 | reg &= ~(1 << CQSPI_READLCAPTURE_BYPASS_LSB); 421 | 422 | reg &= ~(CQSPI_READLCAPTURE_DELAY_MASK 423 | << CQSPI_READLCAPTURE_DELAY_LSB); 424 | 425 | reg |= ((delay & CQSPI_READLCAPTURE_DELAY_MASK) 426 | << CQSPI_READLCAPTURE_DELAY_LSB); 427 | 428 | writel(reg, (u32)reg_base + CQSPI_READLCAPTURE); 429 | //writel(0x21, (u32)reg_base + CQSPI_READLCAPTURE); 430 | 431 | cadence_qspi_apb_controller_enable(reg_base); 432 | return; 433 | } 434 | 435 | void cadence_qspi_apb_config_baudrate_div(void * reg_base, 436 | unsigned int ref_clk_hz, unsigned int sclk_hz) 437 | { 438 | unsigned int reg; 439 | unsigned int div; 440 | 441 | cadence_qspi_apb_controller_disable(reg_base); 442 | reg = readl((u32)reg_base + CQSPI_REG_CONFIG); 443 | reg &= ~(CQSPI_REG_CONFIG_BAUD_MASK << CQSPI_REG_CONFIG_BAUD_LSB); 444 | 445 | div = ref_clk_hz / sclk_hz; 446 | 447 | if (div > 32) 448 | div = 32; 449 | 450 | /* Check if even number. */ 451 | if ((div & 1)) { 452 | div = (div / 2); 453 | } else { 454 | if (ref_clk_hz % sclk_hz) 455 | /* ensure generated SCLK doesn't exceed user 456 | specified sclk_hz */ 457 | div = (div / 2); 458 | else 459 | div = (div / 2) - 1; 460 | } 461 | 462 | //uart_printf("%s: ref_clk %dHz sclk %dHz Div 0x%x\n", __func__, 463 | //ref_clk_hz, sclk_hz, div); 464 | 465 | div = (div & CQSPI_REG_CONFIG_BAUD_MASK) << CQSPI_REG_CONFIG_BAUD_LSB; 466 | reg |= div; 467 | writel(reg, (u32)reg_base + CQSPI_REG_CONFIG); 468 | 469 | cadence_qspi_apb_controller_enable(reg_base); 470 | return; 471 | } 472 | 473 | void cadence_qspi_apb_set_clk_mode(void * reg_base, 474 | unsigned int clk_pol, unsigned int clk_pha) 475 | { 476 | unsigned int reg; 477 | 478 | cadence_qspi_apb_controller_disable(reg_base); 479 | reg = readl((u32)reg_base + CQSPI_REG_CONFIG); 480 | reg &= ~(1 << 481 | (CQSPI_REG_CONFIG_CLK_POL_LSB | CQSPI_REG_CONFIG_CLK_PHA_LSB)); 482 | 483 | reg |= ((clk_pol & 0x1) << CQSPI_REG_CONFIG_CLK_POL_LSB); 484 | reg |= ((clk_pha & 0x1) << CQSPI_REG_CONFIG_CLK_PHA_LSB); 485 | 486 | writel(reg, (u32)reg_base + CQSPI_REG_CONFIG); 487 | 488 | cadence_qspi_apb_controller_enable(reg_base); 489 | return; 490 | } 491 | 492 | void cadence_qspi_apb_chipselect(void * reg_base, 493 | unsigned int chip_select, unsigned int decoder_enable) 494 | { 495 | unsigned int reg; 496 | 497 | cadence_qspi_apb_controller_disable(reg_base); 498 | 499 | 500 | reg = readl((u32)reg_base + CQSPI_REG_CONFIG); 501 | /* docoder */ 502 | if (decoder_enable) { 503 | reg |= CQSPI_REG_CONFIG_DECODE_MASK; 504 | } else { 505 | reg &= ~CQSPI_REG_CONFIG_DECODE_MASK; 506 | /* Convert CS if without decoder. 507 | * CS0 to 4b'1110 508 | * CS1 to 4b'1101 509 | * CS2 to 4b'1011 510 | * CS3 to 4b'0111 511 | */ 512 | chip_select = 0xF & ~(1 << chip_select); 513 | } 514 | 515 | reg &= ~(CQSPI_REG_CONFIG_CHIPSELECT_MASK 516 | << CQSPI_REG_CONFIG_CHIPSELECT_LSB); 517 | reg |= (chip_select & CQSPI_REG_CONFIG_CHIPSELECT_MASK) 518 | << CQSPI_REG_CONFIG_CHIPSELECT_LSB; 519 | writel(reg, (u32)reg_base + CQSPI_REG_CONFIG); 520 | 521 | cadence_qspi_apb_controller_enable(reg_base); 522 | return; 523 | } 524 | 525 | void cadence_qspi_apb_delay(void * reg_base, 526 | unsigned int ref_clk, unsigned int sclk_hz, 527 | unsigned int tshsl_ns, unsigned int tsd2d_ns, 528 | unsigned int tchsh_ns, unsigned int tslch_ns) 529 | { 530 | unsigned int ref_clk_ns; 531 | unsigned int sclk_ns; 532 | unsigned int tshsl, tchsh, tslch, tsd2d; 533 | unsigned int reg; 534 | 535 | cadence_qspi_apb_controller_disable(reg_base); 536 | 537 | /* Convert to ns. */ 538 | ref_clk_ns = (10000000) / ref_clk; 539 | 540 | /* Convert to ns. */ 541 | sclk_ns = (10000000) / sclk_hz; 542 | #if 0 543 | /* Plus 1 to round up 1 clock cycle. */ 544 | tshsl = CQSPI_CAL_DELAY(tshsl_ns, ref_clk_ns, sclk_ns) + 1; 545 | tchsh = CQSPI_CAL_DELAY(tchsh_ns, ref_clk_ns, sclk_ns) + 1; 546 | tslch = CQSPI_CAL_DELAY(tslch_ns, ref_clk_ns, sclk_ns) + 1; 547 | tsd2d = CQSPI_CAL_DELAY(tsd2d_ns, ref_clk_ns, sclk_ns) + 1; 548 | #endif 549 | tshsl = 1; 550 | tchsh = 1; 551 | tslch = 1; 552 | tsd2d = 1; 553 | 554 | reg = ((tshsl & CQSPI_REG_DELAY_TSHSL_MASK) 555 | << CQSPI_REG_DELAY_TSHSL_LSB); 556 | reg |= ((tchsh & CQSPI_REG_DELAY_TCHSH_MASK) 557 | << CQSPI_REG_DELAY_TCHSH_LSB); 558 | reg |= ((tslch & CQSPI_REG_DELAY_TSLCH_MASK) 559 | << CQSPI_REG_DELAY_TSLCH_LSB); 560 | reg |= ((tsd2d & CQSPI_REG_DELAY_TSD2D_MASK) 561 | << CQSPI_REG_DELAY_TSD2D_LSB); 562 | writel(reg, (u32)reg_base + CQSPI_REG_DELAY); 563 | //writel(0x0, (u32)reg_base + CQSPI_REG_DELAY); 564 | 565 | cadence_qspi_apb_controller_enable(reg_base); 566 | return; 567 | } 568 | 569 | void cadence_qspi_apb_controller_init(struct cadence_spi_platdata *plat) 570 | { 571 | unsigned reg; 572 | cadence_qspi_apb_controller_disable(plat->regbase); 573 | 574 | /* Configure the device size and address bytes */ 575 | reg = readl((u32)plat->regbase + CQSPI_REG_SIZE); 576 | /* Clear the previous value */ 577 | reg &= ~(CQSPI_REG_SIZE_PAGE_MASK << CQSPI_REG_SIZE_PAGE_LSB); 578 | reg &= ~(CQSPI_REG_SIZE_BLOCK_MASK << CQSPI_REG_SIZE_BLOCK_LSB); 579 | reg |= (plat->page_size << CQSPI_REG_SIZE_PAGE_LSB); 580 | reg |= (plat->block_size << CQSPI_REG_SIZE_BLOCK_LSB); 581 | writel(reg, (u32)plat->regbase + CQSPI_REG_SIZE); 582 | 583 | /* Configure the remap address register, no remap */ 584 | writel(0,(u32) plat->regbase + CQSPI_REG_REMAP); 585 | //writel(0X8,(u32) plat->regbase + CQSPI_REG_INDIRECTTRI_ADDR_RANGE); 586 | 587 | /* Indirect mode configurations */ 588 | writel((plat->sram_size/2), (u32)plat->regbase + CQSPI_REG_SRAMPARTITION); 589 | 590 | /* Disable all interrupts */ 591 | writel(0, (u32)plat->regbase + CQSPI_REG_IRQMASK); 592 | 593 | cadence_qspi_apb_controller_enable(plat->regbase); 594 | return; 595 | } 596 | 597 | static int cadence_qspi_apb_exec_flash_cmd(u32 reg_base, 598 | unsigned int reg) 599 | { 600 | unsigned int retry = CQSPI_REG_RETRY; 601 | 602 | /* Write the CMDCTRL without start execution. */ 603 | writel(reg, (u32)reg_base + CQSPI_REG_CMDCTRL); 604 | /* Start execute */ 605 | reg |= CQSPI_REG_CMDCTRL_EXECUTE_MASK; 606 | writel(reg, (u32)reg_base + CQSPI_REG_CMDCTRL); 607 | 608 | while (retry--) { 609 | reg = readl((u32)reg_base + CQSPI_REG_CMDCTRL); 610 | if ((reg & CQSPI_REG_CMDCTRL_INPROGRESS_MASK) == 0) 611 | break; 612 | delay(1000); 613 | } 614 | 615 | if (!retry) { 616 | //uart_printf("QSPI: flash command execution timeout\n"); 617 | return -1; 618 | } 619 | 620 | /* Polling QSPI idle status. */ 621 | if (!cadence_qspi_wait_idle(reg_base)) 622 | return -1; 623 | 624 | return 0; 625 | } 626 | 627 | /* For command RDID, RDSR. */ 628 | int cadence_qspi_apb_command_read(void *reg_base, 629 | unsigned int cmdlen, const u8 *cmdbuf, unsigned int rxlen, 630 | u8 *rxbuf) 631 | { 632 | unsigned int reg; 633 | unsigned int read_len; 634 | int status; 635 | 636 | if (!cmdlen || rxlen > CQSPI_STIG_DATA_LEN_MAX || rxbuf == NULL) { 637 | //uart_printf("QSPI: Invalid input arguments cmdlen %d rxlen %d\n", 638 | //cmdlen, rxlen); 639 | return -1; 640 | } 641 | 642 | reg = cmdbuf[0] << CQSPI_REG_CMDCTRL_OPCODE_LSB; 643 | 644 | reg |= (0x1 << CQSPI_REG_CMDCTRL_RD_EN_LSB); 645 | 646 | /* 0 means 1 byte. */ 647 | reg |= (((rxlen - 1) & CQSPI_REG_CMDCTRL_RD_BYTES_MASK) 648 | << CQSPI_REG_CMDCTRL_RD_BYTES_LSB); 649 | status = cadence_qspi_apb_exec_flash_cmd(reg_base, reg); 650 | if (status != 0) 651 | return status; 652 | 653 | reg = readl((u32)reg_base + CQSPI_REG_CMDREADDATALOWER); 654 | 655 | /* Put the read value into rx_buf */ 656 | read_len = (rxlen > 4) ? 4 : rxlen; 657 | sys_memcpy(rxbuf, ®, read_len); 658 | rxbuf += read_len; 659 | 660 | if (rxlen > 4) { 661 | reg = readl((u32)reg_base + CQSPI_REG_CMDREADDATAUPPER); 662 | 663 | read_len = rxlen - read_len; 664 | sys_memcpy(rxbuf, ®, read_len); 665 | } 666 | return 0; 667 | } 668 | 669 | /* For commands: WRSR, WREN, WRDI, CHIP_ERASE, BE, etc. */ 670 | int cadence_qspi_apb_command_write(void * reg_base, unsigned int cmdlen, 671 | const u8 *cmdbuf, unsigned int txlen, const u8 *txbuf) 672 | { 673 | unsigned int reg = 0; 674 | unsigned int addr_value; 675 | unsigned int wr_data; 676 | unsigned int wr_len; 677 | 678 | if (!cmdlen || cmdlen > 5 || txlen > 8 || cmdbuf == NULL) { 679 | //uart_printf("QSPI: Invalid input arguments cmdlen %d txlen %d\n", 680 | //cmdlen, txlen); 681 | return -1; 682 | } 683 | 684 | reg |= cmdbuf[0] << CQSPI_REG_CMDCTRL_OPCODE_LSB; 685 | 686 | if (cmdlen == 4 || cmdlen == 5) { 687 | /* Command with address */ 688 | reg |= (0x1 << CQSPI_REG_CMDCTRL_ADDR_EN_LSB); 689 | /* Number of bytes to write. */ 690 | reg |= ((cmdlen - 2) & CQSPI_REG_CMDCTRL_ADD_BYTES_MASK) 691 | << CQSPI_REG_CMDCTRL_ADD_BYTES_LSB; 692 | /* Get address */ 693 | addr_value = cadence_qspi_apb_cmd2addr(&cmdbuf[1], 694 | cmdlen >= 5 ? 4 : 3); 695 | 696 | writel(addr_value, (u32)reg_base + CQSPI_REG_CMDADDRESS); 697 | } 698 | 699 | if (txlen) { 700 | /* writing data = yes */ 701 | reg |= (0x1 << CQSPI_REG_CMDCTRL_WR_EN_LSB); 702 | reg |= ((txlen - 1) & CQSPI_REG_CMDCTRL_WR_BYTES_MASK) 703 | << CQSPI_REG_CMDCTRL_WR_BYTES_LSB; 704 | 705 | wr_len = txlen > 4 ? 4 : txlen; 706 | sys_memcpy(&wr_data, txbuf, wr_len); 707 | writel(wr_data, (u32)reg_base + 708 | CQSPI_REG_CMDWRITEDATALOWER); 709 | 710 | if (txlen > 4) { 711 | txbuf += wr_len; 712 | wr_len = txlen - wr_len; 713 | sys_memcpy(&wr_data, txbuf, wr_len); 714 | writel(wr_data, (u32)reg_base + 715 | CQSPI_REG_CMDWRITEDATAUPPER); 716 | } 717 | } 718 | 719 | /* Execute the command */ 720 | return cadence_qspi_apb_exec_flash_cmd(reg_base, reg); 721 | } 722 | 723 | /* Opcode + Address (3/4 bytes) + dummy bytes (0-4 bytes) */ 724 | int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata *plat, 725 | unsigned int cmdlen, const u8 *cmdbuf) 726 | { 727 | unsigned int reg; 728 | unsigned int rd_reg; 729 | unsigned int addr_value; 730 | unsigned int dummy_clk; 731 | unsigned int dummy_bytes; 732 | unsigned int addr_bytes; 733 | 734 | /* 735 | * Identify addr_byte. All NOR flash device drivers are using fast read 736 | * which always expecting 1 dummy byte, 1 cmd byte and 3/4 addr byte. 737 | * With that, the length is in value of 5 or 6. Only FRAM chip from 738 | * ramtron using normal read (which won't need dummy byte). 739 | * Unlikely NOR flash using normal read due to performance issue. 740 | */ 741 | if (cmdlen >= 5) 742 | /* to cater fast read where cmd + addr + dummy */ 743 | addr_bytes = cmdlen - 2; 744 | else 745 | /* for normal read (only ramtron as of now) */ 746 | addr_bytes = cmdlen - 1; 747 | 748 | /* Setup the indirect trigger address */ 749 | writel(((u32)plat->ahbbase & CQSPI_INDIRECTTRIGGER_ADDR_MASK), 750 | (u32)plat->regbase + CQSPI_REG_INDIRECTTRIGGER); 751 | 752 | /* Configure the opcode */ 753 | rd_reg = cmdbuf[0] << CQSPI_REG_RD_INSTR_OPCODE_LSB; 754 | if(plat->bit_mode == 4) 755 | { 756 | /* Instruction and address at DQ0, data at DQ0-3. */ 757 | rd_reg |= CQSPI_INST_TYPE_QUAD << CQSPI_REG_RD_INSTR_TYPE_DATA_LSB; 758 | } 759 | else 760 | { 761 | rd_reg &= ~(CQSPI_INST_TYPE_QUAD << CQSPI_REG_RD_INSTR_TYPE_DATA_LSB); 762 | } 763 | /* Get address */ 764 | addr_value = cadence_qspi_apb_cmd2addr(&cmdbuf[1], addr_bytes); 765 | writel(addr_value, (u32)plat->regbase + CQSPI_REG_INDIRECTRDSTARTADDR); 766 | 767 | /* The remaining lenght is dummy bytes. */ 768 | dummy_bytes = cmdlen - addr_bytes - 1; 769 | if (dummy_bytes) { 770 | if (dummy_bytes > CQSPI_DUMMY_BYTES_MAX) 771 | dummy_bytes = CQSPI_DUMMY_BYTES_MAX; 772 | 773 | rd_reg |= (1 << CQSPI_REG_RD_INSTR_MODE_EN_LSB); 774 | #if defined(CONFIG_SPL_SPI_XIP) && defined(CONFIG_SPL_BUILD) 775 | writel(0x0, plat->regbase + CQSPI_REG_MODE_BIT); 776 | #else 777 | writel(0xFF, (u32)plat->regbase + CQSPI_REG_MODE_BIT); 778 | #endif 779 | 780 | /* Convert to clock cycles. */ 781 | dummy_clk = dummy_bytes * CQSPI_DUMMY_CLKS_PER_BYTE; 782 | /* Need to minus the mode byte (8 clocks). */ 783 | dummy_clk -= CQSPI_DUMMY_CLKS_PER_BYTE; 784 | 785 | if (dummy_clk) 786 | rd_reg |= (dummy_clk & CQSPI_REG_RD_INSTR_DUMMY_MASK) 787 | << CQSPI_REG_RD_INSTR_DUMMY_LSB; 788 | } 789 | 790 | writel(rd_reg, (u32)plat->regbase + CQSPI_REG_RD_INSTR); 791 | //writel(0x0012006b, (u32)plat->regbase + CQSPI_REG_RD_INSTR); 792 | //writel(0x041220eb, (u32)plat->regbase + CQSPI_REG_RD_INSTR); 793 | /* set device size */ 794 | reg = readl((u32)plat->regbase + CQSPI_REG_SIZE); 795 | reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK; 796 | reg |= (addr_bytes - 1); 797 | writel(reg, (u32)plat->regbase + CQSPI_REG_SIZE); 798 | return 0; 799 | } 800 | 801 | int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat, 802 | unsigned int rxlen, u8 *rxbuf) 803 | { 804 | unsigned int reg; 805 | 806 | writel(rxlen, (u32)plat->regbase + CQSPI_REG_INDIRECTRDBYTES); 807 | 808 | /* Start the indirect read transfer */ 809 | writel(CQSPI_REG_INDIRECTRD_START_MASK, 810 | (u32)plat->regbase + CQSPI_REG_INDIRECTRD); 811 | 812 | if (qspi_read_sram_fifo_poll(plat->regbase, (void *)rxbuf, 813 | (const void *)plat->ahbbase, rxlen)) 814 | goto failrd; 815 | 816 | /* Check flash indirect controller */ 817 | reg = readl((u32)plat->regbase + CQSPI_REG_INDIRECTRD); 818 | if (!(reg & CQSPI_REG_INDIRECTRD_DONE_MASK)) { 819 | reg = readl((u32)plat->regbase + CQSPI_REG_INDIRECTRD); 820 | //uart_printf("QSPI read_execute: indirect completion status error with reg 0x%x\n", 821 | //reg); 822 | goto failrd; 823 | } 824 | 825 | /* Clear indirect completion status */ 826 | writel(CQSPI_REG_INDIRECTRD_DONE_MASK, 827 | (u32)plat->regbase + CQSPI_REG_INDIRECTRD); 828 | return 0; 829 | 830 | failrd: 831 | /* Cancel the indirect read */ 832 | writel(CQSPI_REG_INDIRECTRD_CANCEL_MASK, 833 | (u32)plat->regbase + CQSPI_REG_INDIRECTRD); 834 | return -1; 835 | } 836 | 837 | /* Opcode + Address (3/4 bytes) */ 838 | int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata *plat, 839 | unsigned int cmdlen, const u8 *cmdbuf) 840 | { 841 | unsigned int reg; 842 | unsigned int addr_bytes = cmdlen > 4 ? 4 : 3; 843 | 844 | if (cmdlen < 4 || cmdbuf == NULL) { 845 | //uart_printf("QSPI: iInvalid input argument, len %d cmdbuf 0x%x\n", 846 | //cmdlen, (unsigned int)cmdbuf); 847 | return -1; 848 | } 849 | /* Setup the indirect trigger address */ 850 | writel(((u32)plat->ahbbase & CQSPI_INDIRECTTRIGGER_ADDR_MASK), 851 | (u32)plat->regbase + CQSPI_REG_INDIRECTTRIGGER); 852 | 853 | /* Configure the opcode */ 854 | reg = cmdbuf[0] << CQSPI_REG_WR_INSTR_OPCODE_LSB; 855 | if(plat->bit_mode == 4) 856 | { 857 | /* Instruction and address at DQ0, data at DQ0-3. */ 858 | reg |= CQSPI_INST_TYPE_QUAD << CQSPI_REG_WR_INSTR_TYPE_DATA_LSB; 859 | } 860 | else 861 | { 862 | reg &= ~(CQSPI_INST_TYPE_QUAD << CQSPI_REG_WR_INSTR_TYPE_DATA_LSB); 863 | } 864 | writel(reg, (u32)plat->regbase + CQSPI_REG_WR_INSTR); 865 | //writel(0x00020032, (u32)plat->regbase + CQSPI_REG_WR_INSTR); 866 | 867 | /* Setup write address. */ 868 | reg = cadence_qspi_apb_cmd2addr(&cmdbuf[1], addr_bytes); 869 | writel(reg, (u32)plat->regbase + CQSPI_REG_INDIRECTWRSTARTADDR); 870 | 871 | reg = readl((u32)plat->regbase + CQSPI_REG_SIZE); 872 | reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK; 873 | reg |= (addr_bytes - 1); 874 | writel(reg, (u32)plat->regbase + CQSPI_REG_SIZE); 875 | return 0; 876 | } 877 | 878 | int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat, 879 | unsigned int txlen, const u8 *txbuf) 880 | { 881 | unsigned int reg = 0; 882 | unsigned int retry; 883 | 884 | /* Configure the indirect read transfer bytes */ 885 | writel(txlen, (u32)plat->regbase + CQSPI_REG_INDIRECTWRBYTES); 886 | 887 | /* Start the indirect write transfer */ 888 | writel(CQSPI_REG_INDIRECTWR_START_MASK, 889 | (u32)plat->regbase + CQSPI_REG_INDIRECTWR); 890 | 891 | if (qpsi_write_sram_fifo_push(plat, (const void *)txbuf, txlen)) 892 | goto failwr; 893 | #if 1 894 | /* Wait until last write is completed (FIFO empty) */ 895 | retry = CQSPI_REG_RETRY; 896 | while (retry--) { 897 | reg = CQSPI_GET_WR_SRAM_LEVEL((u32)plat->regbase); 898 | if (reg == 0) 899 | break; 900 | 901 | delay(1000); 902 | } 903 | 904 | if (reg != 0) { 905 | //uart_printf("QSPI: timeout for indirect write\n"); 906 | goto failwr; 907 | } 908 | 909 | /* Check flash indirect controller status */ 910 | retry = CQSPI_REG_RETRY; 911 | while (retry--) { 912 | reg = readl((u32)plat->regbase + CQSPI_REG_INDIRECTWR); 913 | if (reg & CQSPI_REG_INDIRECTWR_DONE_MASK) 914 | break; 915 | delay(1000); 916 | } 917 | 918 | if (!(reg & CQSPI_REG_INDIRECTWR_DONE_MASK)) { 919 | //uart_printf("QSPI write_execute: indirect completion status error with reg 0x%x\n", 920 | // reg); 921 | goto failwr; 922 | } 923 | 924 | /* Clear indirect completion status */ 925 | writel(CQSPI_REG_INDIRECTWR_DONE_MASK, 926 | (u32)plat->regbase + CQSPI_REG_INDIRECTWR); 927 | #endif 928 | return 0; 929 | 930 | failwr: 931 | /* Cancel the indirect write */ 932 | writel(CQSPI_REG_INDIRECTWR_CANCEL_MASK, 933 | (u32)plat->regbase + CQSPI_REG_INDIRECTWR); 934 | return -1; 935 | } 936 | -------------------------------------------------------------------------------- /src/driver/spi/spi.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | /** 3 | ****************************************************************************** 4 | * @file spi.c 5 | * @author StarFive Technology 6 | * @version V1.0 7 | * @date 07/24/2020 8 | * @brief 9 | ****************************************************************************** 10 | * @copy 11 | * 12 | * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS 13 | * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE 14 | * TIME. AS A RESULT, STARFIVE SHALL NOT BE HELD LIABLE FOR ANY 15 | * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING 16 | * FROM THE CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE 17 | * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. 18 | * 19 | * COPYRIGHT 2020 Shanghai StarFive Technology Co., Ltd. 20 | */ 21 | 22 | #include 23 | #include 24 | 25 | #define SPI_CONTROLLER_NUM 1 26 | struct spi_operation *operations[SPI_CONTROLLER_NUM]; 27 | 28 | int spi_register(unsigned int bus, struct spi_operation *operation) 29 | { 30 | if(bus> SPI_CONTROLLER_NUM-1) 31 | return -1; 32 | 33 | operations[bus] = operation; 34 | 35 | return 0; 36 | } 37 | 38 | int spi_unregister(unsigned int bus) 39 | { 40 | if(bus> SPI_CONTROLLER_NUM-1) 41 | return -1; 42 | 43 | operations[bus] = 0; 44 | 45 | return 0; 46 | } 47 | 48 | struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, 49 | unsigned int max_hz, unsigned int mode, unsigned int bus_width) 50 | { 51 | if(bus> SPI_CONTROLLER_NUM-1) 52 | return NULL; 53 | 54 | if(operations[bus]->setup_slave) 55 | return operations[bus]->setup_slave(bus,cs,max_hz,mode,bus_width); 56 | 57 | return NULL; 58 | } 59 | int spi_xfer(struct spi_slave *slave, unsigned int bitlen, void *dout, 60 | void *din, unsigned long flags,int bit_mode) 61 | { 62 | unsigned int bus = slave->bus; 63 | int ret = -1; 64 | 65 | if(bus> SPI_CONTROLLER_NUM-1) 66 | return -1; 67 | 68 | if(operations[bus]->spi_xfer) 69 | ret = operations[bus]->spi_xfer(slave, bitlen, dout, din, flags, bit_mode); 70 | 71 | return ret; 72 | } 73 | 74 | -------------------------------------------------------------------------------- /src/driver/spi/spi.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Common SPI Interface: Controller-specific definitions 3 | * 4 | * (C) Copyright 2001 5 | * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com. 6 | * 7 | * SPDX-License-Identifier: GPL-2.0+ 8 | */ 9 | 10 | #ifndef _SPI_H_ 11 | #define _SPI_H_ 12 | 13 | #include 14 | 15 | #define SPI_DATEMODE_32 32 16 | #define SPI_DATAMODE_16 16 17 | #define SPI_DATAMODE_8 8 18 | 19 | /* SPI mode flags */ 20 | #define SPI_CPHA 0x01 /* clock phase */ 21 | #define SPI_CPOL 0x02 /* clock polarity */ 22 | #define SPI_MODE_0 (0|0) /* (original MicroWire) */ 23 | #define SPI_MODE_1 (0|SPI_CPHA) 24 | #define SPI_MODE_2 (SPI_CPOL|0) 25 | #define SPI_MODE_3 (SPI_CPOL|SPI_CPHA) 26 | #define SPI_CS_HIGH 0x04 /* CS active high */ 27 | #define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire */ 28 | #define SPI_3WIRE 0x10 /* SI/SO signals shared */ 29 | #define SPI_LOOP 0x20 /* loopback mode */ 30 | #define SPI_SLAVE 0x40 /* slave mode */ 31 | #define SPI_PREAMBLE 0x80 /* Skip preamble bytes */ 32 | 33 | /* SPI transfer flags */ 34 | #define SPI_XFER_BEGIN 0x01 /* Assert CS before transfer */ 35 | #define SPI_XFER_END 0x02 /* Deassert CS after transfer */ 36 | #define SPI_XFER_MMAP 0x08 /* Memory Mapped start */ 37 | #define SPI_XFER_MMAP_END 0x10 /* Memory Mapped End */ 38 | #define SPI_XFER_ONCE (SPI_XFER_BEGIN | SPI_XFER_END) 39 | #define SPI_XFER_U_PAGE (1 << 5) 40 | 41 | /* SPI TX operation modes */ 42 | #define SPI_OPM_TX_QPP 1 << 0 43 | 44 | /* SPI RX operation modes */ 45 | #define SPI_OPM_RX_AS 1 << 0 46 | #define SPI_OPM_RX_DOUT 1 << 1 47 | #define SPI_OPM_RX_DIO 1 << 2 48 | #define SPI_OPM_RX_QOF 1 << 3 49 | #define SPI_OPM_RX_QIOF 1 << 4 50 | #define SPI_OPM_RX_EXTN SPI_OPM_RX_AS | SPI_OPM_RX_DOUT | \ 51 | SPI_OPM_RX_DIO | SPI_OPM_RX_QOF | \ 52 | SPI_OPM_RX_QIOF 53 | 54 | /* SPI bus connection options */ 55 | #define SPI_CONN_DUAL_SHARED 1 << 0 56 | #define SPI_CONN_DUAL_SEPARATED 1 << 1 57 | 58 | /* Header byte that marks the start of the message */ 59 | #define SPI_PREAMBLE_END_BYTE 0xec 60 | 61 | #define SPI_DEFAULT_WORDLEN 8 62 | 63 | /*----------------------------------------------------------------------- 64 | * Representation of a SPI slave, i.e. what we're communicating with. 65 | * 66 | * Drivers are expected to extend this with controller-specific data. 67 | * 68 | * bus: ID of the bus that the slave is attached to. 69 | * cs: ID of the chip select connected to the slave. 70 | */ 71 | 72 | struct spi_slave { 73 | unsigned int bus; 74 | unsigned int bus_width; 75 | #define NOT_SWAP_MODE 0 76 | #define SWAP_MODE 1 77 | unsigned int bus_order; 78 | unsigned int cs; 79 | }; 80 | 81 | struct spi_operation{ 82 | struct spi_slave* (*setup_slave)(unsigned int bus, unsigned int cs, 83 | unsigned int max_hz, u32 mode, u32 fifo_width); 84 | int (*spi_xfer)(struct spi_slave *slave, unsigned int bitlen, void *dout, 85 | void *din, unsigned long flags,int bit_mode); 86 | }; 87 | 88 | 89 | /** 90 | * Initialization, must be called once on start up. 91 | * 92 | */ 93 | void spi_init(void); 94 | 95 | /** 96 | * spi_do_alloc_slave - Allocate a new SPI slave (internal) 97 | * 98 | * Allocate and zero all fields in the spi slave, and set the bus/chip 99 | * select. Use the helper macro spi_alloc_slave() to call this. 100 | * 101 | * @offset: Offset of struct spi_slave within slave structure. 102 | * @size: Size of slave structure. 103 | * @bus: Bus ID of the slave chip. 104 | * @cs: Chip select ID of the slave chip on the specified bus. 105 | */ 106 | void *spi_do_alloc_slave(int offset, int size, unsigned int bus, 107 | unsigned int cs); 108 | 109 | /** 110 | * spi_alloc_slave - Allocate a new SPI slave 111 | * 112 | * Allocate and zero all fields in the spi slave, and set the bus/chip 113 | * select. 114 | * 115 | * @_struct: Name of structure to allocate (e.g. struct tegra_spi). 116 | * This structure must contain a member 'struct spi_slave *slave'. 117 | * @bus: Bus ID of the slave chip. 118 | * @cs: Chip select ID of the slave chip on the specified bus. 119 | */ 120 | #define spi_alloc_slave(_struct, bus, cs) \ 121 | spi_do_alloc_slave(offsetof(_struct, slave), \ 122 | sizeof(_struct), bus, cs) 123 | 124 | /** 125 | * spi_alloc_slave_base - Allocate a new SPI slave with no private data 126 | * 127 | * Allocate and zero all fields in the spi slave, and set the bus/chip 128 | * select. 129 | * 130 | * @bus: Bus ID of the slave chip. 131 | * @cs: Chip select ID of the slave chip on the specified bus. 132 | */ 133 | #define spi_alloc_slave_base(bus, cs) \ 134 | spi_do_alloc_slave(0, sizeof(struct spi_slave), bus, cs) 135 | 136 | int spi_register(unsigned int bus, struct spi_operation *operation); 137 | 138 | /** 139 | * Set up communications parameters for a SPI slave. 140 | * 141 | * This must be called once for each slave. Note that this function 142 | * usually doesn't touch any actual hardware, it only initializes the 143 | * contents of spi_slave so that the hardware can be easily 144 | * initialized later. 145 | * 146 | * @bus: Bus ID of the slave chip. 147 | * @cs: Chip select ID of the slave chip on the specified bus. 148 | * @max_hz: Maximum SCK rate in Hz. 149 | * @mode: Clock polarity, clock phase and other parameters. 150 | * 151 | * Returns: A spi_slave reference that can be used in subsequent SPI 152 | * calls, or NULL if one or more of the parameters are not supported. 153 | */ 154 | struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, 155 | unsigned int max_hz, unsigned int mode, unsigned int bus_width); 156 | 157 | /** 158 | * Free any memory associated with a SPI slave. 159 | * 160 | * @slave: The SPI slave 161 | */ 162 | 163 | 164 | /** 165 | * SPI transfer 166 | * 167 | * This writes "bitlen" bits out the SPI MOSI port and simultaneously clocks 168 | * "bitlen" bits in the SPI MISO port. That's just the way SPI works. 169 | * 170 | * The source of the outgoing bits is the "dout" parameter and the 171 | * destination of the input bits is the "din" parameter. Note that "dout" 172 | * and "din" can point to the same memory location, in which case the 173 | * input data overwrites the output data (since both are buffered by 174 | * temporary variables, this is OK). 175 | * 176 | * spi_xfer() interface: 177 | * @slave: The SPI slave which will be sending/receiving the data. 178 | * @bitlen: How many bits to write and read. 179 | * @dout: Pointer to a string of bits to send out. The bits are 180 | * held in a byte array and are sent MSB first. 181 | * @din: Pointer to a string of bits that will be filled in. 182 | * @flags: A bitwise combination of SPI_XFER_* flags. 183 | * 184 | * Returns: 0 on success, not 0 on failure 185 | */ 186 | int spi_xfer(struct spi_slave *slave, unsigned int bitlen, void *dout, 187 | void *din, unsigned long flags, int bit_mode); 188 | 189 | 190 | #endif /* _SPI_H_ */ 191 | -------------------------------------------------------------------------------- /src/driver/spi/spi_flash.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | /** 3 | ****************************************************************************** 4 | * @file spi_flash.c 5 | * @author StarFive Technology 6 | * @version V1.0 7 | * @date 07/24/2020 8 | * @brief 9 | ****************************************************************************** 10 | * @copy 11 | * 12 | * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS 13 | * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE 14 | * TIME. AS A RESULT, STARFIVE SHALL NOT BE HELD LIABLE FOR ANY 15 | * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING 16 | * FROM THE CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE 17 | * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. 18 | * 19 | * COPYRIGHT 2020 Shanghai StarFive Technology Co., Ltd. 20 | */ 21 | 22 | 23 | #include 24 | #include "spi.h" 25 | #include "spi_flash.h" 26 | #include "spi_flash_internal.h" 27 | #include 28 | 29 | static int qe_enable = 0; 30 | 31 | static void spi_flash_addr(u32 addr, u8 *cmd) 32 | { 33 | /* cmd[0] is actual command */ 34 | cmd[1] = (addr & 0x00FF0000) >> 16; 35 | cmd[2] = (addr & 0x0000FF00) >> 8; 36 | cmd[3] = (addr & 0x000000FF) >> 0; 37 | } 38 | 39 | static int spi_flash_read_write(struct spi_slave *spi, 40 | u8 *cmd, u32 cmd_len, 41 | u8 *data_out, u8 *data_in, 42 | u32 data_len) 43 | { 44 | unsigned long flags = SPI_XFER_BEGIN; 45 | int ret; 46 | 47 | if (data_len == 0) 48 | flags |= SPI_XFER_END; 49 | 50 | ret = spi_xfer(spi, cmd_len * 8, cmd, NULL, flags, SPI_DATAMODE_8); 51 | if (ret) 52 | { 53 | //uart_printf("SF: Failed to send command (%d bytes): %d\n", 54 | //cmd_len, ret); 55 | } 56 | else if (data_len != 0) 57 | { 58 | ret = spi_xfer(spi, data_len * 8, data_out, data_in, SPI_XFER_END, SPI_DATAMODE_8); 59 | } 60 | 61 | return ret; 62 | } 63 | 64 | int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, u32 len) 65 | { 66 | return spi_flash_cmd_read(spi, &cmd, 1, response, len); 67 | } 68 | 69 | int spi_flash_cmd_read(struct spi_slave *spi, u8 *cmd, 70 | u32 cmd_len, void *data, u32 data_len) 71 | { 72 | return spi_flash_read_write(spi, cmd, cmd_len, NULL, data, data_len); 73 | } 74 | 75 | int spi_flash_cmd_write(struct spi_slave *spi, u8 *cmd, u32 cmd_len, 76 | void *data, u32 data_len) 77 | { 78 | return spi_flash_read_write(spi, cmd, cmd_len, data, NULL, data_len); 79 | } 80 | 81 | int spi_flash_cmd_write_enable(struct spi_flash *flash) 82 | { 83 | return spi_flash_cmd(flash->spi, CMD_WRITE_ENABLE, (void*)NULL, 0); 84 | } 85 | 86 | int spi_flash_cmd_write_status_enable(struct spi_flash *flash) 87 | { 88 | return spi_flash_cmd(flash->spi, CMD_STATUS_ENABLE, (void*)NULL, 0); 89 | } 90 | 91 | int spi_flash_cmd_write_disable(struct spi_slave *spi) 92 | { 93 | return spi_flash_cmd(spi, CMD_WRITE_DISABLE, (void*)NULL, 0); 94 | } 95 | int spi_flash_cmd_read_status(struct spi_flash *flash, u8 *cmd, u32 cmd_len, u8 *status) 96 | { 97 | struct spi_slave *spi = flash->spi; 98 | int ret; 99 | 100 | ret = spi_xfer(spi, 8*cmd_len, cmd, NULL, SPI_XFER_BEGIN, SPI_DATAMODE_8); 101 | if (ret) { 102 | //uart_printf("SF: Failed to send command %x: %d\n", (unsigned int)cmd, ret); 103 | return ret; 104 | } 105 | 106 | ret = spi_xfer(spi, 8*1, NULL, status, SPI_XFER_END, SPI_DATAMODE_8); 107 | //uart_printf("status = 0x%x\r\n", status[0]); 108 | if (ret) 109 | return ret; 110 | 111 | return 0; 112 | } 113 | 114 | int spi_flash_cmd_poll_bit(struct spi_flash *flash, unsigned long timeout, 115 | u8 cmd, u8 poll_bit) 116 | { 117 | int ret; 118 | u8 status; 119 | u32 status_tmp = 0; 120 | u32 timebase_1 = 0; 121 | do { 122 | ret = spi_flash_cmd_read_status(flash, &cmd, 1, &status); 123 | //uart_printf("cmd = 0x%x, status = 0x%x\r\n", cmd, status); 124 | if (ret) 125 | return ret; 126 | if ((status & poll_bit) == 0) 127 | break; 128 | timebase_1++;//libo 129 | } while (timebase_1 < timeout); 130 | 131 | if ((status & poll_bit) == 0) 132 | return 0; 133 | 134 | /* Timed out */ 135 | //uart_printf("SF: time out!\r\n"); 136 | return -1; 137 | } 138 | 139 | int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) 140 | { 141 | return spi_flash_cmd_poll_bit(flash, timeout, 142 | CMD_READ_STATUS, STATUS_WIP); 143 | } 144 | 145 | int spi_flash_cmd_poll_enable(struct spi_flash *flash, unsigned long timeout, 146 | u8 cmd, u32 poll_bit) 147 | { 148 | int ret; 149 | u8 status; 150 | u32 status_tmp = 0; 151 | 152 | u32 timebase_1 = 0; 153 | do { 154 | 155 | ret = spi_flash_cmd_read_status(flash, &cmd, 1, &status); 156 | if (ret) 157 | return ret; 158 | //uart_printf("read status = 0x%x\r\n", status); 159 | if ((status & poll_bit) == 1) 160 | break; 161 | timebase_1++; 162 | } while (timebase_1 < timeout); 163 | 164 | /* Timed out */ 165 | //uart_printf("SF: time out!\r\n"); 166 | return 0; 167 | } 168 | 169 | int spi_flash_cmd_status_poll_enable(struct spi_flash *flash, unsigned long timeout, 170 | u8 cmd, u32 poll_bit) 171 | { 172 | int ret; 173 | u8 status; 174 | u32 status_tmp = 0; 175 | 176 | u32 timebase_1 = 0; 177 | do { 178 | 179 | ret = spi_flash_cmd_read_status(flash, &cmd, 1, &status); 180 | if (ret) 181 | return ret; 182 | //uart_printf("read status = 0x%x\r\n", status); 183 | if ((status & poll_bit) == 0x2) 184 | break; 185 | timebase_1++; 186 | } while (timebase_1 < timeout); 187 | 188 | /* Timed out */ 189 | //uart_printf("SF: time out!\r\n"); 190 | return 0; 191 | } 192 | 193 | int spi_flash_cmd_wait_enable(struct spi_flash *flash, unsigned long timeout) 194 | { 195 | return spi_flash_cmd_status_poll_enable(flash, timeout, 196 | CMD_READ_STATUS, FLASH_ENABLE); 197 | } 198 | int spi_flash_write_status(struct spi_flash *flash, u8 *cmd, unsigned int cmd_len,void *data, unsigned int data_len) 199 | { 200 | int ret; 201 | 202 | ret = spi_flash_cmd_write_enable(flash); 203 | if (ret) { 204 | // uart_printf("SF: Unable to claim SPI bus\n"); 205 | return ret; 206 | } 207 | 208 | ret = spi_flash_cmd_write(flash->spi, cmd, cmd_len, data, data_len); 209 | if (ret < 0) { 210 | //uart_printf("SF: write failed\n"); 211 | return ret; 212 | } 213 | ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); 214 | if (ret < 0) { 215 | //uart_printf("SF: wait ready failed\n"); 216 | return ret; 217 | } 218 | ret = spi_flash_cmd_write_disable(flash->spi); 219 | if (ret < 0) { 220 | //uart_printf("SF: disable write failed\n"); 221 | return ret; 222 | } 223 | return 0; 224 | } 225 | #ifdef ISP_BOARD 226 | int spi_flash_write_status_bit(struct spi_flash *flash, u8 status0, u8 bit0) 227 | { 228 | u8 status[2]; 229 | int ret = 0; 230 | 231 | status[0] = CMD_WRITE_STATUS; 232 | status[1] = status0|bit0; 233 | spi_flash_write_status(flash, &status[0], 1, &status[1], 1); 234 | 235 | if (bit0) 236 | { 237 | ret &= spi_flash_cmd_poll_bit(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT, CMD_READ_STATUS, ~bit0); 238 | } 239 | 240 | return ret; 241 | delay(1000); 242 | 243 | 244 | return ret; 245 | } 246 | int spi_flash_protect(struct spi_flash *flash) 247 | { 248 | /* set PB=0 all can write */ 249 | return spi_flash_write_status_bit(flash, 0x00, 0); 250 | } 251 | #else 252 | int spi_flash_write_status_bit(struct spi_flash *flash, u8 status1, u8 status2, u8 bit1, u8 bit2) 253 | { 254 | u8 status[3]; 255 | int ret = 0; 256 | 257 | status[0] = CMD_WRITE_STATUS; 258 | status[1] = status1|bit1; 259 | status[2] = status2|bit2; 260 | spi_flash_write_status(flash, &status[0], 1, &status[1], 2); 261 | 262 | if (bit1) 263 | { 264 | ret &= spi_flash_cmd_poll_bit(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT, CMD_READ_STATUS, ~bit1); 265 | } 266 | if (bit2) 267 | { 268 | ret &= spi_flash_cmd_poll_bit(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT, CMD_READ_STATUS1, ~bit2); 269 | } 270 | 271 | return ret; 272 | delay(1000); 273 | 274 | 275 | return ret; 276 | } 277 | 278 | int spi_flash_protect(struct spi_flash *flash) 279 | { 280 | /* set PB=0 all can write */ 281 | return spi_flash_write_status_bit(flash, 0x00, 0x00, 0, 0); 282 | } 283 | #endif 284 | int spi_flash_cmd_erase(struct spi_flash *flash, u8 erase_cmd, 285 | u32 offset, u32 len) 286 | { 287 | u32 start, end, erase_size; 288 | int ret; 289 | u8 cmd[4]; 290 | 291 | //uart_printf("spi_flash_cmd_erase \r\n"); 292 | 293 | switch(erase_cmd){ 294 | case CMD_W25_SE: 295 | erase_size = flash->sector_size; 296 | break; 297 | case CMD_W25_BE_32: 298 | erase_size = flash->sector_size * 8; 299 | break; 300 | case CMD_W25_BE: 301 | erase_size = flash->block_size; 302 | break; 303 | default: 304 | erase_size = flash->sector_size; 305 | break; 306 | } 307 | 308 | if (offset % erase_size || len % erase_size) { 309 | //uart_printf("SF: Erase offset/length not multiple of erase size\n"); 310 | return -1; 311 | } 312 | 313 | // spi_flash_cmd_write_status_enable(flash); 314 | spi_flash_protect(flash); 315 | 316 | cmd[0] = erase_cmd; 317 | start = offset; 318 | end = start + len; 319 | while (offset < end) 320 | { 321 | spi_flash_addr(offset, cmd); 322 | offset += erase_size; 323 | 324 | //uart_printf("SF: erase %x %x %x %x (%x)\n", cmd[0], cmd[1], 325 | // cmd[2], cmd[3], offset); 326 | 327 | ret = spi_flash_cmd_write_enable(flash); 328 | if (ret) 329 | goto out; 330 | 331 | //spi_flash_cmd_wait_enable(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); 332 | 333 | ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd), NULL, 0); 334 | if (ret) 335 | goto out; 336 | 337 | ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); 338 | if (ret) 339 | goto out; 340 | 341 | ret = spi_flash_cmd_write_disable(flash->spi); 342 | if (ret) 343 | goto out; 344 | 345 | } 346 | 347 | //uart_printf("SF: Successfully erased %d bytes @ %x\n", len , start); 348 | 349 | out: 350 | return ret; 351 | } 352 | 353 | /* mode is 4, 32, 64*/ 354 | int spi_flash_erase_mode(struct spi_flash *flash, u32 offset, u32 len, u32 mode) 355 | { 356 | int ret = 0; 357 | switch (mode) 358 | { 359 | case 4: 360 | ret = spi_flash_cmd_erase(flash, CMD_W25_SE, offset, len); 361 | break; 362 | case 32: 363 | ret = spi_flash_cmd_erase(flash, CMD_W25_BE_32, offset, len); 364 | break; 365 | case 64: 366 | ret = spi_flash_cmd_erase(flash, CMD_W25_BE, offset, len); 367 | break; 368 | default: 369 | ret = spi_flash_cmd_erase(flash, CMD_W25_BE, offset, len); 370 | break; 371 | } 372 | return ret; 373 | } 374 | 375 | int spi_flash_cmd_write_mode(struct spi_flash *flash, u32 offset,u32 len, void *buf, u32 mode) 376 | { 377 | struct spi_slave *spi = flash->spi; 378 | unsigned long byte_addr, page_size; 379 | u32 write_addr; 380 | u32 chunk_len, actual; 381 | int ret; 382 | u8 cmd[4]; 383 | int write_data = 1; 384 | unsigned long flags = SPI_XFER_BEGIN; 385 | 386 | page_size = flash->page_size; 387 | 388 | switch (mode){ 389 | case 1: 390 | cmd[0] = CMD_PAGE_PROGRAM; 391 | qe_enable = 0; 392 | break; 393 | case 4: 394 | cmd[0] = CMD_PAGE_PROGRAM_QUAD; 395 | #ifdef ISP_BOARD 396 | spi_flash_write_status_bit(flash, 0x00, STATUS_QE); 397 | #else 398 | spi_flash_write_status_bit(flash, 0x00, 0x00, 0, STATUS_QE); 399 | #endif 400 | break; 401 | default: 402 | cmd[0] = CMD_PAGE_PROGRAM; 403 | break; 404 | } 405 | 406 | 407 | for (actual = 0; actual < len; actual += chunk_len) 408 | { 409 | write_addr = offset; 410 | byte_addr = offset % page_size; 411 | chunk_len = min(len - actual, page_size - byte_addr); 412 | 413 | spi_flash_addr(write_addr, cmd); 414 | 415 | ret = spi_flash_cmd_write_enable(flash); 416 | if (ret < 0) { 417 | //uart_printf("SF: enabling write failed\n"); 418 | break; 419 | } 420 | spi_flash_cmd_wait_enable(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); 421 | #if 1 422 | if (mode == 1) 423 | { 424 | 425 | 426 | ret = spi_flash_cmd_write(flash->spi, cmd, 4, 427 | (unsigned char*)buf + actual, chunk_len); 428 | if (ret < 0) { 429 | //uart_printf("SF: write failed\n"); 430 | break; 431 | } 432 | 433 | } 434 | #endif 435 | if (mode == 4) 436 | { 437 | flags = SPI_XFER_BEGIN; 438 | if (chunk_len == 0) 439 | flags |= SPI_XFER_END; 440 | 441 | ret = spi_xfer(spi, 4 * 8, cmd, NULL, flags, SPI_DATAMODE_8); 442 | if (ret < 0) 443 | { 444 | //uart_printf("xfer failed\n"); 445 | return ret; 446 | } 447 | else if (chunk_len != 0) 448 | { 449 | //qspi_mode_ctl(SPI4_DATEMODE_4); 450 | ret = spi_xfer(spi, chunk_len * 8, (unsigned char*)buf + actual, NULL, SPI_XFER_END, SPI_DATAMODE_8); 451 | 452 | } 453 | } 454 | //qspi_mode_ctl(SPI4_DATEMODE_0); 455 | ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); 456 | if (ret < 0) 457 | { 458 | //uart_printf("SF: spi_flash_cmd_wait_ready failed\n"); 459 | break; 460 | } 461 | ret = spi_flash_cmd_write_disable(flash->spi); 462 | if (ret < 0) 463 | { 464 | //uart_printf("SF: disable write failed\n"); 465 | break; 466 | } 467 | 468 | offset += chunk_len; 469 | //uart_printf("SF: program %s %d bytes @ %d\n", ret ? "failure" : "success", len, offset); 470 | } 471 | return ret; 472 | } 473 | 474 | int spi_flash_read_common(struct spi_flash *flash, u8 *cmd, 475 | u32 cmd_len, void *data, u32 data_len) 476 | { 477 | struct spi_slave *spi = flash->spi; 478 | int ret; 479 | 480 | ret = spi_flash_cmd_read(spi, cmd, cmd_len, data, data_len); 481 | 482 | return ret; 483 | } 484 | 485 | int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset, 486 | u32 len, void *data, u32 mode) 487 | { 488 | u8 cmd[5]; 489 | 490 | cmd[0] = CMD_READ_ARRAY_FAST; 491 | spi_flash_addr(offset, cmd); 492 | cmd[4] = 0x00; 493 | 494 | return spi_flash_read_common(flash, cmd, sizeof(cmd), data, len); 495 | } 496 | 497 | int spi_flash_read_mode(struct spi_flash *flash, u32 offset, 498 | u32 len, void *data, u32 mode) 499 | { 500 | struct spi_slave *spi = flash->spi; 501 | u8 cmd[5]; 502 | int ret; 503 | int write_data = 0; 504 | u8 status[2] = {2}; 505 | int i = 0; 506 | 507 | switch (mode) 508 | { 509 | case 1: 510 | cmd[0] = CMD_READ_ARRAY_FAST; 511 | qe_enable = 0; 512 | break; 513 | case 2: 514 | cmd[0] = CMD_READ_ARRAY_DUAL; 515 | break; 516 | case 4: 517 | #ifdef ISP_BOARD 518 | cmd[0] = CMD_READ_ARRAY_LEGACY; 519 | //spi_flash_cmd_write_reg_mode(flash, flash_reg_offset, 1, flash_reg); 520 | //flash_reg[0] = 0; 521 | //spi_flash_cmd_write_reg_mode(flash, flash_reg_offset, 1, flash_reg); 522 | //spi_flash_read_reg_mode(flash, flash_reg_offset, 1, flash_reg); 523 | #else 524 | cmd[0] = CMD_READ_ARRAY_QUAD; 525 | if(qe_enable == 0) 526 | { 527 | spi_flash_write_status_bit(flash, 0x00, 0x00, 0, STATUS_QE);; 528 | qe_enable = 1; 529 | } 530 | #endif 531 | break; 532 | default: 533 | cmd[0] = CMD_READ_ARRAY_FAST; 534 | break; 535 | } 536 | 537 | //spi_flash_cmd_poll_bit(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT, CMD_READ_STATUS1, ~STATUS_QE); 538 | 539 | 540 | spi_flash_addr(offset, cmd); 541 | cmd[4] = 0x00; 542 | 543 | 544 | ret = spi_xfer(spi, 5*8, cmd, NULL, SPI_XFER_BEGIN, SPI_DATAMODE_8); 545 | if (ret < 0) 546 | { 547 | //uart_printf("xfer failed\n"); 548 | return ret; 549 | } 550 | ret = spi_xfer(spi, len*8, NULL, data, SPI_XFER_END, SPI_DATAMODE_8); 551 | if (ret < 0) 552 | { 553 | //uart_printf("xfer failed\n"); 554 | return ret; 555 | } 556 | 557 | return 0; 558 | } 559 | -------------------------------------------------------------------------------- /src/driver/spi/spi_flash.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | /** 3 | ****************************************************************************** 4 | * @file spi_flash.h 5 | * @author StarFive Technology 6 | * @version V1.0 7 | * @date 07/24/2020 8 | * @brief 9 | ****************************************************************************** 10 | * @copy 11 | * 12 | * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS 13 | * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE 14 | * TIME. AS A RESULT, STARFIVE SHALL NOT BE HELD LIABLE FOR ANY 15 | * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING 16 | * FROM THE CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE 17 | * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. 18 | * 19 | * COPYRIGHT 2020 Shanghai StarFive Technology Co., Ltd. 20 | */ 21 | 22 | #ifndef _SPI_FLASH_H_ 23 | #define _SPI_FLASH_H_ 24 | 25 | #include 26 | 27 | 28 | //#define SPI_1LINE 29 | 30 | struct spi_flash_params { 31 | const char *name; 32 | u32 id; 33 | /* Log2 of page size in power-of-two mode */ 34 | u8 l2_page_size; 35 | u16 pages_per_sector; 36 | u16 sectors_per_block; 37 | u16 nr_blocks; 38 | int flags; 39 | }; 40 | 41 | struct spi_flash 42 | { 43 | struct spi_slave *spi; 44 | //void *regs; 45 | const char *name; 46 | u32 size; /* Total flash size */ 47 | u32 page_size; /* Write (page) size */ 48 | u32 sector_size; /* Erase (sector) size */ 49 | u32 block_size; /* Erase (sector) size */ 50 | int (*read )(struct spi_flash *flash, u32 offset,u32 len, void *data, u32 mode); 51 | int (*write)(struct spi_flash *flash, u32 offset,u32 len, void *data, u32 mode); 52 | int (*erase)(struct spi_flash *flash, u32 offset,u32 len, u32 mode); 53 | }; 54 | 55 | /*--------------------------------------------------- 56 | * spi_flash_probe: 57 | * This function initialize module hardware and some software structures , 58 | * setup slave and read id codes , search the table and call probe 59 | * 60 | * spi_flash_probe() interface: 61 | * bus: passed to the spi_setup_slave() 62 | * cs: idem 63 | * max_hz: idem 64 | * spi_mode: idem 65 | * bus_width: idem 66 | * 67 | * Returns: return NULL is error , if right return a struct contaims some information 68 | */ 69 | struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, 70 | unsigned int max_hz, u32 mode, u32 fifo_width); 71 | 72 | 73 | static /*inline*/ int spi_flash_read(struct spi_flash *flash, u32 offset, 74 | u32 len, void *buf, u32 mode) 75 | { 76 | return flash->read(flash, offset, len, buf, mode); 77 | } 78 | 79 | static /*inline*/ int spi_flash_write(struct spi_flash *flash, u32 offset, 80 | u32 len, void *buf, u32 mode) 81 | { 82 | return flash->write(flash, offset, len, buf, mode); 83 | } 84 | 85 | static /*inline*/ int spi_flash_erase(struct spi_flash *flash, u32 offset, 86 | u32 len, u32 mode) 87 | { 88 | return flash->erase(flash, offset, len, mode); 89 | } 90 | 91 | 92 | #endif /* _SPI_FLASH_H_ */ 93 | -------------------------------------------------------------------------------- /src/driver/spi/spi_flash_internal.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | /* 3 | * SPI flash internal definitions 4 | * 5 | * Copyright (C) 2008 Atmel Corporation 6 | */ 7 | 8 | /* Common parameters -- kind of high, but they should only occur when there 9 | * is a problem (and well your system already is broken), so err on the side 10 | * of caution in case we're dealing with slower SPI buses and/or processors. 11 | */ 12 | #ifndef __SPI_FLASH_INTERNAL_H_ 13 | #define __SPI_FLASH_INTERNAL_H_ 14 | 15 | #include 16 | 17 | #define CONFIG_SYS_HZ 12000000 18 | #define SPI_FLASH_PROG_TIMEOUT (2 * CONFIG_SYS_HZ) 19 | #define SPI_FLASH_PAGE_ERASE_TIMEOUT (5 * CONFIG_SYS_HZ) 20 | #define SPI_FLASH_SECTOR_ERASE_TIMEOUT (10 * CONFIG_SYS_HZ) 21 | 22 | /* Common commands */ 23 | #define CMD_READ_ARRAY_SLOW 0x03 /* Read Data Bytes */ 24 | #define CMD_READ_ARRAY_FAST 0x0B 25 | #define CMD_READ_ARRAY_DUAL 0x3B 26 | #define CMD_READ_ARRAY_QUAD 0X6B 27 | #define CMD_READ_ARRAY_LEGACY 0xEB 28 | 29 | #define CMD_WRITE_STATUS 0x01 /* Write Status Register */ 30 | 31 | #define CMD_WRITE_STATUS_1 0x01 /* Write Status Register */ 32 | #define CMD_WRITE_STATUS_2 0x31 /* Write Status Register */ 33 | #define CMD_WRITE_STATUS_3 0x11 /* Write Status Register */ 34 | #define CMD_READ_STATUS_1 0x05 /* Read Status Register */ 35 | #define CMD_READ_STATUS_2 0x35 /* Read Status Register */ 36 | #define CMD_READ_STATUS_3 0x15 /* Read Status Register */ 37 | 38 | #define CMD_PAGE_PROGRAM 0x02 /* Page Program */ 39 | #define CMD_PAGE_PROGRAM_QUAD 0x32 40 | #define CMD_WRITE_DISABLE 0x04 /* Write Disable */ 41 | #define CMD_READ_STATUS 0x05 /* Read Status Register */ 42 | #define CMD_READ_STATUS1 0x35 43 | #define CMD_WRITE_ENABLE 0x06 /* Write Enable */ 44 | #define CMD_W25_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ 45 | #define CMD_W25_SE 0x20 /* Sector (4K) Erase */ 46 | #define CMD_W25_BE 0xd8 /* Block (64K) Erase */ 47 | #define CMD_W25_CE 0xc7 /* Chip Erase */ 48 | #define CMD_W25_DP 0xb9 /* Deep Power-down */ 49 | #define CMD_W25_RES 0xab /* Release from DP, and Read Signature */ 50 | #define CMD_W25_BE_32 0x52 /* Sector (32K) Erase */ 51 | #define CMD_STATUS_ENABLE 0x50 52 | 53 | /* Common status */ 54 | #define STATUS_WIP 0x01 55 | #define FLASH_ENABLE 0x02 56 | #define STATUS_QE (0x01 << 1) 57 | 58 | /* Send a single-byte command to the device and read the response */ 59 | int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, u32 len); 60 | 61 | /* 62 | * Send a multi-byte command to the device and read the response. Used 63 | * for flash array reads, etc. 64 | */ 65 | int spi_flash_cmd_read(struct spi_slave *spi, u8 *cmd,u32 cmd_len, 66 | void *data, u32 data_len); 67 | 68 | int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset, 69 | u32 len, void *data, u32 mode); 70 | 71 | int spi_flash_read_mode(struct spi_flash *flash, u32 offset, 72 | u32 len, void *data, u32 mode); 73 | 74 | /* 75 | * Send a multi-byte command to the device followed by (optional) 76 | * data. Used for programming the flash array, etc. 77 | */ 78 | int spi_flash_cmd_write(struct spi_slave *spi, u8 *cmd, u32 cmd_len, 79 | void *data, u32 data_len); 80 | 81 | /* 82 | * Write the requested data out breaking it up into multiple write 83 | * commands as needed per the write size. 84 | */ 85 | int spi_flash_cmd_write_mode(struct spi_flash *flash, u32 offset, 86 | u32 len, void *buf, u32 mode); 87 | 88 | /* 89 | * Enable writing on the SPI flash. 90 | */ 91 | int spi_flash_cmd_write_enable(struct spi_flash *flash); 92 | 93 | /* 94 | * Disable writing on the SPI flash. 95 | */ 96 | int spi_flash_cmd_write_disable(struct spi_slave *spi); 97 | 98 | /* 99 | * Same as spi_flash_cmd_read() except it also claims/releases the SPI 100 | * bus. Used as common part of the ->read() operation. 101 | */ 102 | int spi_flash_read_common(struct spi_flash *flash, u8 *cmd, 103 | u32 cmd_len, void *data, u32 data_len); 104 | 105 | /* Send a command to the device and wait for some bit to clear itself. */ 106 | int spi_flash_cmd_poll_bit(struct spi_flash *flash, unsigned long timeout, 107 | u8 cmd, u8 poll_bit); 108 | 109 | /* 110 | * Send the read status command to the device and wait for the wip 111 | * (write-in-progress) bit to clear itself. 112 | */ 113 | int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout); 114 | 115 | /* Erase sectors. */ 116 | int spi_flash_cmd_erase(struct spi_flash *flash, u8 erase_cmd, u32 offset, u32 len); 117 | int spi_flash_erase_mode(struct spi_flash *flash, u32 offset, u32 len, u32 mode); 118 | 119 | /* Manufacturer-specific probe functions */ 120 | struct spi_flash *spi_flash_probe_spansion(struct spi_slave *spi, u8 *idcode); 121 | struct spi_flash *spi_flash_probe_atmel(struct spi_slave *spi, u8 *idcode); 122 | struct spi_flash *spi_flash_probe_eon(struct spi_slave *spi, u8 *idcode); 123 | struct spi_flash *spi_flash_probe_macronix(struct spi_slave *spi, u8 *idcode); 124 | struct spi_flash *spi_flash_probe_sst(struct spi_slave *spi, u8 *idcode); 125 | struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 *idcode); 126 | struct spi_flash *spi_flash_probe_winbond(struct spi_slave *spi, u8 *idcode); 127 | struct spi_flash *spi_fram_probe_ramtron(struct spi_slave *spi, u8 *idcode); 128 | struct spi_flash *spi_flash_probe_gigadevice(struct spi_slave *spi, u8 *idcode); 129 | struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, 130 | unsigned int max_hz, u32 mode, u32 fifo_width); 131 | 132 | 133 | #endif 134 | 135 | -------------------------------------------------------------------------------- /src/driver/spi/spi_probe.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | /** 3 | ****************************************************************************** 4 | * @file spi_probe.c 5 | * @author StarFive Technology 6 | * @version V1.0 7 | * @date 07/24/2020 8 | * @brief 9 | ****************************************************************************** 10 | * @copy 11 | * 12 | * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS 13 | * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE 14 | * TIME. AS A RESULT, STARFIVE SHALL NOT BE HELD LIABLE FOR ANY 15 | * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING 16 | * FROM THE CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE 17 | * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. 18 | * 19 | * COPYRIGHT 2020 Shanghai StarFive Technology Co., Ltd. 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #define IDCODE_CONT_LEN 0 30 | #define IDCODE_PART_LEN 3 31 | #define IDCODE_LEN (IDCODE_CONT_LEN + IDCODE_PART_LEN) 32 | 33 | #define CMD_READ_ID 0x9f 34 | 35 | #define NOR 0 36 | #define GIGANAND 1 37 | 38 | //#define CONFIG_SPI_FLASH_ATMEL 39 | //#define CONFIG_SPI_FLASH_GIGADEVICE 40 | //#define CONFIG_SPI_FLASH_EON 41 | //#define CONFIG_SPI_FLASH_MACRONIX 42 | //#define CONFIG_SPI_FLASH_SPANSION 43 | //#define CONFIG_SPI_FLASH_STMICRO 44 | //#define CONFIG_SPI_FLASH_SST 45 | //#define CONFIG_SPI_FLASH_WINBOND 46 | //#define TEST_GD25Q64B 47 | //#define TEST_GD25Q64C 48 | //#define TEST_GD25LB64C 49 | 50 | static struct spi_flash g_spi_flash[1]; 51 | 52 | static const struct spi_flash_params spi_flash_table[] = 53 | { 54 | {"Common_flash", 0x534654, 8,16,16,256, NOR}, 55 | }; 56 | 57 | struct spi_flash *spi_flash_probe_nor(struct spi_slave *spi, u8 *idcode) 58 | { 59 | struct spi_flash_params *params; 60 | struct spi_flash *flash; 61 | u32 id = 0; 62 | static int i = 0; 63 | 64 | #if 0 65 | id = ((idcode[2] << 16) | (idcode[1] << 8) | idcode[0]); 66 | if(id == 0x0) 67 | { 68 | return NULL; 69 | } 70 | 71 | params = spi_flash_table; 72 | for (i = 0; spi_flash_table[i].name != NULL; i++) 73 | { 74 | if ((spi_flash_table[i].id & 0xFFFFFF) == id) 75 | { 76 | break; 77 | } 78 | } 79 | #endif 80 | flash = &g_spi_flash[0]; 81 | if (!flash) 82 | { 83 | //uart_printf("SF: Failed to allocate memory\r\n"); 84 | return NULL; 85 | } 86 | 87 | flash->name = spi_flash_table[i].name; 88 | if(spi_flash_table[i].flags == NOR) 89 | { 90 | /* Assuming power-of-two page size initially. */ 91 | flash->write = spi_flash_cmd_write_mode; 92 | flash->erase = spi_flash_erase_mode; 93 | flash->read = spi_flash_read_mode; 94 | flash->page_size = 1 << spi_flash_table[i].l2_page_size; 95 | flash->sector_size = flash->page_size * spi_flash_table[i].pages_per_sector; 96 | flash->block_size = flash->sector_size * spi_flash_table[i].sectors_per_block; 97 | flash->size = flash->page_size * spi_flash_table[i].pages_per_sector 98 | * spi_flash_table[i].sectors_per_block 99 | * spi_flash_table[i].nr_blocks; 100 | } 101 | 102 | //uart_printf("spi probe complete\r\n"); 103 | 104 | return flash; 105 | } 106 | #if 1 107 | static int print_id(u8 *idcode, int len) 108 | { 109 | int i; 110 | 111 | uart_printf("idcode:0x"); 112 | for (i=len-1; i>=0; i--) 113 | print_ubyte_hex(idcode[i]); 114 | uart_printf("\r\n"); 115 | return 0; 116 | } 117 | #endif 118 | static int spi_read_id(struct spi_slave *spi, unsigned char cmd, void *response, u32 len) 119 | { 120 | int ret = -1,ret1 = -1,ret2 = -1; 121 | unsigned char buf[4] = {0};// = {(u8)cmd, 0x00, 0x00, 0x00}; 122 | unsigned char buf_nor[1]; // = {(u8)cmd}; 123 | u8 *idcode = (u8 *)response; 124 | 125 | buf[0] = cmd; 126 | buf[1] = 0; 127 | buf[2] = 0; 128 | buf[3] = 0; 129 | 130 | buf_nor[0] = cmd; 131 | 132 | ret1 = spi_xfer(spi, 1*8, &buf[0], NULL, SPI_XFER_BEGIN, 8); 133 | ret2 = spi_xfer(spi, len*8, NULL, response, SPI_XFER_END, 8); 134 | return 0; 135 | } 136 | 137 | static struct spi_flash aic_flash; 138 | 139 | struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, 140 | unsigned int max_hz, unsigned int mode, unsigned int bus_width) 141 | { 142 | struct spi_slave *spi; 143 | struct spi_flash *flash = &aic_flash; 144 | int ret = 0; 145 | u8 idcode[IDCODE_LEN]; 146 | 147 | spi = spi_setup_slave(bus, cs, max_hz, mode, bus_width); 148 | if (!spi) { 149 | //uart_printf("SF: Failed to set up slave\n"); 150 | return NULL; 151 | } 152 | 153 | /* Read the ID codes */ 154 | ret = spi_read_id(spi, CMD_READ_ID, idcode, sizeof(idcode)); 155 | if (ret) 156 | { 157 | //uart_printf("SF: Failed to read ID : %d\n", ret); 158 | goto err_read_id; 159 | } 160 | 161 | print_id(idcode, sizeof(idcode)); 162 | 163 | flash = spi_flash_probe_nor(spi,idcode); 164 | if (!flash) 165 | { 166 | goto err_manufacturer_probe; 167 | } 168 | 169 | flash->spi = spi; 170 | return flash; 171 | 172 | err_manufacturer_probe: 173 | err_read_id: 174 | 175 | return NULL; 176 | } 177 | -------------------------------------------------------------------------------- /src/driver/timer/timer.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | /** 3 | ****************************************************************************** 4 | * @file timer.c 5 | * @author StarFive Technology 6 | * @version V1.0 7 | * @date 07/24/2020 8 | * @brief 9 | ****************************************************************************** 10 | * @copy 11 | * 12 | * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS 13 | * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE 14 | * TIME. AS A RESULT, STARFIVE SHALL NOT BE HELD LIABLE FOR ANY 15 | * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING 16 | * FROM THE CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE 17 | * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. 18 | * 19 | * COPYRIGHT 2020 Shanghai StarFive Technology Co., Ltd. 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #define TIMER_RATE_HZ (TIMER_CLK_HZ /1000) 30 | 31 | #include "platform.h" 32 | 33 | unsigned long long get_ticks(void) 34 | { 35 | return readq(CLINT_CTRL_MTIME); 36 | } 37 | 38 | u32 get_timer(unsigned int base) 39 | { 40 | return lldiv(get_ticks(), TIMER_RATE_HZ) - base; 41 | } 42 | #if 0 43 | u32 usec_to_tick(u32 usec) 44 | { 45 | u32 value = usec*(timer_clk/1000000); 46 | //printf("value = 0x%x\r\n", value); 47 | 48 | return usec*(timer_clk/1000000); 49 | } 50 | 51 | int udelay(u32 usec) 52 | { 53 | UINT64 tmp; 54 | UINT64 tmo; 55 | 56 | tmo = usec_to_tick(usec); 57 | tmp = get_ticks(0) + tmo; /* get current timestamp */ 58 | 59 | while (get_ticks(0) < tmp)/* loop till event */ 60 | /*NOP*/ 61 | { 62 | } 63 | 64 | return 0; 65 | } 66 | 67 | #endif 68 | 69 | u64 usec_to_tick(u64 usec) 70 | { 71 | u64 value; 72 | value = usec*(TIMER_CLK_HZ/1000)/1000; 73 | return value; 74 | } 75 | 76 | /* delay x useconds */ 77 | int udelay(unsigned int usec) 78 | { 79 | unsigned long tmp; 80 | 81 | tmp = readq((volatile void *)CLINT_CTRL_MTIME) + usec_to_tick(usec); /* get current timestamp */ 82 | 83 | while (readq((volatile void *)CLINT_CTRL_MTIME) < tmp); 84 | } 85 | 86 | void mdelay(unsigned int ms) 87 | { 88 | udelay(1000*ms); 89 | } 90 | 91 | void sdelay(unsigned int s) 92 | { 93 | mdelay(1000*s); 94 | } 95 | 96 | -------------------------------------------------------------------------------- /src/driver/timer/timer.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | /** 3 | ****************************************************************************** 4 | * @file timer.h 5 | * @author StarFive Technology 6 | * @version V1.0 7 | * @date 07/24/2020 8 | * @brief 9 | ****************************************************************************** 10 | * @copy 11 | * 12 | * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS 13 | * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE 14 | * TIME. AS A RESULT, STARFIVE SHALL NOT BE HELD LIABLE FOR ANY 15 | * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING 16 | * FROM THE CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE 17 | * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. 18 | * 19 | * COPYRIGHT 2020 Shanghai StarFive Technology Co., Ltd. 20 | */ 21 | 22 | #ifndef __TIMER_H__ 23 | #define __TIMER_H__ 24 | 25 | #include 26 | 27 | #if 0 28 | #define RUN_MODE_CONTINOUS 0 29 | #define RUN_MODE_SINGLE 1 30 | 31 | #define SOC_SYS_TIMER 0 /* system timer0 */ 32 | 33 | #define CONFIG_SYS_HZ_CLOCK TIMER_CLK_HZ 34 | 35 | struct timer_driver { 36 | void *base; 37 | unsigned long freq; 38 | int irq; 39 | }; 40 | 41 | struct timer_init_s{ 42 | u32 int_en; 43 | u32 run_mode; 44 | u32 size; 45 | u32 one_shot; 46 | u32 count; /* TODO: time value */ 47 | void (*callback)(void*); 48 | void *arg; 49 | u32 wdog_reset_en; 50 | }; 51 | 52 | /* 53 | * public function definition 54 | */ 55 | /*--------------------------------------------------- 56 | * 57 | * timer_clr_int_status: 58 | * This function clear int_status register. 59 | * 60 | * timer_clr_int_status() interface: 61 | * id:0/1/2 indicate clear timer0/timer1/timer2 62 | int_status register. 63 | * 64 | * Returns: 0 on success, not 0 on failure 65 | */ 66 | int timer_clr_int_status(u32 id); 67 | 68 | /*--------------------------------------------------- 69 | * 70 | * timer_set: 71 | * This function set registers defined by timer_init_s 72 | struct. 73 | * 74 | * timer_set() interface: 75 | * id:0/1/2 indicate clear timer0/timer1/timer2 76 | int_status register. 77 | init:timer_init_s struct ptr. 78 | * 79 | * Returns: 0 on success, not 0 on failure 80 | */ 81 | int timer_set(u32 id,struct timer_init_s *init); 82 | 83 | 84 | 85 | /*--------------------------------------------------- 86 | * 87 | */ 88 | void timer_reload(u32 id); 89 | 90 | /*--------------------------------------------------- 91 | * 92 | * timer_stop: 93 | * This function disable and clear interrupt regs of the timer. 94 | * 95 | * timer_stop() interface: 96 | * id:0/1/2 indicate clear timer0/timer1/timer2 97 | int_status register. 98 | * 99 | * Returns: 0 on success, not 0 on failure 100 | */ 101 | int timer_stop(u32 id); 102 | /*--------------------------------------------------- 103 | * 104 | * timer_start: 105 | * This function enable the timer. 106 | * 107 | * timer_start() interface: 108 | * id:0/1/2 indicate clear timer0/timer1/timer2 109 | int_status register. 110 | * 111 | * Returns: 0 on success, not 0 on failure 112 | */ 113 | int timer_start(u32 id); 114 | /*--------------------------------------------------- 115 | * timer_init: 116 | * This function initialize module hardware and some software structures. 117 | * You must call this function before other operation 118 | * 119 | * Returns: 0 on success, not 0 on failure 120 | */ 121 | int timer_init(int id); 122 | 123 | /*--------------------------------------------------- 124 | * module_exit: 125 | * This function free memory. 126 | * 127 | * Returns: 0 on success, not 0 on failure 128 | */ 129 | int timer_exit(void); 130 | #endif 131 | 132 | /*--------------------------------------------------- 133 | * 134 | * udelay: 135 | * This function used for delay usec microsecond. 136 | * 137 | * udelay() interface: 138 | * usec:0~357913941(MAX) int number. 139 | * 140 | * Returns: 0 on success, not 0 on failure 141 | */ 142 | int udelay(u32 usec); 143 | 144 | void mdelay(unsigned int ms); 145 | 146 | void sdelay(unsigned int s); 147 | 148 | u32 get_timer(unsigned int base); 149 | 150 | /*--------------------------------------------------- 151 | * 152 | * get_ticks: 153 | * This function get system ticks number. 154 | * 155 | * get_ticks() interface: 156 | * tick_base:base number of system ticks. 157 | * 158 | * Returns: a long long int number represent how many 159 | ticks from system start based on tick_base. 160 | */ 161 | 162 | unsigned long long get_ticks(void); 163 | 164 | 165 | /*--------------------------------------------------- 166 | * 167 | * usec_to_tick: 168 | * This function convert microsecond to system ticks. 169 | * 170 | * usec_to_tick() interface: 171 | * usec:0~357913941(MAX) int number. 172 | * 173 | * Returns: converted system ticks. 174 | */ 175 | u64 usec_to_tick(u64 usec); 176 | 177 | #define delay udelay 178 | 179 | #endif /* __TIMER_H__ */ 180 | -------------------------------------------------------------------------------- /src/driver/uart/uart.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | /** 3 | ****************************************************************************** 4 | * @file uart.c 5 | * @author StarFive Technology 6 | * @version V1.0 7 | * @date 07/24/2020 8 | * @brief 9 | ****************************************************************************** 10 | * @copy 11 | * 12 | * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS 13 | * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE 14 | * TIME. AS A RESULT, STARFIVE SHALL NOT BE HELD LIABLE FOR ANY 15 | * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING 16 | * FROM THE CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE 17 | * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. 18 | * 19 | * COPYRIGHT 2020 Shanghai StarFive Technology Co., Ltd. 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | //#include 32 | 33 | #define UART_CLK (100000000UL)///(64000000UL)/// 34 | 35 | /* CLK 32M */ 36 | #define UART_BUADRATE_32MCLK_9600 9600 37 | #define UART_BUADRATE_32MCLK_57600 57600 38 | #define UART_BUADRATE_32MCLK_115200 115200 39 | #define UART_BUADRATE_32MCLK_125000 125000 40 | #define UART_BUADRATE_32MCLK_222222 222222 ///230400 41 | #define UART_BUADRATE_32MCLK_333333 333333 ///380400 42 | #define UART_BUADRATE_32MCLK_400000 400000 ///460800 43 | #define UART_BUADRATE_32MCLK_500000 500000 44 | #define UART_BUADRATE_32MCLK_666666 666666 ///921600 45 | #define UART_BUADRATE_32MCLK_1M 1000000 46 | #define UART_BUADRATE_32MCLK_2M 2000000 47 | 48 | 49 | /* CLK 64M */ 50 | #define UART_BUADRATE_64MCLK_38400 38400 51 | #define UART_BUADRATE_64MCLK_57600 57600 52 | #define UART_BUADRATE_64MCLK_115200 115200 53 | #define UART_BUADRATE_64MCLK_230400 230400 54 | #define UART_BUADRATE_64MCLK_380400 380400 55 | #define UART_BUADRATE_64MCLK_444444 444444 ///460800 56 | #define UART_BUADRATE_64MCLK_500000 500000 57 | #define UART_BUADRATE_64MCLK_571428 571428 58 | #define UART_BUADRATE_64MCLK_666666 666666 ///921600 59 | 60 | #define UART_BUADRATE_64MCLK_800000 800000 ///921600 61 | #define UART_BUADRATE_64MCLK_1M 1000000 62 | #define UART_BUADRATE_64MCLK_2M 2000000 63 | 64 | ////#define UART_BUADRATE_2_5M 2500000 /// 65 | ////#define UART_BUADRATE_3M 3000000 /// 66 | #define UART_BUADRATE_64MCLK_4M 4000000 ///shiboqi 67 | 68 | volatile int uart_txfifo_available; 69 | 70 | #define UART_PORT 3 71 | 72 | static const u32 uart_base[4] = { 73 | UART0_BASE_ADDR, 74 | UART1_HS_BASE_ADDR, 75 | UART2_BASE_ADDR, 76 | UART3_BASE_ADDR, 77 | 78 | }; 79 | 80 | static unsigned int serial_in(int id, int offset) 81 | { 82 | offset <<= 2; 83 | return readw(uart_base[id] + offset); 84 | } 85 | 86 | static void serial_out(int id, int offset, int value) 87 | { 88 | offset <<= 2; 89 | writew(value, uart_base[id] + offset); 90 | } 91 | static void wait_for_xmitr() 92 | { 93 | unsigned int status; 94 | 95 | do { 96 | status = serial_in(UART_PORT, UART_USR); 97 | } while (!(status & UART_USR_Tx_FIFO_NFUL)); 98 | } 99 | 100 | void uart_handler() { 101 | uart_txfifo_available = 1; 102 | u32 value = readl(uart_base[UART_PORT] + UART_IER_REG); 103 | value &= (~IER_TBE); 104 | writel(value, uart_base[UART_PORT] + UART_IER_REG); 105 | } 106 | 107 | 108 | void uart_init(int id) 109 | { 110 | unsigned int divisor; 111 | unsigned char lcr_cache; 112 | unsigned char val; 113 | 114 | 115 | _ENABLE_CLOCK_clk_uart3_apb_; 116 | _ENABLE_CLOCK_clk_uart3_core_; 117 | 118 | _ASSERT_RESET_rstgen_rstn_uart3_apb_; 119 | _ASSERT_RESET_rstgen_rstn_uart3_core_; 120 | _CLEAR_RESET_rstgen_rstn_uart3_core_; 121 | _CLEAR_RESET_rstgen_rstn_uart3_apb_; 122 | SET_GPIO_14_dout_uart3_pad_sout; 123 | //SET_GPIO_6_doen_uart0_pad_sout; 124 | SET_GPIO_14_doen_LOW; 125 | SET_GPIO_13_doen_HIGH; 126 | SET_GPIO_uart3_pad_sin(13); 127 | 128 | 129 | divisor = (UART_CLK / 9600) >> 4; 130 | 131 | lcr_cache = readl(uart_base[id] + UART_LCR_REG); 132 | writel((LCR_DLAB | lcr_cache), uart_base[id] + UART_LCR_REG); 133 | // writel(0, uart_base[id] + REG_MCR); 134 | writel((unsigned char)(divisor & 0xff), uart_base[id] + UART_BRDL_REG); 135 | writel((unsigned char)((divisor >> 8) & 0xff), uart_base[id] + UART_BRDH_REG); 136 | 137 | /* restore the DLAB to access the baud rate divisor registers */ 138 | writel(lcr_cache, uart_base[id] + UART_LCR_REG); 139 | 140 | /* 8 data bits, 1 stop bit, no parity, clear DLAB */ 141 | writel((LCR_CS8 | LCR_1_STB | LCR_PDIS), uart_base[id] + UART_LCR_REG); 142 | writel(0, uart_base[id] + UART_MDC_REG); 143 | 144 | /* 145 | * Program FIFO: enabled, mode 0 (set for compatibility with quark), 146 | * generate the interrupt at 8th byte 147 | * Clear TX and RX FIFO 148 | */ 149 | writel((FCR_FIFO | FCR_MODE1 | /*FCR_FIFO_1*/FCR_FIFO_8 | FCR_RCVRCLR | FCR_XMITCLR), uart_base[id] + UART_FCR_REG); 150 | 151 | } 152 | 153 | int _putc(char c) { 154 | int timecnt = 0; 155 | int ret = 0; 156 | 157 | do 158 | { 159 | //if(timecnt > 10000) 160 | // return -1; 161 | //timecnt++; 162 | }while((readl((uart_base[UART_PORT] + UART_LSR_REG)) & LSR_THRE) == 0); 163 | 164 | writel(c, uart_base[UART_PORT] + UART_THR_REG); 165 | 166 | 167 | return 0; 168 | } 169 | 170 | void rlSendString(char *s) 171 | { 172 | while (*s){ 173 | _putc(*s++); 174 | } 175 | } 176 | 177 | static void sys_out_char(const char c) 178 | { 179 | _putc( c); 180 | } 181 | int CtrlBreak( void ) 182 | { 183 | int retflag; 184 | 185 | do{ 186 | retflag = serial_getc( ); 187 | if( retflag == 0x03 ){ 188 | break; 189 | } 190 | }while( retflag ); 191 | return retflag; 192 | } 193 | int serial_getc() 194 | { 195 | unsigned int status; 196 | 197 | status = serial_in(UART_PORT, REG_LSR); 198 | while (!(status & (1 << 0))) 199 | status = serial_in(UART_PORT, REG_LSR); 200 | 201 | status = serial_in(UART_PORT, REG_RDR); 202 | return status; 203 | } 204 | 205 | void serial_gets(char *pstr) 206 | { 207 | unsigned char c; 208 | unsigned char *pstrorg; 209 | 210 | pstrorg = (unsigned char *) pstr; 211 | again: 212 | 213 | while ((c = serial_getc()) != '\r') 214 | { 215 | if (c == '\b'){ 216 | if ((int) pstrorg < (int) pstr){ 217 | rlSendString("\b \b"); 218 | pstr--; 219 | } 220 | }else{ 221 | *pstr++ = c; 222 | sys_out_char(c); 223 | } 224 | } 225 | 226 | *pstr = '\0'; 227 | 228 | rlSendString("\r\n"); 229 | 230 | } 231 | 232 | int _inbyte(unsigned short timeout) // msec timeout 233 | { 234 | unsigned int c; 235 | unsigned int delay = timeout*20; 236 | 237 | while (!(serial_in(UART_PORT, REG_LSR) & LSR_RXRDY)) { 238 | udelay(50); 239 | if (timeout && (--delay == 0)) { 240 | return -1; 241 | } 242 | } 243 | c = serial_in(UART_PORT, REG_RDR); 244 | return c; 245 | } 246 | 247 | void _outbyte(int c) 248 | { 249 | while(!(serial_in(UART_PORT, REG_LSR) & LSR_TEMT)) 250 | ; 251 | 252 | serial_out(UART_PORT, REG_THR, c); 253 | } 254 | 255 | void _puts(const char * s) { 256 | while (*s != '\0'){ 257 | _putc(*s++); 258 | } 259 | } 260 | int __serial_tstc() 261 | { 262 | return ((serial_in(UART_PORT, REG_LSR)) & (1 << 0)); 263 | } 264 | int serial_tstc() 265 | { 266 | return __serial_tstc(); 267 | } 268 | void print_ubyte_hex(unsigned char bval) 269 | { 270 | static const char digits[16] = "0123456789ABCDEF"; 271 | char tmp[2]; 272 | int dig=0; 273 | 274 | dig = ((bval&0xf0)>>4); 275 | tmp[0] = digits[dig]; 276 | dig = (bval&0x0f); 277 | tmp[1] = digits[dig]; 278 | _putc(tmp[0]); 279 | _putc(tmp[1]); 280 | } 281 | int serial_nowait_getc() 282 | { 283 | unsigned int status; 284 | 285 | status = serial_in(UART_PORT, REG_LSR); 286 | if (!(status & (1 << 0))) { 287 | status = 0;//NO_POLL_CHAR; 288 | goto out; 289 | } 290 | status = serial_in(UART_PORT, REG_RDR); 291 | out: 292 | return status; 293 | } 294 | 295 | void sys_itoa(int value, char* string, unsigned char radix) 296 | { 297 | int i; 298 | int count = 0; 299 | unsigned long temp; 300 | unsigned long res; 301 | char ch[512]; 302 | 303 | if (radix == 10 && value < 0){ 304 | ch[0] = '-';count++;temp = 0 - value; 305 | }else{ 306 | temp = value; 307 | } 308 | 309 | while (1) 310 | { 311 | res = temp % radix; 312 | temp = temp / radix; 313 | if (res < 10) 314 | ch[count++] = res + '0'; 315 | else 316 | ch[count++] = res - 10 + 'a'; 317 | if (temp == 0) 318 | break; 319 | } 320 | ch[count] = '\0'; 321 | string[0] = '\0'; 322 | for (i = 0; i < count; i++) 323 | string[count - i - 1] = ch[i]; 324 | 325 | string[count] = '\0'; 326 | } 327 | static void sys_console_out(const char* buf, unsigned int nbytes) 328 | { 329 | while (nbytes--) 330 | sys_out_char(*buf++); 331 | } 332 | -------------------------------------------------------------------------------- /src/driver/uart/uart.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | /** 3 | ****************************************************************************** 4 | * @file uart.h 5 | * @author StarFive Technology 6 | * @version V1.0 7 | * @date 07/24/2020 8 | * @brief 9 | ****************************************************************************** 10 | * @copy 11 | * 12 | * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS 13 | * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE 14 | * TIME. AS A RESULT, STARFIVE SHALL NOT BE HELD LIABLE FOR ANY 15 | * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING 16 | * FROM THE CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE 17 | * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. 18 | * 19 | * COPYRIGHT 2020 Shanghai StarFive Technology Co., Ltd. 20 | */ 21 | 22 | 23 | #ifndef _UART_H 24 | #define _UART_H 25 | #include 26 | 27 | #define UART_REG_ADDR_INTERVAL 4 28 | #define REG_THR 0x00 /* Transmitter holding reg. */ 29 | #define REG_RDR 0x00 /* Receiver data reg. */ 30 | #define REG_BRDL 0x00 /* Baud rate divisor (LSB) */ 31 | #define REG_BRDH 0x01 /* Baud rate divisor (MSB) */ 32 | #define REG_IER 0x01 /* Interrupt enable reg. */ 33 | #define REG_IIR 0x02 /* Interrupt ID reg. */ 34 | #define REG_FCR 0x02 /* FIFO control reg. */ 35 | #define REG_LCR 0x03 /* Line control reg. */ 36 | #define REG_MDC 0x04 /* Modem control reg. */ 37 | #define REG_LSR 0x05 /* Line status reg. */ 38 | #define REG_MSR 0x06 /* Modem status reg. */ 39 | #define REG_DLF 0xC0 /* Divisor Latch Fraction */ 40 | 41 | 42 | 43 | #define UART_USR 31 44 | #define UART_USR_BUSY (1 << 0) /* UART is busy (1) */ 45 | #define UART_USR_Tx_FIFO_NFUL (1 << 1) /* Tx FIFO is not full (1) */ 46 | #define UART_USR_Tx_FIFO_NEMP (1 << 2) /* Tx FIFO is empty (1) */ 47 | #define UART_USR_Rx_FIFO_NHFL (1 << 3) /* Rx FIFO is not empty (1) */ 48 | #define UART_USR_Rx_FIFO_NFUL (1 << 4) /* Rx FIFO is full (1) */ 49 | 50 | 51 | /* equates for interrupt enable register */ 52 | 53 | #define IER_RXRDY 0x01 /* receiver data ready */ 54 | #define IER_TBE 0x02 /* transmit bit enable */ 55 | #define IER_LSR 0x04 /* line status interrupts */ 56 | #define IER_MSI 0x08 /* modem status interrupts */ 57 | 58 | 59 | /* constants for line control register */ 60 | 61 | #define LCR_CS5 0x00 /* 5 bits data size */ 62 | #define LCR_CS6 0x01 /* 6 bits data size */ 63 | #define LCR_CS7 0x02 /* 7 bits data size */ 64 | #define LCR_CS8 0x03 /* 8 bits data size */ 65 | #define LCR_2_STB 0x04 /* 2 stop bits */ 66 | #define LCR_1_STB 0x00 /* 1 stop bit */ 67 | #define LCR_PEN 0x08 /* parity enable */ 68 | #define LCR_PDIS 0x00 /* parity disable */ 69 | #define LCR_EPS 0x10 /* even parity select */ 70 | #define LCR_SP 0x20 /* stick parity select */ 71 | #define LCR_SBRK 0x40 /* break control bit */ 72 | #define LCR_DLAB 0x80 /* divisor latch access enable */ 73 | 74 | /* constants for line status register */ 75 | 76 | #define LSR_RXRDY 0x01 /* receiver data available */ 77 | #define LSR_OE 0x02 /* overrun error */ 78 | #define LSR_PE 0x04 /* parity error */ 79 | #define LSR_FE 0x08 /* framing error */ 80 | #define LSR_BI 0x10 /* break interrupt */ 81 | #define LSR_EOB_MASK 0x1E /* Error or Break mask */ 82 | #define LSR_THRE 0x20 /* transmit holding register empty */ 83 | #define LSR_TEMT 0x40 /* transmitter empty */ 84 | 85 | /* equates for FIFO control register */ 86 | 87 | #define FCR_FIFO 0x01 /* enable XMIT and RCVR FIFO */ 88 | #define FCR_RCVRCLR 0x02 /* clear RCVR FIFO */ 89 | #define FCR_XMITCLR 0x04 /* clear XMIT FIFO */ 90 | 91 | /* 92 | * Per PC16550D (Literature Number: SNLS378B): 93 | * 94 | * RXRDY, Mode 0: When in the 16450 Mode (FCR0 = 0) or in 95 | * the FIFO Mode (FCR0 = 1, FCR3 = 0) and there is at least 1 96 | * character in the RCVR FIFO or RCVR holding register, the 97 | * RXRDY pin (29) will be low active. Once it is activated the 98 | * RXRDY pin will go inactive when there are no more charac- 99 | * ters in the FIFO or holding register. 100 | * 101 | * RXRDY, Mode 1: In the FIFO Mode (FCR0 = 1) when the 102 | * FCR3 = 1 and the trigger level or the timeout has been 103 | * reached, the RXRDY pin will go low active. Once it is acti- 104 | * vated it will go inactive when there are no more characters 105 | * in the FIFO or holding register. 106 | * 107 | * TXRDY, Mode 0: In the 16450 Mode (FCR0 = 0) or in the 108 | * FIFO Mode (FCR0 = 1, FCR3 = 0) and there are no charac- 109 | * ters in the XMIT FIFO or XMIT holding register, the TXRDY 110 | * pin (24) will be low active. Once it is activated the TXRDY 111 | * pin will go inactive after the first character is loaded into the 112 | * XMIT FIFO or holding register. 113 | * 114 | * TXRDY, Mode 1: In the FIFO Mode (FCR0 = 1) when 115 | * FCR3 = 1 and there are no characters in the XMIT FIFO, the 116 | * TXRDY pin will go low active. This pin will become inactive 117 | * when the XMIT FIFO is completely full. 118 | */ 119 | #define FCR_MODE0 0x00 /* set receiver in mode 0 */ 120 | #define FCR_MODE1 0x08 /* set receiver in mode 1 */ 121 | 122 | /* RCVR FIFO interrupt levels: trigger interrupt with this bytes in FIFO */ 123 | #define FCR_FIFO_1 0x00 /* 1 byte in RCVR FIFO */ 124 | #define FCR_FIFO_4 0x40 /* 4 bytes in RCVR FIFO */ 125 | #define FCR_FIFO_8 0x80 /* 8 bytes in RCVR FIFO */ 126 | #define FCR_FIFO_14 0xC0 /* 14 bytes in RCVR FIFO */ 127 | 128 | /* 129 | * UART NS16750 supports 64 bytes FIFO, which can be enabled 130 | * via the FCR register 131 | */ 132 | #define FCR_FIFO_64 0x20 /* Enable 64 bytes FIFO */ 133 | 134 | /* constants for line control register */ 135 | 136 | #define LCR_CS5 0x00 /* 5 bits data size */ 137 | #define LCR_CS6 0x01 /* 6 bits data size */ 138 | #define LCR_CS7 0x02 /* 7 bits data size */ 139 | #define LCR_CS8 0x03 /* 8 bits data size */ 140 | #define LCR_2_STB 0x04 /* 2 stop bits */ 141 | #define LCR_1_STB 0x00 /* 1 stop bit */ 142 | #define LCR_PEN 0x08 /* parity enable */ 143 | #define LCR_PDIS 0x00 /* parity disable */ 144 | #define LCR_EPS 0x10 /* even parity select */ 145 | #define LCR_SP 0x20 /* stick parity select */ 146 | #define LCR_SBRK 0x40 /* break control bit */ 147 | #define LCR_DLAB 0x80 /* divisor latch access enable */ 148 | 149 | /* constants for the modem control register */ 150 | 151 | #define MCR_DTR 0x01 /* dtr output */ 152 | #define MCR_RTS 0x02 /* rts output */ 153 | #define MCR_OUT1 0x04 /* output #1 */ 154 | #define MCR_OUT2 0x08 /* output #2 */ 155 | #define MCR_LOOP 0x10 /* loop back */ 156 | #define MCR_AFCE 0x20 /* auto flow control enable */ 157 | 158 | /* constants for line status register */ 159 | 160 | #define LSR_RXRDY 0x01 /* receiver data available */ 161 | #define LSR_OE 0x02 /* overrun error */ 162 | #define LSR_PE 0x04 /* parity error */ 163 | #define LSR_FE 0x08 /* framing error */ 164 | #define LSR_BI 0x10 /* break interrupt */ 165 | #define LSR_EOB_MASK 0x1E /* Error or Break mask */ 166 | #define LSR_THRE 0x20 /* transmit holding register empty */ 167 | #define LSR_TEMT 0x40 /* transmitter empty */ 168 | 169 | /* constants for modem status register */ 170 | 171 | #define MSR_DCTS 0x01 /* cts change */ 172 | #define MSR_DDSR 0x02 /* dsr change */ 173 | #define MSR_DRI 0x04 /* ring change */ 174 | #define MSR_DDCD 0x08 /* data carrier change */ 175 | #define MSR_CTS 0x10 /* complement of cts */ 176 | #define MSR_DSR 0x20 /* complement of dsr */ 177 | #define MSR_RI 0x40 /* complement of ring signal */ 178 | #define MSR_DCD 0x80 /* complement of dcd */ 179 | 180 | #define UART_THR_REG (REG_THR * UART_REG_ADDR_INTERVAL) 181 | #define UART_RDR_REG (REG_RDR * UART_REG_ADDR_INTERVAL) 182 | #define UART_BRDL_REG (REG_BRDL * UART_REG_ADDR_INTERVAL) 183 | #define UART_BRDH_REG (REG_BRDH * UART_REG_ADDR_INTERVAL) 184 | #define UART_IER_REG (REG_IER * UART_REG_ADDR_INTERVAL) 185 | #define UART_IIR_REG (REG_IIR * UART_REG_ADDR_INTERVAL) 186 | #define UART_FCR_REG (REG_FCR * UART_REG_ADDR_INTERVAL) 187 | #define UART_LCR_REG (REG_LCR * UART_REG_ADDR_INTERVAL) 188 | #define UART_MDC_REG (REG_MDC * UART_REG_ADDR_INTERVAL) 189 | #define UART_LSR_REG (REG_LSR * UART_REG_ADDR_INTERVAL) 190 | #define UART_MSR_REG (REG_MSR * UART_REG_ADDR_INTERVAL) 191 | 192 | 193 | extern void uart_init(); 194 | extern int _putc(char c); 195 | 196 | extern void rlSendString(char *s); 197 | extern int serial_getc(); 198 | extern int CtrlBreak( void ); 199 | extern int serial_nowait_getc(); 200 | extern void print_ubyte_hex(unsigned char bval); 201 | 202 | #endif // _UART_H 203 | -------------------------------------------------------------------------------- /src/driver/xmodem/crc16.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001-2019 Georges Menie (www.menie.org) 3 | * All rights reserved. 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the University of California, Berkeley nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "crc16.h" 29 | 30 | /* CRC16 implementation acording to CCITT standards */ 31 | 32 | static const unsigned short crc16tab[256]= { 33 | 0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7, 34 | 0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef, 35 | 0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6, 36 | 0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de, 37 | 0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485, 38 | 0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d, 39 | 0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4, 40 | 0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc, 41 | 0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823, 42 | 0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b, 43 | 0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12, 44 | 0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a, 45 | 0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41, 46 | 0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49, 47 | 0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70, 48 | 0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78, 49 | 0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f, 50 | 0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067, 51 | 0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e, 52 | 0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256, 53 | 0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d, 54 | 0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405, 55 | 0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c, 56 | 0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634, 57 | 0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab, 58 | 0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3, 59 | 0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a, 60 | 0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92, 61 | 0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9, 62 | 0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1, 63 | 0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8, 64 | 0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0 65 | }; 66 | 67 | unsigned short crc16_ccitt(const void *buf, int len) 68 | { 69 | register int counter; 70 | register unsigned short crc = 0; 71 | for( counter = 0; counter < len; counter++) 72 | crc = (crc<<8) ^ crc16tab[((crc>>8) ^ *(char *)buf++)&0x00FF]; 73 | return crc; 74 | } 75 | -------------------------------------------------------------------------------- /src/driver/xmodem/crc16.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001-2019 Georges Menie (www.menie.org) 3 | * All rights reserved. 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the University of California, Berkeley nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef _CRC16_H_ 29 | #define _CRC16_H_ 30 | 31 | unsigned short crc16_ccitt(const void *buf, int len); 32 | 33 | #endif /* _CRC16_H_ */ 34 | -------------------------------------------------------------------------------- /src/driver/xmodem/xmodem.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001-2019 Georges Menie (www.menie.org) 3 | * All rights reserved. 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the University of California, Berkeley nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | /* this code needs standard functions memcpy() and memset() 29 | and input/output functions _inbyte() and _outbyte(). 30 | 31 | the prototypes of the input/output functions are: 32 | int _inbyte(unsigned short timeout); // msec timeout 33 | void _outbyte(int c); 34 | 35 | */ 36 | #include "crc16.h" 37 | #include 38 | #include 39 | 40 | #define SOH 0x01 41 | #define STX 0x02 42 | #define EOT 0x04 43 | #define ACK 0x06 44 | #define NAK 0x15 45 | #define CAN 0x18 46 | #define CTRLZ 0x1A 47 | 48 | #define DLY_1S 1000 49 | #define MAXRETRANS 1000 50 | 51 | static int check(int crc, const unsigned char *buf, int sz) 52 | { 53 | if (crc) { 54 | unsigned short crc = crc16_ccitt(buf, sz); 55 | unsigned short tcrc = (buf[sz]<<8)+buf[sz+1]; 56 | if (crc == tcrc) 57 | return 1; 58 | } 59 | else { 60 | int i; 61 | unsigned char cks = 0; 62 | for (i = 0; i < sz; ++i) { 63 | cks += buf[i]; 64 | } 65 | if (cks == buf[sz]) 66 | return 1; 67 | } 68 | 69 | return 0; 70 | } 71 | 72 | static void flushinput(void) 73 | { 74 | while (_inbyte(((DLY_1S)*3)>>1) >= 0) 75 | ; 76 | } 77 | 78 | int xmodemReceive(unsigned char *dest, int destsz) 79 | { 80 | unsigned char xbuff[1030]; /* 1024 for XModem 1k + 3 head chars + 2 crc + nul */ 81 | unsigned char *p; 82 | int bufsz, crc = 0; 83 | unsigned char trychar = 'C'; 84 | unsigned char packetno = 1; 85 | int i, c, len = 0; 86 | int retry, retrans = MAXRETRANS; 87 | 88 | for(;;) { 89 | for( retry = 0; retry < MAXRETRANS; ++retry) { 90 | if (trychar) _outbyte(trychar); 91 | if ((c = _inbyte((DLY_1S))) >= 0) { 92 | switch (c) { 93 | case SOH: 94 | bufsz = 128; 95 | goto start_recv; 96 | case STX: 97 | bufsz = 1024; 98 | goto start_recv; 99 | case EOT: 100 | flushinput(); 101 | _outbyte(ACK); 102 | return len; /* normal end */ 103 | case CAN: 104 | if ((c = _inbyte(DLY_1S)) == CAN) { 105 | flushinput(); 106 | _outbyte(ACK); 107 | return -1; /* canceled by remote */ 108 | } 109 | break; 110 | default: 111 | break; 112 | } 113 | } 114 | } 115 | if (trychar == 'C') { trychar = NAK; continue; } 116 | flushinput(); 117 | _outbyte(CAN); 118 | _outbyte(CAN); 119 | _outbyte(CAN); 120 | return -2; /* sync error */ 121 | 122 | start_recv: 123 | if (trychar == 'C') crc = 1; 124 | trychar = 0; 125 | p = xbuff; 126 | *p++ = c; 127 | for (i = 0; i < (bufsz+(crc?1:0)+3); ++i) { 128 | if ((c = _inbyte(DLY_1S)) < 0) goto reject; 129 | *p++ = c; 130 | } 131 | 132 | if (xbuff[1] == (unsigned char)(~xbuff[2]) && 133 | (xbuff[1] == packetno || xbuff[1] == (unsigned char)packetno-1) && 134 | check(crc, &xbuff[3], bufsz)) { 135 | if (xbuff[1] == packetno) { 136 | // register int count = destsz - len; 137 | // if (count > bufsz) count = bufsz; 138 | if (bufsz > 0) { 139 | sys_memcpy (&dest[len], &xbuff[3], bufsz); 140 | len += bufsz; 141 | } 142 | ++packetno; 143 | retrans = MAXRETRANS+1; 144 | } 145 | if (--retrans <= 0) { 146 | flushinput(); 147 | _outbyte(CAN); 148 | _outbyte(CAN); 149 | _outbyte(CAN); 150 | return -3; /* too many retry error */ 151 | } 152 | _outbyte(ACK); 153 | continue; 154 | } 155 | reject: 156 | flushinput(); 157 | _outbyte(NAK); 158 | } 159 | } 160 | --------------------------------------------------------------------------------