├── .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 |
--------------------------------------------------------------------------------