├── .gitignore ├── LICENSE ├── Makefile ├── Makefile.build ├── README.md ├── src ├── Makefile ├── Makefile.target ├── common │ ├── cache.S │ ├── common.mk │ └── crc32.c ├── include │ ├── addrspace.h │ ├── asm.h │ ├── bitops.h │ ├── byteorder.h │ ├── cache.h │ ├── compiler.h │ ├── console.h │ ├── crc32.h │ ├── div64.h │ ├── errno.h │ ├── genfuncs.h │ ├── lshr64.h │ ├── lzma.h │ ├── malloc.h │ ├── mipscmregs.h │ ├── mipsregs.h │ ├── mmio.h │ ├── ns16550.h │ ├── spi-nand-load.h │ ├── spi-nand.h │ ├── stage2.h │ ├── stage3.h │ ├── stdarg.h │ ├── stdbool.h │ ├── stddef.h │ ├── string.h │ ├── timer.h │ └── types.h ├── libc │ ├── libc.mk │ ├── memcmp.c │ ├── memcpy.c │ ├── memset.c │ └── strlen.c ├── loader.lds.S ├── mt7621 │ ├── include │ │ ├── config.h │ │ ├── cps.h │ │ ├── mt7621_ddr_param.h │ │ ├── mt7621_regs.h │ │ ├── serial.h │ │ ├── spi.h │ │ └── target.h │ ├── serial.c │ ├── spi.c │ ├── stage1 │ │ ├── build.mk │ │ ├── entry.S │ │ └── target.c │ ├── stage2 │ │ ├── build.mk │ │ ├── cps.c │ │ ├── dramc │ │ │ ├── .gitignore │ │ │ ├── dramc.S │ │ │ ├── mt7621_stage_sram.bin │ │ │ └── mt7621_stage_sram_noprint.bin │ │ ├── entry.S │ │ └── target.c │ └── target.mk ├── stage1 │ ├── console.c │ ├── main.c │ ├── spi-nand.c │ ├── stage.mk │ └── timer.c └── stage2 │ ├── console.c │ ├── div64.c │ ├── lshr64.c │ ├── lzma │ ├── LzmaDec.c │ ├── LzmaDec.h │ ├── Types.h │ └── lzma.c │ ├── main.c │ ├── malloc.c │ ├── memsize.c │ ├── printf.c │ ├── spi-nand-load.c │ ├── stage.mk │ └── timer.c ├── toolchain └── mipsel32r2-gcc_7.2.0-uClibc-ng_1.0.27-Win64.tar.xz └── tools ├── Makefile ├── Makefile.host └── padutil.c /.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | *.o 3 | *.d 4 | *.dep 5 | *.exe 6 | *.bin 7 | *.elf -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 Weijie Gao . All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | # Copyright (C) 2020 Weijie Gao 3 | 4 | TOPDIR := $(CURDIR) 5 | export TOPDIR 6 | 7 | TARGET_SRCDIR := $(TOPDIR)/src 8 | TOOLS_SRCDIR := $(TOPDIR)/tools 9 | TOP_BUILD_DIR := $(TOPDIR)/build 10 | 11 | TOOLS_DIR := $(TOP_BUILD_DIR)/tools 12 | export TOOLS_DIR 13 | 14 | all: tools 15 | $(MAKE) -C $(TARGET_SRCDIR) all SRCDIR=$(TARGET_SRCDIR) OUTDIR=$(TOP_BUILD_DIR) TARGET_NAME=target 16 | 17 | tools: 18 | $(MAKE) -C $(TOOLS_SRCDIR) all SRCDIR=$(TOOLS_SRCDIR) OUTDIR=$(TOOLS_DIR) 19 | 20 | clean: 21 | rm -rf $(TOP_BUILD_DIR) 22 | 23 | .PHONY: tools clean 24 | -------------------------------------------------------------------------------- /Makefile.build: -------------------------------------------------------------------------------- 1 | 2 | PHONY := FORCE 3 | 4 | squote := ' 5 | 6 | escsq = $(subst $(squote),'\$(squote)',$1) 7 | 8 | make-cmd = $(call escsq,$(subst \#,\\\#,$(subst $$,$$$$,$(cmd_$(1))))) 9 | 10 | arg-check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \ 11 | $(filter-out $(cmd_$@), $(cmd_$(1)))) 12 | 13 | any-prereq = $(filter-out $(PHONY),$?) $(filter-out $(PHONY) $(wildcard $^),$^) 14 | 15 | always = $(if $(strip $(any-prereq)), $(cmd_$(1))) 16 | 17 | if_changed = $(if $(strip $(any-prereq) $(arg-check)), \ 18 | $(cmd_$(1)) && \ 19 | printf '%s\n\n' 'cmd_$@ := $(make-cmd)' > $@.dep \ 20 | ) 21 | 22 | if_changed_dep = $(if $(strip $(any-prereq) $(arg-check)), \ 23 | $(cmd_$(1)) && \ 24 | printf '%s\n\n' 'cmd_$@ := $(make-cmd)' > $@.dep && \ 25 | cat '$(@:.o=.d)' >> $@.dep \ 26 | ) 27 | 28 | .PHONY: $(PHONY) 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | This s a standalone program / bootloader used for booting directly from Micron SPI-NAND on MediaTek MT7621 platform. 4 | 5 | # Prerequisites 6 | - The bootstrap of MT7621 board is set to "Boot from SPI 3-byte address". 7 | - A Micron SPI-NAND flash chip with "SPI NOR Read Configuration" enabled. 8 | 9 | # Toolchain 10 | Prebuilt toolchain for Windows 64-bit platform is provided (use it with MSYS2). 11 | You can also build your own toolchain, but remember to enable LTO (--enable-lto) 12 | 13 | # Binary structure 14 | 15 | ## 1st stage loader 16 | The 1st stage loader only occupies the first page of the SPI-NAND flash. 17 | It's used to setup a basic environment to load 2nd stage loader into locked L2 cache and transfer control to 2nd stage loader. 18 | The size of 1st stage loader must not be greater than the page size of the SPI-NAND flash (i.e. 2KB or 4KB). 19 | 20 | ## 2nd stage loader 21 | The 2nd stage loader runs in locked L2 cache and will do all initializations that 1st stage loader can not do (CPU/DDR initialization & cache reset). 22 | The 2nd stage loader then loads 3rd stage loader into memory and transfer control. 23 | The size of 2nd stage loader must not be greater than 192KB (3/4 of 256KB L2 cache). 24 | 25 | ## 3rd stage loader 26 | The 3rd stage loader will not be provided by this code. 27 | You can use you customized bootloader (Breed, U-Boot or whatever) to act as the 3rd stage loader. 28 | The 3rd stage loader must have a image header to describe its size/load address/entry point/compression. 29 | Accepted headers are: Breed private header and U-Boot legacy image header. 30 | Accepted compression is LZMA. 31 | 32 | ## Output image 33 | The 1st and 2nd stage loaders will be concatenate in to one binary file. 34 | 35 | # Compilation 36 | `make CROSS_COMPILE=` 37 | 38 | Optional make parameters (passed to make commandline): 39 | 40 | | Name | Arg type | Default value | Description | 41 | | -------- | ----- | - | ---- | 42 | | BAUDRATE | int | 115200 | Baudrate of the UART console output | 43 | | _4K_PAGE_SUPPORT | bool (1 for true) | | Build for SPI-NAND with 4KB page size & 256KB block size | 44 | | STAGE3_OFFSET | hex | | The offset of 3rd-stage image in NAND | 45 | | STAGE3_PAYLOAD | string | | Automatically concatenate 3rd-stage image after final output image | 46 | 47 | If STAGE3_PAYLOAD is specified, STAGE3_OFFSET will be ignored, and the offset of 3rd stage will be set to the size of final output image 48 | 49 | ## Final output image 50 | build/target/output-loader.bin 51 | 52 | # CPU/DDR configuration 53 | Please edit src/mt7621/stage2/entry.S 54 | 55 | ``` 56 | EXPORT(_dramc_cpu_freq) 57 | .word 880 58 | EXPORT(_dramc_ddr_freq) 59 | .word 1 60 | 61 | EXPORT(_dramc_ddr2_act_sel) 62 | .word 2 63 | EXPORT(_dramc_ddr3_act_sel) 64 | .word 2 65 | ``` 66 | 67 | ## CPU frequency 68 | As-is, 880 stands for 880MHz, step is 20MHz 69 | 70 | ## DDR frequency 71 | 1 - 1200MHz 72 | 2 - 1066MHz (actual 1040MHz) 73 | 3 - 800MHz 74 | 4 - 400MHz 75 | 76 | ## DDR2 AC timing selection 77 | 0 - 512Mb (Generic 64MB) 78 | 1 - 512Mb (Optimized for W9751G6KB_A02, DDR frequency is 1066MHz) 79 | 2 - 1024Mb (Generic 128MB) 80 | 3 - 1024Mb (Optimized for W971GG6KB25, DDR frequency is 800MHz) 81 | 4 - 1024Mb (Optimized for W971GG6KB18, DDR frequency is 1066MHz) 82 | 83 | ## DDR3 AC timing selection 84 | 0 - 1024Mb (Generic 128MB) 85 | 1 - 1024Mb (Optimized for MT7621DA, integrated DDR KGD) 86 | 2 - 2048Mb (Generic 256MB) 87 | 3 - 4096Mb (Generic 512MB) 88 | 89 | # License 90 | BSD-3-Clause 91 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | # Copyright (C) 2020 Weijie Gao 3 | 4 | include $(TOPDIR)/Makefile.build 5 | 6 | BAUDRATE ?= 115200 7 | export BAUDRATE 8 | 9 | ifeq ($(_4K_PAGE_SUPPORT),1) 10 | PAGESIZE := 0x1000 11 | BLOCKSIZE := 0x40000 12 | else 13 | PAGESIZE := 0x800 14 | BLOCKSIZE := 0x20000 15 | endif 16 | 17 | export PAGESIZE BLOCKSIZE 18 | 19 | BIN_OUT := $(OUTDIR)/$(TARGET_NAME)/output-loader.bin 20 | 21 | DEPS := $(addsuffix .dep,$(BIN_OUT)) 22 | 23 | STAGES := stage1 stage2 24 | 25 | all: $(BIN_OUT) 26 | 27 | cmd_cat_final = cat $(OUTDIR)/$(TARGET_NAME)/stage1/stage1-pad.bin $(OUTDIR)/$(TARGET_NAME)/stage2/stage2-pad.bin $(STAGE3_PAYLOAD) > $@ 28 | 29 | $(BIN_OUT): $(STAGES) FORCE 30 | $(call if_changed,cat_final) 31 | 32 | $(STAGES): 33 | $(MAKE) -f Makefile.target all STAGE=$@ TARGET=mt7621 SRCDIR=$(SRCDIR) OUTDIR=$(OUTDIR)/$(TARGET_NAME)/$@ 34 | 35 | .PHONY: $(STAGES) 36 | 37 | -include $(DEPS) 38 | -------------------------------------------------------------------------------- /src/Makefile.target: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | # Copyright (C) 2020 Weijie Gao 3 | 4 | include $(TOPDIR)/Makefile.build 5 | 6 | LDS := loader.lds 7 | 8 | CFLAGS := -Os -Wall -ffunction-sections -fdata-sections -nostdinc -fno-builtin -ggdb -gdwarf-4 9 | CPPFLAGS := -Iinclude -DBAUDRATE=$(BAUDRATE) -DSTAGE=$(STAGE:stage%=%) 10 | CPPLDSFLAGS := -Umips -DSTAGE$(STAGE:stage%=%) -DPAGESIZE=$(PAGESIZE) 11 | AFLAGS := -D__ASSEMBLY__ 12 | LDFLAGS := -Wl,--gc-sections -Wl,-Map,$(OUTDIR)/$(STAGE).map -nostdlib 13 | OBJFLAGS := -O binary --gap-fill=0xff 14 | 15 | include $(STAGE)/stage.mk 16 | include $(TARGET)/target.mk 17 | include libc/libc.mk 18 | include common/common.mk 19 | 20 | CC := $(CROSS_COMPILE)gcc 21 | OBJCOPY := $(CROSS_COMPILE)objcopy 22 | 23 | COBJS_OUT := $(addprefix $(OUTDIR)/,$(COBJS)) 24 | SOBJS_OUT := $(addprefix $(OUTDIR)/,$(SOBJS)) 25 | HEAD_OUT := $(addprefix $(OUTDIR)/,$(HEAD)) 26 | LDS_OUT := $(addprefix $(OUTDIR)/,$(LDS)) 27 | ELF_OUT := $(OUTDIR)/$(STAGE).elf 28 | BIN_OUT += $(OUTDIR)/$(STAGE).bin 29 | 30 | LDFLAGS += -Wl,-T,$(LDS_OUT) 31 | 32 | DEPS := $(addsuffix .dep,$(COBJS_OUT) $(SOBJS_OUT) $(HEAD_OUT) $(ELF_OUT) $(BIN_OUT)) 33 | 34 | .SECONDEXPANSION: 35 | 36 | all: $(OUTDIR)/$(STAGE).bin 37 | 38 | $(OUTDIR)/$(STAGE).bin: $(ELF_OUT) 39 | $(OBJCOPY) $(OBJFLAGS) $^ $@ 40 | 41 | cmd_link = $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(HEAD_OUT) -Wl,--start-group $(SOBJS_OUT) $(COBJS_OUT) -Wl,--end-group 42 | 43 | $(ELF_OUT): $(HEAD_OUT) $(SOBJS_OUT) $(COBJS_OUT) $(LDS_OUT) FORCE 44 | $(call if_changed,link) 45 | 46 | cmd_lds = $(CC) $(CPPLDSFLAGS) -MD -E -P -C -o $@ $< 47 | 48 | $(LDS_OUT): $(LDS).S FORCE 49 | $(call if_changed,lds) 50 | 51 | cmd_compile = $(CC) $(CFLAGS) $(CPPFLAGS) -MD -c -o $@ $< 52 | 53 | $(COBJS_OUT): $(OUTDIR)/%.o: $(SRCDIR)/%.c FORCE | $$(@D)/ 54 | $(call if_changed_dep,compile) 55 | 56 | cmd_asm = $(CC) $(CFLAGS) $(CPPFLAGS) $(AFLAGS) -MD -c -o $@ $< 57 | 58 | $(HEAD_OUT) $(SOBJS_OUT): $(OUTDIR)/%.o: $(SRCDIR)/%.S FORCE | $$(@D)/ 59 | $(call if_changed_dep,asm) 60 | 61 | .PRECIOUS: $(OUTDIR)/ $(OUTDIR)%/ 62 | 63 | $(OUTDIR)/: 64 | mkdir -p $@ 65 | 66 | $(OUTDIR)%/: 67 | mkdir -p $@ 68 | 69 | clean: 70 | rm -f $(ELF_OUT) $(SOBJS_OUT) $(COBJS_OUT) $(HEAD_OUT) $(DEPS) $(OUTDIR)/$(STAGE).bin $(OUTDIR)/$(STAGE).map 71 | 72 | .PHONY: clean 73 | 74 | -include $(STAGE)/stage-post.mk 75 | -include $(TARGET)/target-post.mk 76 | 77 | -include $(DEPS) 78 | -------------------------------------------------------------------------------- /src/common/cache.S: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause */ 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Generic cache manipluation for MIPS platform 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | .text 14 | .set nomips16 15 | .set noreorder 16 | 17 | #if L1_DCACHE_LINESIZE == L1_ICACHE_LINESIZE 18 | LEAFUNC(invalidate_l1_cache_range) 19 | li $v1, ~(L1_DCACHE_LINESIZE - 1) 20 | add $a1, $a1, $a0 21 | addi $a1, L1_DCACHE_LINESIZE - 1 22 | and $a0, $a0, $v1 23 | and $a1, $a1, $v1 24 | 25 | 1: 26 | cache HIT_INVALIDATE_I, 0($a0) 27 | cache HIT_INVALIDATE_D, 0($a0) 28 | addi $a0, L1_DCACHE_LINESIZE 29 | bne $a0, $a1, 1b 30 | nop 31 | 32 | jr $ra 33 | nop 34 | ENDFUNC(invalidate_l1_cache_range) 35 | 36 | LEAFUNC(flush_l1_cache_range) 37 | li $v1, ~(L1_DCACHE_LINESIZE - 1) 38 | add $a1, $a1, $a0 39 | addi $a1, L1_DCACHE_LINESIZE - 1 40 | and $a0, $a0, $v1 41 | and $a1, $a1, $v1 42 | 43 | 1: 44 | cache HIT_WRITEBACK_INV_D, 0($a0) 45 | cache HIT_INVALIDATE_I, 0($a0) 46 | addi $a0, L1_DCACHE_LINESIZE 47 | bne $a0, $a1, 1b 48 | nop 49 | 50 | jr $ra 51 | nop 52 | ENDFUNC(flush_l1_cache_range) 53 | 54 | #if L1_DCACHE_SIZE == L1_ICACHE_SIZE 55 | LEAFUNC(reset_l1_cache) 56 | move $a0, $0 57 | li $a1, L1_DCACHE_SIZE 58 | 59 | mtc0 $0, CP0_TAGLO 60 | mtc0 $0, CP0_TAGHI 61 | mtc0 $0, CP0_DTAGLO 62 | mtc0 $0, CP0_DTAGHI 63 | 64 | 1: 65 | cache INDEX_STORE_TAG_I, 0($a0) 66 | cache INDEX_STORE_TAG_D, 0($a0) 67 | addiu $a0, $a0, L1_DCACHE_LINESIZE 68 | bne $a0, $a1, 1b 69 | nop 70 | 71 | jr $ra 72 | nop 73 | ENDFUNC(reset_l1_cache) 74 | #else 75 | LEAFUNC(reset_l1_cache) 76 | mtc0 $0, CP0_TAGLO 77 | mtc0 $0, CP0_TAGHI 78 | mtc0 $0, CP0_DTAGLO 79 | mtc0 $0, CP0_DTAGHI 80 | 81 | move $a0, $0 82 | li $a1, L1_DCACHE_SIZE 83 | 1: 84 | cache INDEX_STORE_TAG_D, 0($a0) 85 | addiu $a0, $a0, L1_DCACHE_LINESIZE 86 | bne $a0, $a1, 1b 87 | nop 88 | 89 | move $a0, $0 90 | li $a1, L1_ICACHE_SIZE 91 | 1: 92 | cache INDEX_STORE_TAG_I, 0($a0) 93 | addiu $a0, $a0, L1_ICACHE_LINESIZE 94 | bne $a0, $a1, 1b 95 | nop 96 | 97 | jr $ra 98 | nop 99 | ENDFUNC(reset_l1_cache) 100 | #endif 101 | 102 | #endif /* L1_DCACHE_LINESIZE == L1_ICACHE_LINESIZE */ 103 | -------------------------------------------------------------------------------- /src/common/common.mk: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | # Copyright (C) 2020 Weijie Gao 3 | 4 | SOBJS += common/cache.o 5 | -------------------------------------------------------------------------------- /src/common/crc32.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | 3 | #include 4 | #include 5 | 6 | static uint32_t *crc_table; 7 | 8 | #define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); 9 | #define DO2(buf) DO1(buf); DO1(buf); 10 | #define DO4(buf) DO2(buf); DO2(buf); 11 | #define DO8(buf) DO4(buf); DO4(buf); 12 | 13 | uint32_t crc32(uint32_t crc, const void *buf, size_t len) 14 | { 15 | const uint8_t *ptr = (const uint8_t *) buf; 16 | 17 | crc = crc ^ 0xffffffff; 18 | 19 | while (len >= 8) { 20 | DO8(ptr); 21 | len -= 8; 22 | } 23 | 24 | while (len) { 25 | DO1(ptr); 26 | len--; 27 | } 28 | 29 | return crc ^ 0xffffffff; 30 | } 31 | 32 | void make_crc32_table(void) 33 | { 34 | uint32_t c, poly = 0; 35 | int n, k; 36 | 37 | static const uint8_t p[] = {0, 1, 2, 4, 5, 7, 8, 10, 11, 12, 16, 22, 23, 26}; 38 | 39 | crc_table = malloc(256 * sizeof(*crc_table)); 40 | 41 | /* make exclusive-or pattern from polynomial (0xedb88320) */ 42 | for (n = 0; n < sizeof(p) / sizeof(uint8_t); n++) 43 | poly |= 1 << (31 - p[n]); 44 | 45 | for (n = 0; n < 256; n++) { 46 | c = (uint8_t)n; 47 | for (k = 0; k < 8; k++) 48 | c = c & 1 ? poly ^ (c >> 1) : c >> 1; 49 | crc_table[n] = c; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/include/addrspace.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause */ 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Address space related for MIPS platform 6 | */ 7 | 8 | #ifndef _ADDRSPACE_H_ 9 | #define _ADDRSPACE_H_ 10 | 11 | #define PHYSMASK 0x1fffffff 12 | 13 | #define KSEG0BASE 0x80000000 14 | #define KSEG1BASE 0xa0000000 15 | #define KSEG2BASE 0xc0000000 16 | 17 | #define KSEG0 KSEG0BASE 18 | #define KSEG1 KSEG1BASE 19 | #define KSEG2 KSEG2BASE 20 | 21 | #define CPHYSADDR(x) ((x) & PHYSMASK) 22 | #define KSEG1ADDR(x) (CPHYSADDR(x) | KSEG1BASE) 23 | 24 | #endif /* _ADDRSPACE_H_ */ 25 | -------------------------------------------------------------------------------- /src/include/asm.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause */ 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | */ 5 | 6 | #ifndef _ASM_H_ 7 | #define _ASM_H_ 8 | 9 | #define FUNC(funcname, fgpr, framesize, rpc) \ 10 | .section .text. ## funcname, "ax", @progbits; \ 11 | .align 2; \ 12 | .globl funcname; \ 13 | .type funcname, @function; \ 14 | .ent funcname, 0; \ 15 | funcname: \ 16 | .frame fgpr, framesize, rpc 17 | 18 | #define LEAFUNC(funcname) \ 19 | FUNC(funcname, $sp, 0, $ra) 20 | 21 | #define ENTRY(funcname) \ 22 | FUNC(funcname, $sp, 0, $ra) 23 | 24 | #define ENDFUNC(funcname) \ 25 | .end funcname; \ 26 | .size funcname, . - funcname 27 | 28 | #define EXPORT(symbol) \ 29 | .globl symbol; \ 30 | symbol: 31 | 32 | #endif /* _ASM_H_ */ 33 | -------------------------------------------------------------------------------- /src/include/bitops.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause */ 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Generic bit operations 6 | */ 7 | 8 | #ifndef _BITOPS_H_ 9 | #define _BITOPS_H_ 10 | 11 | #define BITS_PER_LONG _MIPS_SZLONG 12 | 13 | #define BIT(x) (1 << (x)) 14 | 15 | #define GENMASK(h, l) \ 16 | (((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) 17 | 18 | #ifndef __ASSEMBLY__ 19 | static inline unsigned long ffs(unsigned long word) 20 | { 21 | int num = 1; 22 | 23 | if (!word) 24 | return 0; 25 | 26 | #if BITS_PER_LONG == 64 27 | if ((word & 0xffffffff) == 0) { 28 | num += 32; 29 | word >>= 32; 30 | } 31 | #endif 32 | 33 | if ((word & 0xffff) == 0) { 34 | num += 16; 35 | word >>= 16; 36 | } 37 | 38 | if ((word & 0xff) == 0) { 39 | num += 8; 40 | word >>= 8; 41 | } 42 | 43 | if ((word & 0xf) == 0) { 44 | num += 4; 45 | word >>= 4; 46 | } 47 | 48 | if ((word & 0x3) == 0) { 49 | num += 2; 50 | word >>= 2; 51 | } 52 | 53 | if ((word & 0x1) == 0) 54 | num += 1; 55 | 56 | return num; 57 | } 58 | 59 | static inline unsigned long ffs64(unsigned long long word) 60 | { 61 | #if BITS_PER_LONG == 64 62 | return ffs(word); 63 | #else 64 | if (!word) 65 | return 0; 66 | 67 | if ((word & 0xffffffff) == 0) 68 | return ffs(word >> 32) + 32; 69 | 70 | return ffs(word & 0xffffffff); 71 | #endif 72 | } 73 | #endif /* !__ASSEMBLY__ */ 74 | 75 | #endif /* _BITOPS_H_ */ 76 | -------------------------------------------------------------------------------- /src/include/byteorder.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause */ 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Generic byte swap functions 6 | */ 7 | 8 | #ifndef _BYTEORDER_H_ 9 | #define _BYTEORDER_H_ 10 | 11 | #include 12 | 13 | static inline uint32_t bswap32(uint32_t val) 14 | { 15 | return ((val & 0x000000ffUL) << 24) | 16 | ((val & 0x0000ff00UL) << 8) | 17 | ((val & 0x00ff0000UL) >> 8) | 18 | ((val & 0xff000000UL) >> 24); 19 | } 20 | 21 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 22 | #define cpu_to_be32(x) bswap32(x) 23 | #define be32_to_cpu(x) bswap32(x) 24 | #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 25 | #define cpu_to_be32(x) (x) 26 | #define be32_to_cpu(x) (x) 27 | #else 28 | #error Byte-order is not defined by the compiler! 29 | #endif 30 | 31 | #endif /* _BYTEORDER_H_ */ 32 | -------------------------------------------------------------------------------- /src/include/cache.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause */ 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Generic cache manipluation for MIPS platform 6 | */ 7 | 8 | #ifndef _CACHE_H_ 9 | #define _CACHE_H_ 10 | 11 | #ifndef __ASSEMBLY__ 12 | #include 13 | #include 14 | #endif 15 | 16 | #define INDEX_STORE_TAG_I 0x08 17 | #define INDEX_STORE_TAG_D 0x09 18 | #define INDEX_STORE_TAG_SD 0x0b 19 | #define INDEX_STORE_DATA_SD 0x0f 20 | #define HIT_INVALIDATE_I 0x10 21 | #define HIT_INVALIDATE_D 0x11 22 | #define HIT_INVALIDATE_SD 0x13 23 | #define HIT_WRITEBACK_INV_D 0x15 24 | #define HIT_WRITEBACK_INV_SD 0x17 25 | 26 | #ifndef __ASSEMBLY__ 27 | extern void __nomips16 invalidate_l1_cache_range(uintptr_t base, uint32_t size); 28 | extern void __nomips16 flush_l1_cache_range(uintptr_t base, uint32_t size); 29 | extern void __nomips16 reset_l1_cache(void); 30 | #endif 31 | 32 | #endif /* _CACHE_H_ */ 33 | -------------------------------------------------------------------------------- /src/include/compiler.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause */ 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Compiler-specific functions 6 | */ 7 | 8 | #ifndef _COMPILER_H_ 9 | #define _COMPILER_H_ 10 | 11 | #define __nomips16 __attribute__ ((nomips16)) 12 | #define __noreturn __attribute__ ((noreturn)) 13 | #define __maybe_unused __attribute__ ((unused)) 14 | 15 | #define unreachable() __builtin_unreachable() 16 | 17 | #endif /* _COMPILER_H_ */ 18 | -------------------------------------------------------------------------------- /src/include/console.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause */ 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Generic console functions 6 | */ 7 | 8 | #ifndef _CONSOLE_H_ 9 | #define _CONSOLE_H_ 10 | 11 | #include 12 | 13 | void putc(char c); 14 | void puts(const char *s); 15 | 16 | #if STAGE == 2 17 | #include 18 | 19 | int vprintf(const char *fmt, va_list args); 20 | int printf(const char *fmt, ...); 21 | #endif 22 | 23 | #endif /* _CONSOLE_H_ */ 24 | -------------------------------------------------------------------------------- /src/include/crc32.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause */ 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | */ 5 | 6 | #ifndef _CRC32_H_ 7 | #define _CRC32_H_ 8 | 9 | #include 10 | 11 | uint32_t crc32(uint32_t crc, const void *buf, size_t len); 12 | void make_crc32_table(void); 13 | 14 | #endif /* _CRC32_H_ */ 15 | -------------------------------------------------------------------------------- /src/include/div64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. 3 | * Copyright (c) 2014 Mellanox Technologies, Ltd. All rights reserved. 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice unmodified, this list of conditions, and the following 11 | * disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 | * 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 | #ifndef _DIV64_H_ 29 | #define _DIV64_H_ 30 | 31 | #include 32 | 33 | uint32_t __div64_32(uint64_t *n, uint32_t base); 34 | 35 | #endif /* _DIV64_H_ */ 36 | -------------------------------------------------------------------------------- /src/include/errno.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause */ 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Standard C library implementation 6 | */ 7 | 8 | #ifndef _ERRNO_H_ 9 | #define _ERRNO_H_ 10 | 11 | #define EPERM 1 12 | #define ENOENT 2 13 | #define ENOFILE ENOENT 14 | #define ESRCH 3 15 | #define EINTR 4 16 | #define EIO 5 17 | #define ENXIO 6 18 | #define E2BIG 7 19 | #define ENOEXEC 8 20 | #define EBADF 9 21 | #define ECHILD 10 22 | #define EAGAIN 11 23 | #define ENOMEM 12 24 | #define EACCES 13 25 | #define EFAULT 14 26 | #define EBUSY 16 27 | #define EEXIST 17 28 | #define EXDEV 18 29 | #define ENODEV 19 30 | #define ENOTDIR 20 31 | #define EISDIR 21 32 | #define EINVAL 22 33 | #define ENFILE 23 34 | #define EMFILE 24 35 | #define ENOTTY 25 36 | #define EFBIG 27 37 | #define ENOSPC 28 38 | #define ESPIPE 29 39 | #define EROFS 30 40 | #define EMLINK 31 41 | #define EPIPE 32 42 | #define EDOM 33 43 | #define ERANGE 34 44 | #define EDEADLK 36 45 | #define EDEADLOCK EDEADLK 46 | #define ENAMETOOLONG 38 47 | #define ENOLCK 39 48 | #define ENOSYS 40 49 | #define ENOTEMPTY 41 50 | #define EILSEQ 42 51 | #define EADDRINUSE 100 52 | #define EADDRNOTAVAIL 101 53 | #define EAFNOSUPPORT 102 54 | #define EALREADY 103 55 | #define EBADMSG 104 56 | #define ECANCELED 105 57 | #define ECONNABORTED 106 58 | #define ECONNREFUSED 107 59 | #define ECONNRESET 108 60 | #define EDESTADDRREQ 109 61 | #define EHOSTUNREACH 110 62 | #define EIDRM 111 63 | #define EINPROGRESS 112 64 | #define EISCONN 113 65 | #define ELOOP 114 66 | #define EMSGSIZE 115 67 | #define ENETDOWN 116 68 | #define ENETRESET 117 69 | #define ENETUNREACH 118 70 | #define ENOBUFS 119 71 | #define ENODATA 120 72 | #define ENOLINK 121 73 | #define ENOMSG 122 74 | #define ENOPROTOOPT 123 75 | #define ENOSR 124 76 | #define ENOSTR 125 77 | #define ENOTCONN 126 78 | #define ENOTRECOVERABLE 127 79 | #define ENOTSOCK 128 80 | #define ENOTSUP 129 81 | #define ENOTSUPP ENOTSUP 82 | #define EOPNOTSUPP 130 83 | #define EOVERFLOW 132 84 | #define EOWNERDEAD 133 85 | #define EPROTO 134 86 | #define EPROTONOSUPPORT 135 87 | #define EPROTOTYPE 136 88 | #define ETIME 137 89 | #define ETIMEDOUT 138 90 | #define ETXTBSY 139 91 | #define EWOULDBLOCK 140 92 | 93 | #endif /* _ERRNO_H_ */ 94 | -------------------------------------------------------------------------------- /src/include/genfuncs.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause */ 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | */ 5 | 6 | #ifndef _GENFUNCS_H_ 7 | #define _GENFUNCS_H_ 8 | 9 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) 10 | 11 | #endif /* _GENFUNCS_H_ */ 12 | -------------------------------------------------------------------------------- /src/include/lshr64.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause */ 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Implementation for 64-bit logical right shift 6 | */ 7 | 8 | #ifndef _LSHR64_H_ 9 | #define _LSHR64_H_ 10 | 11 | #include 12 | 13 | uint64_t __lshr64(uint64_t val, uint32_t sh); 14 | 15 | #endif /* _LSHR64_H_ */ 16 | -------------------------------------------------------------------------------- /src/include/lzma.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause */ 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Wrapper for LZMA decompression 6 | */ 7 | 8 | #ifndef _LZMA_H_ 9 | #define _LZMA_H_ 10 | 11 | #include 12 | 13 | int lzma_uncompress(const void *comp_data, uint32_t comp_size, 14 | void *decomp_data, uint32_t *decomp_size); 15 | 16 | #endif /* _LZMA_H_ */ 17 | -------------------------------------------------------------------------------- /src/include/malloc.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause */ 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Simple memory pool 6 | */ 7 | 8 | #ifndef _MALLOC_H_ 9 | #define _MALLOC_H_ 10 | 11 | #include 12 | 13 | void malloc_init(uintptr_t base); 14 | void *malloc(size_t size); 15 | 16 | #endif /* _MALLOC_H_ */ 17 | -------------------------------------------------------------------------------- /src/include/mipscmregs.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause */ 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Register definitions for MIPS CM/CPS 6 | */ 7 | 8 | #ifndef _MIPSCMREGS_H_ 9 | #define _MIPSCMREGS_H_ 10 | 11 | /* 12 | **************************************************************** 13 | * Global Control Registers 14 | **************************************************************** 15 | */ 16 | 17 | #define GCR_CONFIG 0x0000 18 | #define GCR_CONFIG_NUMIOCU_M 0xff00 19 | #define GCR_CONFIG_NUMIOCU_S 8 20 | #define GCR_CONFIG_PCORES_M 0xff 21 | #define GCR_CONFIG_PCORES_S 0 22 | 23 | #define GCR_BASE 0x0008 24 | #define GCR_CCA_DEF_OVERRIDE_VALUE_M 0xe0 25 | #define GCR_CCA_DEF_OVERRIDE_VALUE_S 5 26 | #define GCR_CCA_DEFAULT_OVERRIDE_ENABLE (1 << 4) 27 | #define GCR_CM_DEFAULT_TARGET_M 0x03 28 | #define GCR_CM_DEFAULT_TARGET_S 0 29 | #define GCR_CM_DEFAULT_TARGET_MEMORY 0 30 | 31 | #define GCR_BASE_UPPER 0x000c 32 | 33 | #define GCR_CONTROL 0x0010 34 | #define GCR_CONTROL_SYNCCTL 0x10000 35 | 36 | #define GCR_ACCESS 0x0020 37 | 38 | #define GCR_GIC_BASE 0x0080 39 | #define GCR_GIC_BASE_ADDR_M 0xfffe000 40 | #define GCR_GIC_BASE_ADDR_S 17 41 | #define GCR_GIC_EN 0x01 42 | 43 | #define GCR_CPC_BASE 0x0088 44 | #define GCR_CPC_BASE_ADDR_M 0xffff8000 45 | #define GCR_CPC_BASE_ADDR_S 15 46 | #define GCR_CPC_EN 0x01 47 | 48 | #define GCR_REGn_BASE(n) (0x0090 + ((n) << 4)) 49 | #define GCR_REGn_MASK(n) (0x0098 + ((n) << 4)) 50 | #define GCR_REGn_MASK_ADDRMASK_S 16 51 | #define GCR_REGn_MASK_CMTGT_IOCU0 0x2 52 | 53 | #define GCR_GIC_STATUS 0x00d0 54 | #define GCR_GIC_EX 0x01 55 | 56 | #define GCR_CPC_STATUS 0x00f0 57 | #define GCR_CPC_EX 0x01 58 | 59 | 60 | /* 61 | **************************************************************** 62 | * Global Interrupt Controller Registers 63 | **************************************************************** 64 | */ 65 | 66 | #define GIC_SH_CONFIG 0x0000 67 | #define GIC_SH_NUMINTERRUPTS_M 0xff0000 68 | #define GIC_SH_NUMINTERRUPTS_S 16 69 | 70 | #define GIC_SH_POL_BASE 0x0100 71 | #define GIC_SH_TRIG_BASE 0x0180 72 | #define GIC_SH_RMASK_BASE 0x0300 73 | #define GIC_SH_SMASK_BASE 0x0380 74 | #define GIC_SH_MASK_BASE 0x0400 75 | #define GIC_SH_PEND_BASE 0x0480 76 | 77 | #define GIC_SH_REG(r, i) ((r) + ((i) / 32) * 4) 78 | #define GIC_SH_BIT(i) ((i) % 32) 79 | 80 | #define GIC_SH_MAP_PIN_BASE 0x0500 81 | #define GIC_SH_MAP_PIN(i) (GIC_SH_MAP_PIN_BASE + (i) * 4) 82 | #define GIC_MAP_TO_PIN 0x80000000 83 | #define GIC_MAP_PIN_M 0x3f 84 | #define GIC_MAP_PIN_S 0 85 | 86 | #define GIC_SH_MAP_VPE_BASE 0x2000 87 | #define GIC_SH_MAP_VPE(i) (GIC_SH_MAP_VPE_BASE + (i) * 0x20) 88 | 89 | #endif /* _MIPSCMREGS_H_ */ 90 | -------------------------------------------------------------------------------- /src/include/mipsregs.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause */ 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Generic MIPS Co-processor registers 6 | */ 7 | 8 | #ifndef _MIPSREGS_H_ 9 | #define _MIPSREGS_H_ 10 | 11 | #define CP0_COUNT $9 12 | #define CP0_COMPARE $11 13 | #define CP0_STATUS $12 14 | #define CP0_CAUSE $13 15 | #define CP0_EBASE $15, 1 16 | #define CP0_CMGCRBASE $15, 3 17 | #define CP0_CONFIG $16 18 | #define CP0_CONFIG2 $16, 2 19 | #define CP0_WATCHLO $18 20 | #define CP0_WATCHHI $19 21 | #define CP0_ECC $26 22 | #define CP0_TAGLO $28 23 | #define CP0_DTAGLO $28, 2 24 | #define CP0_STAGLO $28, 4 25 | #define CP0_SDATALO $28, 5 26 | #define CP0_TAGHI $29 27 | #define CP0_DTAGHI $29, 2 28 | #define CP0_SDATAHI $29, 5 29 | 30 | /* CP0_STATUS fields */ 31 | #define ST0_IMPL (3 << 16) 32 | #define ST0_BEV 0x00400000 33 | #define ST0_ERL 0x00000004 34 | 35 | /* CP0_EBASE fields */ 36 | #define EBASE_CPUNUM 0x3ff 37 | 38 | /* CP0_CONFIG fields */ 39 | #define CONF_CM_UNCACHED 2 40 | #define CONF_CM_CACHABLE_NONCOHERENT 3 41 | #define CONF_CM_CACHABLE_COW 5 42 | 43 | #endif /* _MIPSREGS_H_ */ 44 | -------------------------------------------------------------------------------- /src/include/mmio.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause */ 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Simple MMIO register R/W macros 6 | */ 7 | 8 | #ifndef _MMIO_H_ 9 | #define _MMIO_H_ 10 | 11 | #define reg_read32(addr) (*(volatile unsigned int *)(addr)) 12 | #define reg_write32(addr, val) (*(volatile unsigned int *)(addr) = (val)) 13 | #define reg_set32(addr, val) (*(volatile unsigned int *)(addr) |= (val)) 14 | #define reg_clr32(addr, val) (*(volatile unsigned int *)(addr) &= ~(val)) 15 | #define reg_clrset32(addr, clr, set) (*(volatile unsigned int *)(addr) = (*(volatile unsigned int *)(addr) & (~(clr))) | (set)) 16 | 17 | #endif /* _MMIO_H_ */ 18 | -------------------------------------------------------------------------------- /src/include/ns16550.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause */ 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Generic ns16550 UART registers 6 | */ 7 | 8 | #ifndef _NS16550_H_ 9 | #define _NS16550_H_ 10 | 11 | #include 12 | 13 | #define BASE_CLOCK_DIVISOR 16 14 | 15 | #define UART_TBR 0x00 16 | #define UART_DLL UART_TBR 17 | #define UART_IER 0x04 18 | #define UART_DLM UART_IER 19 | #define UART_FCR 0x08 20 | #define UART_LCR 0x0c 21 | #define UART_LSR 0x14 22 | 23 | #define LCR_DLAB BIT(7) /* Divisor Latch Access Bit */ 24 | #define LCR_WLS1 BIT(1) /* Word Length Select */ 25 | #define LCR_WLS0 BIT(0) /* Word Length Select */ 26 | 27 | #define LSR_TEMT BIT(6) 28 | 29 | #endif /* _NS16550_H_ */ 30 | -------------------------------------------------------------------------------- /src/include/spi-nand-load.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause */ 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * SPI-NAND driver with bad block skipping mechanism 6 | */ 7 | 8 | #ifndef _SPI_NAND_LOAD_H_ 9 | #define _SPI_NAND_LOAD_H_ 10 | 11 | #include 12 | 13 | int spi_nand_load_init(void); 14 | 15 | int spi_nand_read_page_to_cache(uint32_t pa); 16 | int spi_nand_load_skip_bad(uint64_t addr, void *buff, uint32_t size); 17 | 18 | #endif /* _SPI_NAND_LOAD_H_ */ 19 | -------------------------------------------------------------------------------- /src/include/spi-nand.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause */ 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Simple SPI-NAND driver 6 | */ 7 | 8 | #ifndef _SPI_NAND_H_ 9 | #define _SPI_NAND_H_ 10 | 11 | void spi_nand_init(void); 12 | void spi_nand_addr_to_pa_ca(uint32_t addr, uint32_t *pa, uint32_t *ca); 13 | void spi_nand_read_page_to_cache(uint32_t pa); 14 | void spi_nand_read_page_cache(uint32_t ca, void *buf, uint32_t len); 15 | void spi_nand_load(uint32_t addr, void *buf, uint32_t len, void *page_cache); 16 | 17 | #endif /* _SPI_NAND_H_ */ 18 | -------------------------------------------------------------------------------- /src/include/stage2.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause */ 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Definitions for 2nd-stage headers 6 | */ 7 | 8 | #ifndef _STAGE2_H_ 9 | #define _STAGE2_H_ 10 | 11 | #include 12 | 13 | struct stage2_header { 14 | uint32_t insn[2]; 15 | uint32_t loadaddr; 16 | uint32_t size; 17 | }; 18 | 19 | uintptr_t get_mem_size(uintptr_t base, uintptr_t limit); 20 | void set_meminfo(uint32_t base, uint32_t size); 21 | void set_stage3_offset(uint32_t offset); 22 | 23 | #endif /* _STAGE2_H_ */ 24 | -------------------------------------------------------------------------------- /src/include/stage3.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause */ 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Definitions for 3rd-stage headers and entry-point ABIs 6 | */ 7 | 8 | #ifndef _STAGE3_H_ 9 | #define _STAGE3_H_ 10 | 11 | #include 12 | 13 | #define UBOOT_IH_MAGIC 0x27051956 14 | #define UBOOT_IH_NMLEN 32 15 | 16 | #define UBOOT_IH_COMP_NONE 0 17 | #define UBOOT_IH_COMP_LZMA 3 18 | 19 | typedef struct uboot_image_header { 20 | uint32_t ih_magic; 21 | uint32_t ih_hcrc; 22 | uint32_t ih_time; 23 | uint32_t ih_size; 24 | uint32_t ih_load; 25 | uint32_t ih_ep; 26 | uint32_t ih_dcrc; 27 | uint8_t ih_os; 28 | uint8_t ih_arch; 29 | uint8_t ih_type; 30 | uint8_t ih_comp; 31 | uint8_t ih_name[UBOOT_IH_NMLEN]; 32 | } uboot_image_header_t; 33 | 34 | typedef void (*u_boot_entry_point_t)(void); 35 | 36 | 37 | #define BOOTSTRAP_HDR_MAGIC 0x37540178 38 | 39 | typedef struct bootstrap_kernel_header_type { 40 | uint32_t magic; 41 | uint32_t length; 42 | uint32_t load_address; 43 | uint32_t entry_point; 44 | } bootstrap_kernel_header_t; 45 | 46 | typedef void (*kernel_entry_point_t)(uint32_t ramsize); 47 | 48 | #endif /* _STAGE3_H_ */ 49 | -------------------------------------------------------------------------------- /src/include/stdarg.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause */ 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Standard C library implementation (GCC-specific) 6 | */ 7 | 8 | #ifndef _STDARG_H_ 9 | #define _STDARG_H_ 10 | 11 | typedef __builtin_va_list va_list; 12 | 13 | #define va_start(v, l) __builtin_va_start(v, l) 14 | #define va_end(v) __builtin_va_end(v) 15 | #define va_arg(v, l) __builtin_va_arg(v, l) 16 | #define va_copy(d, s) __builtin_va_copy(d, s) 17 | 18 | #endif /* _STDARG_H_ */ 19 | -------------------------------------------------------------------------------- /src/include/stdbool.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause */ 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Standard C library implementation 6 | */ 7 | 8 | #ifndef _STDBOOL_H_ 9 | #define _STDBOOL_H_ 10 | 11 | #define bool _Bool 12 | #define true 1 13 | #define false 0 14 | 15 | #endif /* _STDBOOL_H_ */ 16 | -------------------------------------------------------------------------------- /src/include/stddef.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause */ 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Standard C library implementation 6 | */ 7 | 8 | #ifndef _STDDEF_H_ 9 | #define _STDDEF_H_ 10 | 11 | #define NULL ((void *)0) 12 | 13 | #define offsetof(TYPE, MEMBER) __builtin_offsetof(TYPE, MEMBER) 14 | 15 | #endif /* _STDDEF_H_ */ 16 | -------------------------------------------------------------------------------- /src/include/string.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause */ 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Standard C library string functions 6 | */ 7 | 8 | #ifndef _STRING_H_ 9 | #define _STRING_H_ 10 | 11 | #include 12 | 13 | void *memset(void *dst, int val, uintptr_t count); 14 | void *memcpy(void *dst, const void *src, uintptr_t count); 15 | int memcmp(const void *cs, const void *ct, uintptr_t count); 16 | uintptr_t strlen(const char *s); 17 | 18 | #endif /* _STRING_H_ */ 19 | -------------------------------------------------------------------------------- /src/include/timer.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause */ 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Simple timer utilities 6 | */ 7 | 8 | #ifndef _TIMER_H_ 9 | #define _TIMER_H_ 10 | 11 | #include 12 | 13 | void set_timer_freq(uint32_t freq); 14 | void udelay(uint32_t usec); 15 | 16 | #if STAGE == 2 17 | uint64_t get_ticks(void); 18 | uint64_t get_timer(uint64_t base); 19 | #endif 20 | 21 | #endif /* _TIMER_H_ */ 22 | -------------------------------------------------------------------------------- /src/include/types.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause */ 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Standard C type definitions 6 | */ 7 | 8 | #ifndef _TYPES_H_ 9 | #define _TYPES_H_ 10 | 11 | typedef unsigned char uint8_t; 12 | typedef signed char int8_t; 13 | 14 | typedef unsigned short uint16_t; 15 | typedef signed short int16_t; 16 | 17 | typedef unsigned int uint32_t; 18 | typedef signed int int32_t; 19 | 20 | typedef unsigned long long uint64_t; 21 | typedef signed long long int64_t; 22 | 23 | typedef unsigned long uintptr_t; 24 | typedef signed long intptr_t; 25 | 26 | typedef unsigned long size_t; 27 | 28 | typedef intptr_t ptrdiff_t; 29 | 30 | #endif /* _TYPES_H_ */ 31 | -------------------------------------------------------------------------------- /src/libc/libc.mk: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | # Copyright (C) 2020 Weijie Gao 3 | 4 | COBJS += libc/memset.o \ 5 | libc/memcmp.o \ 6 | libc/memcpy.o \ 7 | libc/strlen.o 8 | -------------------------------------------------------------------------------- /src/libc/memcmp.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | */ 5 | 6 | #include 7 | 8 | int memcmp(const void *cs, const void *ct, uintptr_t count) 9 | { 10 | const uint8_t *su1 = cs, *su2 = ct; 11 | int res = 0; 12 | 13 | while (count) { 14 | res = *su1 - *su2; 15 | if (res) 16 | return res; 17 | 18 | su1++; 19 | su2++; 20 | count--; 21 | } 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /src/libc/memcpy.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | */ 5 | 6 | #include 7 | 8 | void *memcpy(void *dst, const void *src, uintptr_t count) 9 | { 10 | uintptr_t *dl = (uintptr_t *)dst, *sl = (uintptr_t *)src; 11 | uint8_t *d8, *s8; 12 | 13 | if (src == dst) 14 | return dst; 15 | 16 | if ((((uintptr_t) dst | (uintptr_t) src) & (sizeof(*dl) - 1)) == 0) { 17 | while (count >= sizeof(*dl)) { 18 | *dl++ = *sl++; 19 | count -= sizeof(*dl); 20 | } 21 | } 22 | 23 | d8 = (uint8_t *)dl; 24 | s8 = (uint8_t *)sl; 25 | 26 | while (count--) 27 | *d8++ = *s8++; 28 | 29 | return dst; 30 | } 31 | -------------------------------------------------------------------------------- /src/libc/memset.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | */ 5 | 6 | #include 7 | 8 | void *memset(void *dst, int val, uintptr_t count) 9 | { 10 | char *ptr = dst; 11 | 12 | while (count--) 13 | *ptr++ = val; 14 | 15 | return dst; 16 | } 17 | -------------------------------------------------------------------------------- /src/libc/strlen.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | */ 5 | 6 | #include 7 | 8 | uintptr_t strlen(const char *s) 9 | { 10 | uintptr_t n = 0; 11 | 12 | while (*s++) 13 | n++; 14 | 15 | return n; 16 | } 17 | -------------------------------------------------------------------------------- /src/loader.lds.S: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause */ 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | */ 5 | 6 | OUTPUT_ARCH(mips) 7 | 8 | ENTRY(_start) 9 | 10 | SECTIONS { 11 | . = 0x00000000; 12 | 13 | . = ALIGN(4); 14 | .text : { 15 | __copy_start = .; 16 | __text_start = .; 17 | *(.text*) 18 | __text_end = .; 19 | } 20 | 21 | . = ALIGN(4); 22 | .rodata : { 23 | *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) 24 | } 25 | 26 | . = ALIGN(4); 27 | .data : { 28 | *(.data*) 29 | } 30 | 31 | . = ALIGN(4); 32 | .sdata : { 33 | *(.sdata*) 34 | } 35 | 36 | . = ALIGN(4); 37 | __copy_end = .; 38 | __copy_size = . - __copy_start; 39 | 40 | . = ALIGN(4); 41 | .bss : { 42 | __bss_start = .; 43 | *(.bss.*) 44 | *(.sbss.*) 45 | *(COMMON) 46 | . = ALIGN(4); 47 | __bss_end = .; 48 | } 49 | 50 | . = ALIGN(4); 51 | __prog_end = .; 52 | __prog_size = . - __copy_start; 53 | 54 | /DISCARD/ : { 55 | *(.note.gnu.*) 56 | *(.MIPS.abiflags) 57 | *(.prgend) 58 | } 59 | 60 | #ifdef STAGE2 61 | __stage3_offset = PAGESIZE + ALIGN(__copy_size, PAGESIZE); 62 | #endif 63 | } 64 | -------------------------------------------------------------------------------- /src/mt7621/include/config.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause */ 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * MediaTek MT7621 related parameters 6 | */ 7 | 8 | #ifndef _CONFIG_H_ 9 | #define _CONFIG_H_ 10 | 11 | #define L1_DCACHE_SIZE (32 << 10) 12 | #define L1_DCACHE_LINESIZE 32 13 | 14 | #define L1_ICACHE_SIZE (32 << 10) 15 | #define L1_ICACHE_LINESIZE 32 16 | 17 | #define L2_CACHE_SIZE (256 << 10) 18 | #define L2_CACHE_LINESIZE 32 19 | 20 | #define CMGIC_BASE 0x1fbc0000 21 | #define CMGCR_BASE 0x1fbf8000 22 | #define CMCPC_BASE 0x1fbf0000 23 | 24 | #endif /* _CONFIG_H_ */ 25 | -------------------------------------------------------------------------------- /src/mt7621/include/cps.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause */ 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | */ 5 | 6 | #ifndef _CPS_H_ 7 | #define _CPS_H_ 8 | 9 | void mt7621_cps_init(void); 10 | 11 | #endif /* _CPS_H_ */ 12 | -------------------------------------------------------------------------------- /src/mt7621/include/mt7621_ddr_param.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause */ 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * DRAMC related definitions for MediaTek MT7621 6 | */ 7 | 8 | #ifndef _MT7621_DDR_PARAM_H_ 9 | #define _MT7621_DDR_PARAM_H_ 10 | 11 | #include 12 | 13 | typedef uint32_t ddr_ac_timing_param_t[24]; 14 | 15 | typedef enum ddr2_act_type { 16 | DDR2_512M = 0, 17 | DDR2_W9751G6KB_A02_1066_512M, 18 | DDR2_1024M, 19 | DDR2_W971GG6KB25_800_1024M, 20 | DDR2_W971GG6KB18_1066_1024M, 21 | 22 | __DDR2_ACT_MAX 23 | } ddr2_act_t; 24 | 25 | typedef enum ddr3_act_type { 26 | DDR3_1024M = 0, 27 | DDR3_1024M_KGD, 28 | DDR3_2048M, 29 | DDR3_4096M, 30 | 31 | __DDR3_ACT_MAX 32 | } ddr3_act_t; 33 | 34 | typedef enum ddr_init_type { 35 | DDR_INIT_PRE_DEFINED_FIRST = 0, 36 | DDR_INIT_BOARD_PROVIDED_FIRST 37 | } ddr_init_type_t; 38 | 39 | typedef enum ddr_type { 40 | MT7621_DDR3 = 0, 41 | MT7621_DDR2 = 1 42 | } ddr_type_t; 43 | 44 | #endif /* _MT7621_DDR_PARAM_H_ */ 45 | -------------------------------------------------------------------------------- /src/mt7621/include/mt7621_regs.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause */ 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Register definitions for MediaTek MT7621 6 | */ 7 | 8 | #ifndef _MT7621_REGS_H_ 9 | #define _MT7621_REGS_H_ 10 | 11 | #include 12 | 13 | #define PALMBUS_BASE 0xbe000000 14 | 15 | #define SYSCTL_BASE (PALMBUS_BASE + 0x000) 16 | 17 | #define SYSCTL_SYSCFG0 (PALMBUS_BASE + 0x010) 18 | #define XTAL_MODE_SEL_M 0x1c0 19 | #define XTAL_MODE_SEL_S 6 20 | #define XTAL_MODE_SEL_W 3 21 | #define DRAM_TYPE BIT(4) 22 | 23 | #define SYSCTL_CLKCFG0 (PALMBUS_BASE + 0x02c) 24 | #define CPU_CLK_SEL_M 0xc0000000 25 | #define CPU_CLK_SEL_S 30 26 | #define CPU_CLK_SEL_W 2 27 | #define MPLL_CFG_SEL BIT(23) 28 | 29 | #define SYSCTL_RSTCTL (PALMBUS_BASE + 0x034) 30 | #define SPI_RST BIT(18) 31 | #define MC_RST BIT(2) 32 | #define SYS_RST BIT(0) 33 | 34 | #define SYSCTL_CUR_CLK_STS (PALMBUS_BASE + 0x044) 35 | #define CUR_CPU_FDIV_M 0x1f00 36 | #define CUR_CPU_FDIV_S 8 37 | #define CUR_CPU_FDIV_W 5 38 | #define CUR_CPU_FFRAC_M 0x1f 39 | #define CUR_CPU_FFRAC_S 0 40 | #define CUR_CPU_FFRAC_W 5 41 | 42 | #define SYSCTL_GPIOMODE (SYSCTL_BASE + 0x60) 43 | #define UART1_MODE_M 0x02 44 | 45 | #define RBUS_DYN_CFG0 (PALMBUS_BASE + 0x410) 46 | 47 | #define SPI_BASE (PALMBUS_BASE + 0xb00) 48 | 49 | #define SPI_TRANS_REG (SPI_BASE + 0x00) 50 | #define SPI_ADDR_SIZE_MASK 0x03 51 | #define SPI_ADDR_SIZE_SHIFT 19 52 | #define SPI_MASTER_BUSY BIT(16) 53 | #define SPI_MASTER_START BIT(8) 54 | 55 | #define SPI_OP_ADDR_REG (SPI_BASE + 0x04) 56 | #define SPI_DIDO_REG(x) (SPI_BASE + 0x08 + ((x) << 2)) 57 | 58 | #define SPI_MASTER_REG (SPI_BASE + 0x28) 59 | #define RS_SLAVE_SEL_MASK 0x7 60 | #define RS_SLAVE_SEL_SHIFT 29 61 | #define RS_CLK_SEL_MASK 0xfff 62 | #define RS_CLK_SEL_SHIFT 16 63 | #define MORE_BUF_MODE BIT(2) 64 | 65 | #define SPI_MOREBUF_REG (SPI_BASE + 0x2c) 66 | #define CMD_BIT_CNT_MASK 0x3f 67 | #define CMD_BIT_CNT_SHIFT 24 68 | #define MISO_BIT_CNT_MASK 0x1ff 69 | #define MISO_BIT_CNT_SHIFT 12 70 | #define MOSI_BIT_CNT_MASK 0x1ff 71 | #define MOSI_BIT_CNT_SHIFT 0 72 | 73 | #define SPI_CS_POLAR_REG (SPI_BASE + 0x38) 74 | #define SPI_MMAP_SPACE (SPI_BASE + 0x3c) 75 | 76 | #define UART1_BASE (PALMBUS_BASE + 0xc00) 77 | 78 | #define DRAMC_BASE (PALMBUS_BASE + 0x5000) 79 | 80 | #define DRAMC_CPLL_REG (DRAMC_BASE + 0x0648) 81 | #define CPLL_PREDIV_M 0x3000 82 | #define CPLL_PREDIV_S 12 83 | #define CPLL_FBDIV_M 0x7f0 84 | #define CPLL_FBDIV_S 4 85 | #define CPLL_FBSEL_M 0x03 86 | #define CPLL_FBSEL_S 1 87 | 88 | #define FE_BASE 0xbe100000 89 | #define FE_RST_GLO 0x04 90 | 91 | #define GCR_REG0_BASE_VALUE 0x1c000000 92 | #define GCR_REG0_MASK_VALUE 0x0000fc00 /* 64M Palmbus */ 93 | 94 | #endif /* _MT7621_REGS_H_ */ 95 | -------------------------------------------------------------------------------- /src/mt7621/include/serial.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause */ 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Simple UART driver for MediaTek MT7621 6 | */ 7 | 8 | #ifndef _SERIAL_H_ 9 | #define _SERIAL_H_ 10 | 11 | void serial_init(void); 12 | void serial_putc(char c); 13 | 14 | #endif /* _SERIAL_H_ */ 15 | -------------------------------------------------------------------------------- /src/mt7621/include/spi.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause */ 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * SPI controller driver for MT7621 6 | */ 7 | 8 | #ifndef _SPI_H_ 9 | #define _SPI_H_ 10 | 11 | #include 12 | 13 | void spi_init(void); 14 | void spi_set_clock(uint32_t hclk, uint32_t clk); 15 | void spi_en(void); 16 | void spi_dis(void); 17 | void spi_read(uint8_t *buf, uint32_t len); 18 | void spi_write(const uint8_t *buf, uint32_t len); 19 | 20 | #endif /* _SPI_H_ */ 21 | -------------------------------------------------------------------------------- /src/mt7621/include/target.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause */ 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | */ 5 | 6 | #ifndef _TARGET_H_ 7 | #define _TARGET_H_ 8 | 9 | #include 10 | 11 | uintptr_t get_stage2_offset(void); 12 | 13 | void target_init(void); 14 | void target_stage2_pre_setup(uintptr_t loadaddr, uint32_t size); 15 | void target_stage2_post_setup(uintptr_t loadaddr, uint32_t size); 16 | void target_stage2_data_process(uintptr_t dstaddr, uint32_t ca); 17 | 18 | #endif /* _TARGET_H_ */ 19 | -------------------------------------------------------------------------------- /src/mt7621/serial.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Simple UART driver for MediaTek MT7621 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define UART_BASE UART1_BASE 14 | #define BASE_CLOCK 50000000 15 | 16 | #define DIV_ROUND_CLOSEST(x, divisor) \ 17 | ({ \ 18 | typeof(divisor) __divisor = divisor; \ 19 | (((x) + ((__divisor) / 2)) / (__divisor)); \ 20 | }) 21 | 22 | extern uint32_t _baudrate; 23 | 24 | void serial_init(void) 25 | { 26 | uint32_t clock_divisor; 27 | 28 | clock_divisor = DIV_ROUND_CLOSEST(BASE_CLOCK, (BASE_CLOCK_DIVISOR * _baudrate)); 29 | 30 | reg_clr32(SYSCTL_GPIOMODE, UART1_MODE_M); 31 | 32 | reg_write32(UART_BASE + UART_IER, 0); 33 | reg_write32(UART_BASE + UART_FCR, 0); 34 | 35 | /* set baud rate */ 36 | reg_write32(UART_BASE + UART_LCR, LCR_WLS0 | LCR_WLS1 | LCR_DLAB); 37 | reg_write32(UART_BASE + UART_DLL, clock_divisor & 0xff); 38 | reg_write32(UART_BASE + UART_DLM, clock_divisor >> 8); 39 | reg_write32(UART_BASE + UART_LCR, LCR_WLS0 | LCR_WLS1); 40 | } 41 | 42 | void serial_putc(char c) 43 | { 44 | /* wait for room in the tx FIFO on UART */ 45 | while ((reg_read32(UART_BASE + UART_LSR) & LSR_TEMT) == 0); 46 | 47 | reg_write32(UART_BASE + UART_TBR, c); 48 | } 49 | -------------------------------------------------------------------------------- /src/mt7621/spi.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * SPI controller driver for MT7621 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define MT7621_RX_FIFO_LEN 32 14 | #define MT7621_TX_FIFO_LEN 36 15 | 16 | void spi_init(void) 17 | { 18 | reg_write32(SPI_MASTER_REG, (RS_SLAVE_SEL_MASK << RS_SLAVE_SEL_SHIFT) | 19 | (12 << RS_CLK_SEL_SHIFT) | MORE_BUF_MODE); 20 | reg_write32(SPI_CS_POLAR_REG, 0); 21 | } 22 | 23 | void spi_set_clock(uint32_t hclk, uint32_t clk) 24 | { 25 | uint32_t div, val; 26 | 27 | div = (hclk + clk - 1) / clk; 28 | 29 | if (div > 4097) 30 | div = 4097; 31 | 32 | if (div < 2) 33 | div = 2; 34 | 35 | div -= 2; 36 | 37 | val = reg_read32(SPI_MASTER_REG); 38 | val &= ~(RS_CLK_SEL_MASK << RS_CLK_SEL_SHIFT); 39 | val |= div << RS_CLK_SEL_SHIFT; 40 | reg_write32(SPI_MASTER_REG, val); 41 | } 42 | 43 | void spi_en(void) 44 | { 45 | reg_write32(SPI_CS_POLAR_REG, 1); 46 | } 47 | 48 | void spi_dis(void) 49 | { 50 | reg_write32(SPI_CS_POLAR_REG, 0); 51 | } 52 | 53 | static void spi_busy_wait(void) 54 | { 55 | while (reg_read32(SPI_TRANS_REG) & SPI_MASTER_BUSY); 56 | } 57 | 58 | void spi_read(uint8_t *buf, uint32_t len) 59 | { 60 | uint32_t rx_len, val = 0; 61 | int i; 62 | 63 | while (len) { 64 | rx_len = len < MT7621_RX_FIFO_LEN ? len : MT7621_RX_FIFO_LEN; 65 | 66 | reg_write32(SPI_MOREBUF_REG, (rx_len * 8) << MISO_BIT_CNT_SHIFT); 67 | reg_write32(SPI_TRANS_REG, SPI_MASTER_START); 68 | 69 | spi_busy_wait(); 70 | 71 | for (i = 0; i < rx_len; i++) { 72 | if ((i % 4) == 0) 73 | val = reg_read32(SPI_DIDO_REG(i / 4)); 74 | *buf++ = val & 0xff; 75 | val >>= 8; 76 | } 77 | 78 | len -= rx_len; 79 | } 80 | } 81 | 82 | void spi_write(const uint8_t *buf, uint32_t len) 83 | { 84 | uint32_t tx_len, opcode_len, dido_len, val; 85 | int i; 86 | 87 | while (len) { 88 | tx_len = len < MT7621_TX_FIFO_LEN ? len: MT7621_TX_FIFO_LEN; 89 | 90 | opcode_len = tx_len < 4 ? tx_len : 4; 91 | dido_len = tx_len - opcode_len; 92 | 93 | val = 0; 94 | for (i = 0; i < opcode_len; i++) { 95 | val <<= 8; 96 | val |= *buf++; 97 | } 98 | 99 | reg_write32(SPI_OP_ADDR_REG, val); 100 | 101 | val = 0; 102 | for (i = 0; i < dido_len; i++) { 103 | val |= (*buf++) << ((i % 4) * 8); 104 | 105 | if ((i % 4 == 3) || (i == dido_len - 1)) { 106 | reg_write32(SPI_DIDO_REG(i / 4), val); 107 | val = 0; 108 | } 109 | } 110 | 111 | reg_write32(SPI_MOREBUF_REG, 112 | ((opcode_len * 8) << CMD_BIT_CNT_SHIFT) | 113 | ((dido_len * 8) << MOSI_BIT_CNT_SHIFT)); 114 | reg_write32(SPI_TRANS_REG, SPI_MASTER_START); 115 | 116 | spi_busy_wait(); 117 | 118 | len -= tx_len; 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/mt7621/stage1/build.mk: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | # Copyright (C) 2020 Weijie Gao 3 | 4 | TEXT_BASE := 0xbe108000 5 | 6 | HEAD := $(TARGET)/$(STAGE)/entry.o 7 | COBJS += $(TARGET)/$(STAGE)/target.o 8 | -------------------------------------------------------------------------------- /src/mt7621/stage1/entry.S: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause */ 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Entry for 1st-stage 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | .text 17 | .set nomips16 18 | .set noreorder 19 | 20 | ENTRY(_start) 21 | b _start_real 22 | nop 23 | 24 | .org 0x08 25 | EXPORT(_stage2_offset) 26 | .word PAGESIZE 27 | 28 | EXPORT(_baudrate) 29 | .word BAUDRATE 30 | 31 | _start_real: 32 | mfc0 $t0, CP0_EBASE 33 | and $t0, $t0, EBASE_CPUNUM 34 | bnez $t0, _start_real 35 | nop 36 | 37 | mtc0 $0, CP0_COUNT 38 | mtc0 $0, CP0_COMPARE 39 | 40 | /* Init CP0 Status */ 41 | mfc0 $t0, CP0_STATUS 42 | and $t0, ST0_IMPL 43 | or $t0, ST0_BEV | ST0_ERL 44 | mtc0 $t0, CP0_STATUS 45 | nop 46 | 47 | /* Clear Watch Status bits and disable watch exceptions */ 48 | li $t0, 0x7 # Clear I, R and W conditions 49 | mtc0 $0, CP0_WATCHLO, 0 50 | mtc0 $t1, CP0_WATCHHI, 0 51 | mtc0 $0, CP0_WATCHLO, 1 52 | mtc0 $t1, CP0_WATCHHI, 1 53 | mtc0 $0, CP0_WATCHLO, 2 54 | mtc0 $t1, CP0_WATCHHI, 2 55 | mtc0 $0, CP0_WATCHLO, 3 56 | mtc0 $t1, CP0_WATCHHI, 3 57 | 58 | /* Clear WP, IV and SW interrupts */ 59 | mtc0 $0, CP0_CAUSE 60 | 61 | /* Set KSEG0 to Uncached */ 62 | mfc0 $t0, CP0_CONFIG 63 | ins $t0, $0, 0, 3 64 | ori $t0, $t0, CONF_CM_UNCACHED 65 | mtc0 $t0, CP0_CONFIG 66 | ehb 67 | 68 | /* Setup GCR base */ 69 | 1: mfc0 $t0, CP0_CMGCRBASE 70 | sll $t0, $t0, 4 71 | 72 | li $t1, CMGCR_BASE 73 | beq $t0, $t1, 2f 74 | 75 | /* Move the GCRs to our configured base address */ 76 | li $t2, KSEG1BASE 77 | addu $t0, $t0, $t2 78 | sw $0, GCR_BASE_UPPER($t0) 79 | sw $t1, GCR_BASE($t0) 80 | 81 | /* Re-check the GCR base */ 82 | b 1b 83 | nop 84 | 2: 85 | 86 | /* Setup basic CPS */ 87 | li $t0, (KSEG1BASE + CMGCR_BASE) 88 | li $t1, GCR_REG0_BASE_VALUE 89 | sw $t1, (GCR_REGn_BASE(0))($t0) 90 | 91 | li $t1, ((GCR_REG0_MASK_VALUE << GCR_REGn_MASK_ADDRMASK_S) | \ 92 | GCR_REGn_MASK_CMTGT_IOCU0) 93 | sw $t1, (GCR_REGn_MASK(0))($t0) 94 | 95 | lw $t1, GCR_BASE($t0) 96 | ins $t1, $0, 0, 2 97 | sw $t1, GCR_BASE($t0) 98 | 99 | lw $t1, GCR_CONTROL($t0) 100 | li $t2, GCR_CONTROL_SYNCCTL 101 | or $t1, $t1, $t2 102 | sw $t1, GCR_CONTROL($t0) 103 | 104 | /* Increase SPI frequency */ 105 | li $t0, PALMBUS_BASE 106 | li $t1, 5 107 | sw $t1, (SPI_MMAP_SPACE - PALMBUS_BASE)($t0) 108 | 109 | /* Set CPU clock to 500MHz */ 110 | lw $t1, (SYSCTL_CLKCFG0 - PALMBUS_BASE)($t0) 111 | ins $t1, $0, 30, 2 112 | sw $t1, (SYSCTL_CLKCFG0 - PALMBUS_BASE)($t0) 113 | 114 | /* Set CPU clock divider to 1/1 */ 115 | li $t1, 0x101 116 | sw $t1, (RBUS_DYN_CFG0 - PALMBUS_BASE)($t0) 117 | 118 | /* Enable Frame Engine SRAM */ 119 | li $t0, FE_BASE 120 | li $t1, 1 121 | sw $t1, FE_RST_GLO($t0) 122 | li $t1, 6 123 | sw $t1, FE_RST_GLO($t0) 124 | 125 | /* Initialize L1 & L2 Cache */ 126 | bal cache_init 127 | nop 128 | 129 | /* Copy bootcode into SRAM */ 130 | la $a0, _start 131 | li $a1, 0xbfc00000 132 | li $a2, 0x800 133 | 134 | 1: lw $a3, 0($a1) 135 | sw $a3, 0($a0) 136 | addiu $a0, 4 137 | addiu $a1, 4 138 | sub $a2, 4 139 | bnez $a2, 1b 140 | nop 141 | 142 | /* Clear BSS section */ 143 | la $a0, __bss_start 144 | la $a1, __bss_end 145 | 146 | 1: sw $0, 0($a0) 147 | addiu $a0, 4 148 | bne $a0, $a1, 1b 149 | nop 150 | 151 | /* Setup stack */ 152 | li $sp, 0xbe10dff0 153 | 154 | /* Continue to run in SRAM */ 155 | la $t9, stage1_main 156 | jr $t9 157 | nop 158 | ENDFUNC(_start) 159 | 160 | LEAFUNC(lock_l2_cache) 161 | li $v0, 0x1ffff800 162 | li $v1, ~(L2_CACHE_LINESIZE - 1) 163 | add $a1, $a1, $a0 164 | addi $a1, L2_CACHE_LINESIZE - 1 165 | and $a0, $a0, $v1 166 | and $a1, $a1, $v1 167 | 168 | mtc0 $0, CP0_SDATALO 169 | mtc0 $0, CP0_SDATAHI 170 | 171 | 1: 172 | and $v1, $a0, $v0 173 | ori $v1, 0xa0 174 | mtc0 $v1, CP0_STAGLO 175 | cache INDEX_STORE_TAG_SD, 0($a0) 176 | cache INDEX_STORE_DATA_SD, 0($a0) 177 | cache INDEX_STORE_DATA_SD, 8($a0) 178 | cache INDEX_STORE_DATA_SD, 16($a0) 179 | cache INDEX_STORE_DATA_SD, 24($a0) 180 | addi $a0, L2_CACHE_LINESIZE 181 | bne $a0, $a1, 1b 182 | nop 183 | 184 | jr $ra 185 | nop 186 | ENDFUNC(lock_l2_cache) 187 | 188 | LEAFUNC(fill_l2_cache) 189 | addiu $a2, 7 190 | ins $a2, $0, 0, 3 191 | 192 | 1: lw $t0, 0($a1) 193 | mtc0 $t0, CP0_SDATALO 194 | lw $t0, 4($a1) 195 | mtc0 $t0, CP0_SDATAHI 196 | cache INDEX_STORE_DATA_SD, 0($a0) 197 | addiu $a0, 8 198 | addiu $a1, 8 199 | sub $a2, 8 200 | bnez $a2, 1b 201 | nop 202 | 203 | jr $ra 204 | nop 205 | ENDFUNC(fill_l2_cache) 206 | 207 | FUNC(cache_init, $sp, 0, $ra) 208 | move $s0, $ra 209 | 210 | li $s1, (KSEG1BASE + CMGCR_BASE) 211 | 212 | /* Enable CCA override. Set to uncached */ 213 | lw $s2, 0($s1) 214 | ins $s2, $0, 4, 4 215 | ori $s3, $s2, (GCR_CCA_DEFAULT_OVERRIDE_ENABLE | (2 << GCR_CCA_DEF_OVERRIDE_VALUE_S)) 216 | sw $s3, 0($s1) 217 | 218 | /* Initialize L1 Cache */ 219 | bal reset_l1_cache 220 | nop 221 | 222 | /* Initialize L2 Cache */ 223 | move $a0, $0 224 | li $a1, L2_CACHE_SIZE 225 | 226 | mtc0 $0, CP0_STAGLO 227 | 228 | 1: 229 | cache INDEX_STORE_TAG_SD, 0($a0) 230 | addiu $a0, $a0, L2_CACHE_LINESIZE 231 | bne $a0, $a1, 1b 232 | nop 233 | 234 | /* Dsiable CCA override */ 235 | sw $s2, 0($s1) 236 | 237 | /* Set KSEG0 to non-coherent cached (important!) */ 238 | mfc0 $t0, CP0_CONFIG 239 | ins $t0, $0, 0, 3 240 | ori $t0, CONF_CM_CACHABLE_NONCOHERENT 241 | mtc0 $t0, CP0_CONFIG 242 | ehb 243 | 244 | /* Initialize L1 Cache again */ 245 | bal reset_l1_cache 246 | nop 247 | 248 | /* Disable L2 cache bypass */ 249 | mfc0 $t0, CP0_CONFIG2 250 | ins $t0, $0, 12, 1 251 | mtc0 $t0, CP0_CONFIG2 252 | ehb 253 | 254 | /* Clear WSC & SPR bit in ErrCtl */ 255 | mfc0 $t0, CP0_ECC 256 | li $t1, 0xcfffffff 257 | and $t0, $t0, $t1 258 | mtc0 $t0, CP0_ECC 259 | ehb 260 | 261 | move $ra, $s0 262 | jr $ra 263 | nop 264 | ENDFUNC(cache_init) 265 | -------------------------------------------------------------------------------- /src/mt7621/stage1/target.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | extern void __nomips16 lock_l2_cache(uintptr_t base, uint32_t size); 16 | extern void __nomips16 fill_l2_cache(uintptr_t dst, void *src, uint32_t size); 17 | 18 | extern uintptr_t _stage2_offset; 19 | 20 | uintptr_t get_stage2_offset(void) 21 | { 22 | return _stage2_offset; 23 | } 24 | 25 | void target_init(void) 26 | { 27 | set_timer_freq(500000000 / 2); 28 | serial_init(); 29 | spi_init(); 30 | } 31 | 32 | void target_stage2_pre_setup(uintptr_t loadaddr, uint32_t size) 33 | { 34 | lock_l2_cache(loadaddr, size); 35 | } 36 | 37 | void target_stage2_post_setup(uintptr_t loadaddr, uint32_t size) 38 | { 39 | invalidate_l1_cache_range(loadaddr, size); 40 | 41 | ((void (*)(void))loadaddr)(); 42 | } 43 | 44 | void target_stage2_data_process(uintptr_t dstaddr, uint32_t ca) 45 | { 46 | uint8_t buf[PAGESIZE]; 47 | 48 | spi_nand_read_page_cache(ca, buf, sizeof(buf)); 49 | fill_l2_cache(dstaddr, buf, PAGESIZE); 50 | } 51 | -------------------------------------------------------------------------------- /src/mt7621/stage2/build.mk: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | # Copyright (C) 2020 Weijie Gao 3 | 4 | TEXT_BASE := 0x82000000 5 | 6 | HEAD := $(TARGET)/$(STAGE)/entry.o 7 | COBJS += $(TARGET)/$(STAGE)/target.o \ 8 | $(TARGET)/$(STAGE)/cps.o 9 | 10 | SOBJS += $(TARGET)/$(STAGE)/dramc/dramc.o 11 | 12 | ifeq ($(MT7621_DRAMC_DEBUG),y) 13 | AFLAGS += -DDRAMC_BIN_FILE=\"$(TARGET)/$(STAGE)/dramc/mt7621_stage_sram.bin\" 14 | else 15 | AFLAGS += -DDRAMC_BIN_FILE=\"$(TARGET)/$(STAGE)/dramc/mt7621_stage_sram_noprint.bin\" 16 | endif 17 | -------------------------------------------------------------------------------- /src/mt7621/stage2/cps.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * MIPS CPS initialization for MediaTek MT7621 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | static const struct cm_region { 16 | uint32_t base; 17 | uint32_t size; 18 | } cm_regions[] = { 19 | { 0x1c000000, 0x04000000 }, 20 | { 0x60000000, 0x10000000 }, 21 | { 0x1c000000, 0x04000000 }, 22 | { 0x1c000000, 0x04000000 }, 23 | }; 24 | 25 | static const struct gic_map_pin { 26 | uint32_t src; 27 | uint32_t pin; 28 | } gic_map_pins[] = { 29 | { 0, 0 }, 30 | { 1, 0 }, 31 | { 2, 4 }, 32 | { 3, 3 }, 33 | { 4, 0 }, 34 | { 5, 5 }, 35 | { 56, 1 }, 36 | { 57, 1 }, 37 | { 58, 1 }, 38 | { 59, 1 }, 39 | { 60, 2 }, 40 | { 61, 2 }, 41 | { 62, 2 }, 42 | { 63, 2 }, 43 | }; 44 | 45 | static inline uint32_t cmgcr_read(uint32_t reg) 46 | { 47 | return reg_read32(KSEG1ADDR(CMGCR_BASE) + reg); 48 | } 49 | 50 | static inline void cmgcr_write(uint32_t reg, uint32_t val) 51 | { 52 | reg_write32(KSEG1ADDR(CMGCR_BASE) + reg, val); 53 | } 54 | 55 | static inline void cmgcr_rmw(uint32_t reg, uint32_t clr, uint32_t set) 56 | { 57 | uint32_t val; 58 | 59 | val = cmgcr_read(reg); 60 | val &= ~clr; 61 | val |= set; 62 | cmgcr_write(reg, val); 63 | } 64 | 65 | static inline uint32_t cmgic_read(uint32_t reg) 66 | { 67 | return reg_read32(KSEG1ADDR(CMGIC_BASE) + reg); 68 | } 69 | 70 | static inline void cmgic_write(uint32_t reg, uint32_t val) 71 | { 72 | reg_write32(KSEG1ADDR(CMGIC_BASE) + reg, val); 73 | } 74 | 75 | static inline void cmgic_rmw(uint32_t reg, uint32_t clr, uint32_t set) 76 | { 77 | uint32_t val; 78 | 79 | val = cmgic_read(reg); 80 | val &= ~clr; 81 | val |= set; 82 | cmgic_write(reg, val); 83 | } 84 | 85 | static void cm_init(void) 86 | { 87 | uint32_t num_cores, num_iocu; 88 | int i; 89 | 90 | num_cores = ((cmgcr_read(GCR_CONFIG) & GCR_CONFIG_PCORES_M) >> GCR_CONFIG_PCORES_S) + 1; 91 | 92 | cmgcr_write(GCR_ACCESS, (1 << num_cores) - 1); 93 | 94 | num_iocu = ((cmgcr_read(GCR_CONFIG) & GCR_CONFIG_NUMIOCU_M) >> GCR_CONFIG_NUMIOCU_S) + 1; 95 | 96 | if (!num_iocu) 97 | return; 98 | 99 | for (i = 0; i < ARRAY_SIZE(cm_regions); i++) { 100 | cmgcr_write(GCR_REGn_BASE(i), cm_regions[i].base); 101 | cmgcr_write(GCR_REGn_MASK(i), (~(cm_regions[i].size - 1)) | GCR_REGn_MASK_CMTGT_IOCU0); 102 | } 103 | 104 | cmgcr_rmw(GCR_BASE, GCR_CM_DEFAULT_TARGET_M, GCR_CM_DEFAULT_TARGET_MEMORY); 105 | cmgcr_rmw(GCR_CONTROL, 0, GCR_CONTROL_SYNCCTL); 106 | } 107 | 108 | static void cpc_init(void) 109 | { 110 | if (cmgcr_read(GCR_CPC_STATUS) & GCR_CPC_EX) 111 | cmgcr_write(GCR_CPC_BASE, CMCPC_BASE | GCR_CPC_EN); 112 | } 113 | 114 | static void gic_init(void) 115 | { 116 | int i; 117 | 118 | if (!(cmgcr_read(GCR_GIC_STATUS) & GCR_GIC_EX)) 119 | return; 120 | 121 | cmgcr_write(GCR_GIC_BASE, CMGIC_BASE | GCR_GIC_EN); 122 | 123 | /* Interrupt 0..5: Level Trigger, Active High */ 124 | cmgic_rmw(GIC_SH_TRIG_BASE, 0x3f, 0); 125 | cmgic_rmw(GIC_SH_RMASK_BASE, 0, 0x3f); 126 | cmgic_rmw(GIC_SH_POL_BASE, 0, 0x3f); 127 | cmgic_rmw(GIC_SH_SMASK_BASE, 0, 0x3f); 128 | 129 | /* Interrupt 56..63: Edge Trigger, Rising Edge */ 130 | /* Hardcoded to set up the last 8 external interrupts for IPI. */ 131 | cmgic_rmw(GIC_SH_REG(GIC_SH_TRIG_BASE, 56), 0, 0xff << GIC_SH_BIT(56)); 132 | cmgic_rmw(GIC_SH_REG(GIC_SH_RMASK_BASE, 56), 0, 0xff << GIC_SH_BIT(56)); 133 | cmgic_rmw(GIC_SH_REG(GIC_SH_POL_BASE, 56), 0, 0xff << GIC_SH_BIT(56)); 134 | cmgic_rmw(GIC_SH_REG(GIC_SH_SMASK_BASE, 56), 0, 0xff << GIC_SH_BIT(56)); 135 | 136 | /* Map interrupt source to interrupt pin */ 137 | for (i = 0; i < ARRAY_SIZE(gic_map_pins); i++) 138 | cmgic_write(GIC_SH_MAP_PIN(gic_map_pins[i].src), GIC_MAP_TO_PIN | gic_map_pins[i].pin); 139 | 140 | /* Interrupt 31..0 map to VPE0 */ 141 | for (i = 0; i < 32; i++) 142 | cmgic_write(GIC_SH_MAP_VPE(i), 1); 143 | 144 | /* 145 | * Direct GIC_int 56..63 to vpe 0..3 146 | * MIPS Linux convention that last 16 interrupts implemented be set 147 | * aside for IPI signaling. 148 | * The actual interrupts are tied low and software sends interrupts 149 | * via GIC_SH_WEDGE writes. 150 | */ 151 | for (i = 0; i < 4; i++) { 152 | cmgic_write(GIC_SH_MAP_VPE(56 + i), 1 << i); 153 | cmgic_write(GIC_SH_MAP_VPE(60 + i), 1 << i); 154 | } 155 | } 156 | 157 | void mt7621_cps_init(void) 158 | { 159 | cm_init(); 160 | cpc_init(); 161 | gic_init(); 162 | } 163 | -------------------------------------------------------------------------------- /src/mt7621/stage2/dramc/.gitignore: -------------------------------------------------------------------------------- 1 | !mt7621_stage_sram.bin 2 | !mt7621_stage_sram_noprint.bin 3 | -------------------------------------------------------------------------------- /src/mt7621/stage2/dramc/dramc.S: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause */ 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Wrapper for MediaTek MT7621 DRAMC binary 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define DRAMC_BIN_LOADADDR 0xBE108800 14 | #define DRAMC_ACT_SIZE 0x60 15 | 16 | .align 2 17 | .section ".data.dramc_cpu_freq", "a" 18 | .type dramc_cpu_freq, @object 19 | .globl dramc_cpu_freq 20 | dramc_cpu_freq: 21 | .word 0 22 | .size dramc_cpu_freq, . - dramc_cpu_freq 23 | 24 | .align 2 25 | .section ".data.dramc_ddr_freq", "a" 26 | .type dramc_ddr_freq, @object 27 | .globl dramc_ddr_freq 28 | dramc_ddr_freq: 29 | .word 0 30 | .size dramc_ddr_freq, . - dramc_ddr_freq 31 | 32 | .align 2 33 | .section ".data.dramc_ddr2_act", "a" 34 | .type dramc_ddr2_act, @object 35 | .globl dramc_ddr2_act 36 | dramc_ddr2_act: 37 | .word 0 38 | .size dramc_ddr2_act, . - dramc_ddr2_act 39 | 40 | .align 2 41 | .section ".data.dramc_ddr3_act", "a" 42 | .type dramc_ddr3_act, @object 43 | .globl dramc_ddr3_act 44 | dramc_ddr3_act: 45 | .word 0 46 | .size dramc_ddr3_act, . - dramc_ddr3_act 47 | 48 | .align 2 49 | .section ".rodata.dramc_bin", "a" 50 | .type dramc_bin, @object 51 | dramc_bin: 52 | .incbin DRAMC_BIN_FILE 53 | .equ dramc_bin_size, . - dramc_bin 54 | .size dramc_bin, dramc_bin_size 55 | 56 | .text 57 | .set noreorder 58 | .set nomips16 59 | 60 | LEAFUNC(dramc_init) 61 | li $t0, 0xBE00001C 62 | li $t1, 0x0 63 | sw $t1, 0($t0) 64 | 65 | /* move code to SRAM */ 66 | la $t0, dramc_bin 67 | li $t1, DRAMC_BIN_LOADADDR 68 | li $t3, dramc_bin_size 69 | 70 | 1: 71 | lw $t2, 0($t0) 72 | sw $t2, 0($t1) 73 | addiu $t0, $t0, 4 74 | addiu $t1, $t1, 4 75 | subu $t3, $t3, 4 76 | bgtz $t3, 1b 77 | nop 78 | 79 | /* Override DDR2 AC timing settings */ 80 | la $t0, dramc_ddr2_act 81 | lw $t0, 0($t0) 82 | li $t1, DRAMC_BIN_LOADADDR + 0xc8 83 | li $t3, DRAMC_ACT_SIZE 84 | 85 | 1: 86 | lw $t2, 0($t0) 87 | sw $t2, 0($t1) 88 | addiu $t0, $t0, 4 89 | addiu $t1, $t1, 4 90 | subu $t3, $t3, 4 91 | bgtz $t3, 1b 92 | nop 93 | 94 | /* Override DDR3 AC timing settings */ 95 | la $t0, dramc_ddr3_act 96 | lw $t0, 0($t0) 97 | li $t1, DRAMC_BIN_LOADADDR + 0x60 98 | li $t3, DRAMC_ACT_SIZE 99 | 100 | 1: 101 | lw $t2, 0($t0) 102 | sw $t2, 0($t1) 103 | addiu $t0, $t0, 4 104 | addiu $t1, $t1, 4 105 | subu $t3, $t3, 4 106 | bgtz $t3, 1b 107 | nop 108 | 109 | /* Set CPU frequency */ 110 | la $t0, dramc_cpu_freq 111 | lw $t0, 0($t0) 112 | li $t1, DRAMC_BIN_LOADADDR + 0x20 113 | sw $t0, 0($t1) 114 | 115 | /* Set DDR frequency */ 116 | la $t0, dramc_ddr_freq 117 | lw $t0, 0($t0) 118 | li $t1, DRAMC_BIN_LOADADDR + 0x24 119 | sw $t0, 0($t1) 120 | 121 | /* Set baudrate */ 122 | la $t0, _baudrate 123 | lw $t0, 0($t0) 124 | li $t1, DRAMC_BIN_LOADADDR + 0x130 125 | sw $t0, 0($t1) 126 | 127 | /* Save return address */ 128 | li $t0, 0xBE10DFF0 129 | sw $ra, 0($t0) 130 | 131 | /* Invoke DRAMC bin */ 132 | li $t9, 0xBE108800 133 | jalr $t9 134 | nop 135 | 136 | /* Restore return address */ 137 | li $t0, 0xBE10DFF0 138 | lw $ra, 0($t0) 139 | 140 | jr $ra 141 | nop 142 | ENDFUNC(dramc_init) 143 | -------------------------------------------------------------------------------- /src/mt7621/stage2/dramc/mt7621_stage_sram.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackpascal/mt7621-boot-spi-nand/799379a3b0e71a3e549eff5db3e34631f4354a76/src/mt7621/stage2/dramc/mt7621_stage_sram.bin -------------------------------------------------------------------------------- /src/mt7621/stage2/dramc/mt7621_stage_sram_noprint.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackpascal/mt7621-boot-spi-nand/799379a3b0e71a3e549eff5db3e34631f4354a76/src/mt7621/stage2/dramc/mt7621_stage_sram_noprint.bin -------------------------------------------------------------------------------- /src/mt7621/stage2/entry.S: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause */ 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Entry for 2nd-stage 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | .text 16 | .set nomips16 17 | .set noreorder 18 | 19 | ENTRY(_start) 20 | EXPORT(stage2_info) 21 | b _start_real 22 | nop 23 | 24 | .org 0x08 25 | EXPORT(_load_addr) 26 | .word __copy_start 27 | EXPORT(_load_size) 28 | .word __prog_size 29 | EXPORT(_stage3_offset) 30 | #ifdef STAGE3_OFFSET 31 | .word STAGE3_OFFSET 32 | #else 33 | .word __stage3_offset 34 | #endif 35 | EXPORT(_baudrate) 36 | .word BAUDRATE 37 | EXPORT(_unused) 38 | .word 1 39 | EXPORT(_dramc_cpu_freq) 40 | .word 880 41 | EXPORT(_dramc_ddr_freq) 42 | .word 1 43 | EXPORT(_dramc_init_type) 44 | .word 0 45 | EXPORT(_dramc_ddr2_act_sel) 46 | .word 2 47 | EXPORT(_dramc_ddr3_act_sel) 48 | .word 2 49 | EXPORT(_dramc_ddr2_act) 50 | .word 0, 0, 0, 0, 0, 0, 0, 0 51 | .word 0, 0, 0, 0, 0, 0, 0, 0 52 | .word 0, 0, 0, 0, 0, 0, 0, 0 53 | EXPORT(_dramc_ddr3_act) 54 | .word 0, 0, 0, 0, 0, 0, 0, 0 55 | .word 0, 0, 0, 0, 0, 0, 0, 0 56 | .word 0, 0, 0, 0, 0, 0, 0, 0 57 | 58 | _start_real: 59 | /* Clear BSS section */ 60 | la $a0, __bss_start 61 | la $a1, __bss_end 62 | 63 | 1: bge $a0, $a1, 2f 64 | nop 65 | 66 | sw $0, 0($a0) 67 | addiu $a0, 4 68 | b 1b 69 | nop 70 | 2: 71 | 72 | /* Setup initial stack */ 73 | li $sp, 0xbe10dff0 74 | 75 | /* Pre-initialization */ 76 | la $t9, mt7621_stage2_pre_init 77 | jalr $t9 78 | nop 79 | 80 | /* Set MPLL from CR */ 81 | li $t0, PALMBUS_BASE 82 | lw $t1, (SYSCTL_CLKCFG0 - PALMBUS_BASE)($t0) 83 | li $t2, MPLL_CFG_SEL 84 | or $t1, $t1, $t2 85 | sw $t1, (SYSCTL_CLKCFG0 - PALMBUS_BASE)($t0) 86 | 87 | /* Initialize DRAM & CPU */ 88 | bal dramc_init 89 | nop 90 | 91 | /* Set CPU clock from CPLL */ 92 | li $t0, PALMBUS_BASE 93 | lw $t1, (SYSCTL_CLKCFG0 - PALMBUS_BASE)($t0) 94 | li $t2, 1 95 | ins $t1, $t2, 30, 2 96 | sw $t1, (SYSCTL_CLKCFG0 - PALMBUS_BASE)($t0) 97 | 98 | /* Move stage2 code from locked L2-cache to DRAM */ 99 | bal self_solidify 100 | nop 101 | 102 | /* Release FE SRAM */ 103 | li $t0, PALMBUS_BASE 104 | li $t0, FE_BASE 105 | li $t1, 1 106 | sw $t1, FE_RST_GLO($t0) 107 | 108 | /* Setup final stack */ 109 | li $sp, 0x86000000 110 | 111 | /* Continue to stage2 common routine */ 112 | la $t9, stage2_main 113 | jr $t9 114 | nop 115 | ENDFUNC(_start) 116 | 117 | LEAFUNC(self_solidify) 118 | la $a0, __copy_start 119 | la $a1, __prog_end 120 | 121 | li $v1, ~(4 - 1) 122 | and $a0, $a0, $v1 123 | 124 | addiu $a1, 4 - 1 125 | and $a1, $a1, $v1 126 | 127 | li $a2, KSEG1 128 | ins $a2, $a0, 0, 29 129 | 130 | 1: lw $a3, 0($a0) 131 | sw $a3, 0($a2) 132 | addiu $a0, 4 133 | addiu $a2, 4 134 | bne $a0, $a1, 1b 135 | nop 136 | 137 | /* Set KSEG0 to Uncached */ 138 | mfc0 $t0, CP0_CONFIG 139 | ins $t0, $0, 0, 3 140 | ori $t0, $t0, CONF_CM_UNCACHED 141 | mtc0 $t0, CP0_CONFIG 142 | ehb 143 | 144 | /* Invalidate L2 Cache */ 145 | move $a0, $0 146 | li $a1, L2_CACHE_SIZE 147 | 148 | mtc0 $0, CP0_STAGLO 149 | 150 | 1: 151 | cache INDEX_STORE_TAG_SD, 0($a0) 152 | addiu $a0, $a0, L2_CACHE_LINESIZE 153 | bne $a0, $a1, 1b 154 | nop 155 | 156 | /* Set KSEG0 to Cachable */ 157 | mfc0 $t0, CP0_CONFIG 158 | ins $t0, $0, 0, 3 159 | ori $t0, $t0, CONF_CM_CACHABLE_COW 160 | mtc0 $t0, CP0_CONFIG 161 | ehb 162 | 163 | jr $ra 164 | nop 165 | ENDFUNC(self_solidify) 166 | -------------------------------------------------------------------------------- /src/mt7621/stage2/target.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Low-level initialization code for MediaTek MT7621 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | struct mt7621_stage2_info { 23 | struct stage2_header hdr; 24 | uint32_t stage3_offset; 25 | uint32_t baudrate; 26 | uint32_t unused; 27 | uint32_t dramc_cpu_freq; 28 | uint32_t dramc_ddr_freq; 29 | uint32_t dramc_init_type; 30 | uint32_t dramc_ddr2_act_sel; 31 | uint32_t dramc_ddr3_act_sel; 32 | ddr_ac_timing_param_t dramc_ddr2_act; 33 | ddr_ac_timing_param_t dramc_ddr3_act; 34 | }; 35 | 36 | extern const struct mt7621_stage2_info stage2_info; 37 | extern uint32_t dramc_cpu_freq; 38 | extern uint32_t dramc_ddr_freq; 39 | extern const ddr_ac_timing_param_t *dramc_ddr2_act; 40 | extern const ddr_ac_timing_param_t *dramc_ddr3_act; 41 | 42 | static void set_final_timer_freq(void); 43 | static void config_usb_xhci(void); 44 | 45 | static const ddr_ac_timing_param_t ddr2_act[] = { 46 | [DDR2_512M] = { 47 | 0xAA00AA00, 0xAA00AA00, 0x00000007, 0x22174441, 48 | 0x00000000, 0xF0748661, 0x40001273, 0x9F0A0481, 49 | 0x0304692F, 0x15602842, 0x00008888, 0x88888888, 50 | 0x00000000, 0x00000000, 0x00000000, 0x07100000, 51 | 0x00001B63, 0x00002000, 0x00004000, 0x00006000, 52 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 53 | }, 54 | [DDR2_W9751G6KB_A02_1066_512M] = { 55 | 0xAA00AA00, 0xAA00AA00, 0x00000007, 0x33484584, 56 | 0x00000000, 0xF07486A1, 0x50001273, 0x9F010481, 57 | 0x0304693F, 0x15602842, 0x00008888, 0x88888888, 58 | 0x00000000, 0x00000000, 0x00000010, 0x07100000, 59 | 0x00001F73, 0x00002000, 0x00004000, 0x00006000, 60 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 61 | }, 62 | [DDR2_1024M] = { 63 | 0xAA00AA00, 0xAA00AA00, 0x00000007, 0x22174441, 64 | 0x01000000, 0xF0748661, 0x40001273, 0x9F0F0481, 65 | 0x0304692F, 0x15602842, 0x00008888, 0x88888888, 66 | 0x00000000, 0x00000000, 0x00000000, 0x07100000, 67 | 0x00001B63, 0x00002000, 0x00004000, 0x00006000, 68 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 69 | }, 70 | [DDR2_W971GG6KB25_800_1024M] = { 71 | 0xAA00AA00, 0xAA00AA00, 0x00000007, 0x22174430, 72 | 0x01000000, 0xF0748661, 0x40001273, 0x9F0F0481, 73 | 0x0304692F, 0x15602842, 0x00008888, 0x88888888, 74 | 0x00000000, 0x00000000, 0x00000000, 0x07100000, 75 | 0x00001B63, 0x00002000, 0x00004000, 0x00006000, 76 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 77 | }, 78 | [DDR2_W971GG6KB18_1066_1024M] = { 79 | 0xAA00AA00, 0xAA00AA00, 0x00000007, 0x33484584, 80 | 0x01000000, 0xF07486A1, 0x50001273, 0x9F070481, 81 | 0x0304693F, 0x15602842, 0x00008888, 0x88888888, 82 | 0x00000000, 0x00000000, 0x00000010, 0x07100000, 83 | 0x00001F73, 0x00002000, 0x00004000, 0x00006000, 84 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 85 | } 86 | }; 87 | 88 | static const ddr_ac_timing_param_t ddr3_act[] = { 89 | [DDR3_1024M] = { 90 | 0xAA00AA00, 0xAA00AA00, 0x00000007, 0x44694683, 91 | 0x01000000, 0xF07486A1, 0xC287221D, 0x9F060481, 92 | 0x03046948, 0x15602842, 0x00008888, 0x88888888, 93 | 0x00000000, 0x00000000, 0x00000210, 0x07100000, 94 | 0x00001B61, 0x00002040, 0x00004010, 0x00006000, 95 | 0x0C000000, 0x07070000, 0x00000000, 0x00000000, 96 | }, 97 | [DDR3_1024M_KGD] = { 98 | 0xAA00AA00, 0xAA00AA00, 0x00000007, 0x44694673, 99 | 0x01000000, 0xF07486A1, 0xC287221D, 0x9F050481, 100 | 0x03046948, 0x15602842, 0x00008888, 0x88888888, 101 | 0x00000000, 0x00000000, 0x00000220, 0x07100000, 102 | 0x00001B61, 0x00002040, 0x00004010, 0x00006000, 103 | 0x0C000000, 0x07070000, 0x00000000, 0x00000000, 104 | }, 105 | [DDR3_2048M] = { 106 | 0xAA00AA00, 0xAA00AA00, 0x00000007, 0x44694683, 107 | 0x01000000, 0xF07486A1, 0xC287221D, 0x9F0F0481, 108 | 0x03046948, 0x15602842, 0x00008888, 0x88888888, 109 | 0x00000000, 0x00000000, 0x00000240, 0x07100000, 110 | 0x00001B61, 0x00002040, 0x00004010, 0x00006000, 111 | 0x0C000000, 0x07070000, 0x00000000, 0x00000000, 112 | }, 113 | [DDR3_4096M] = { 114 | 0xFF00FF00, 0xFF00FF00, 0x00000007, 0x44694683, 115 | 0x01000000, 0xF07406A1, 0xC287221D, 0x9F060481, 116 | 0x03046923, 0x152f2842, 0x00008888, 0x88888888, 117 | 0x00000000, 0x00000000, 0x00000210, 0x07100000, 118 | 0x00001B61, 0x00002040, 0x00004010, 0x00006000, 119 | 0x0C000000, 0x07070000, 0x000C0000, 0x00000000, 120 | } 121 | }; 122 | 123 | static const uint32_t xtal_div_tbl[] = {0, 1, 2, 2}; 124 | 125 | static uint32_t bus_freq; 126 | 127 | void mt7621_stage2_pre_init(void) 128 | { 129 | uint32_t syscfg0, dram_type, cpu_freq, xtal_freq, xtal_div, cpu_clk_fb; 130 | 131 | mt7621_cps_init(); 132 | 133 | serial_init(); 134 | 135 | /* DRAM type: 0 for DDR3, 1 for DDR2 */ 136 | syscfg0 = reg_read32(SYSCTL_SYSCFG0); 137 | dram_type = (syscfg0 & DRAM_TYPE) ? MT7621_DDR2 : MT7621_DDR3; 138 | 139 | /* Base clock used for MPLL */ 140 | switch ((syscfg0 & XTAL_MODE_SEL_M) >> XTAL_MODE_SEL_S) { 141 | case 0: 142 | case 1: 143 | case 2: 144 | xtal_freq = 20; 145 | xtal_div = 0; 146 | break; 147 | case 3: 148 | case 4: 149 | case 5: 150 | xtal_freq = 40; 151 | xtal_div = 1; 152 | break; 153 | default: 154 | xtal_freq = 25; 155 | xtal_div = 0; 156 | } 157 | 158 | /* Select DRAMC parameters */ 159 | cpu_freq = stage2_info.dramc_cpu_freq; 160 | if (cpu_freq < 400 || cpu_freq > 1200) { 161 | printf("CPU clock %uMHz is invalid, restoring to default 880MHz\n", 162 | cpu_freq); 163 | cpu_freq = 880; 164 | } 165 | 166 | cpu_clk_fb = cpu_freq * (1 << xtal_div_tbl[xtal_div]) / xtal_freq - 1; 167 | dramc_cpu_freq = 0xc0004802 | (cpu_clk_fb << CPLL_FBDIV_S) | 168 | (xtal_div << CPLL_PREDIV_S); 169 | 170 | if (stage2_info.dramc_ddr_freq == 1) { 171 | if (dram_type == MT7621_DDR3) { 172 | dramc_ddr_freq = 0x11000000; 173 | } else { 174 | puts("1200MHz is not valid for DDR2, restoring to default 800MHz"); 175 | dramc_ddr_freq = 0x31000000; 176 | } 177 | } else if (stage2_info.dramc_ddr_freq == 2) { 178 | dramc_ddr_freq = 0x21000000; 179 | } else if (stage2_info.dramc_ddr_freq == 3) { 180 | dramc_ddr_freq = 0x31000000; 181 | } else if (stage2_info.dramc_ddr_freq == 4) { 182 | dramc_ddr_freq = 0x41000000; 183 | } else { 184 | printf("DDR clock option %u is invalid, restoring to default 800MHz\n", 185 | stage2_info.dramc_ddr_freq); 186 | dramc_ddr_freq = 0x31000000; 187 | } 188 | 189 | if (stage2_info.dramc_init_type == DDR_INIT_PRE_DEFINED_FIRST) { 190 | if (stage2_info.dramc_ddr2_act_sel >= __DDR2_ACT_MAX) { 191 | printf("DDR2 AC timing option %u is invalid, restoring to default 128MB\n", 192 | stage2_info.dramc_ddr2_act_sel); 193 | dramc_ddr2_act = &ddr2_act[DDR2_1024M]; 194 | } else { 195 | dramc_ddr2_act = &ddr2_act[stage2_info.dramc_ddr2_act_sel]; 196 | } 197 | 198 | if (stage2_info.dramc_ddr3_act_sel >= __DDR3_ACT_MAX) { 199 | printf("DDR3 AC timing option %u is invalid, restoring to default 256MB\n", 200 | stage2_info.dramc_ddr3_act_sel); 201 | dramc_ddr3_act = &ddr3_act[DDR3_2048M]; 202 | } else { 203 | dramc_ddr3_act = &ddr3_act[stage2_info.dramc_ddr3_act_sel]; 204 | } 205 | } else { 206 | dramc_ddr2_act = &stage2_info.dramc_ddr2_act; 207 | dramc_ddr3_act = &stage2_info.dramc_ddr3_act; 208 | } 209 | } 210 | 211 | void target_init(void) 212 | { 213 | uint32_t memsize; 214 | 215 | memsize = get_mem_size(KSEG1, 512 << 20); 216 | if (memsize == 512 << 20) 217 | memsize = 448 << 20; 218 | 219 | set_meminfo(KSEG0, memsize); 220 | 221 | set_final_timer_freq(); 222 | 223 | /* USB XHCI init */ 224 | config_usb_xhci(); 225 | 226 | /* SPI init */ 227 | spi_init(); 228 | 229 | /* IMPORTANT: SPI clock must not be greater than 20MHz */ 230 | spi_set_clock(bus_freq, 20000000); 231 | 232 | set_stage3_offset(stage2_info.stage3_offset); 233 | } 234 | 235 | static void set_final_timer_freq(void) 236 | { 237 | uint32_t bs, xtal_sel, clkcfg0, cur_clk, mempll18, dividx, fb; 238 | uint32_t xtal_clk, xtal_div, ffiv, ffrac, cpu_clk; 239 | const static uint32_t xtal_div_tbl[] = {0, 1, 2, 2}; 240 | 241 | bs = reg_read32(SYSCTL_SYSCFG0); 242 | clkcfg0 = reg_read32(SYSCTL_CLKCFG0); 243 | cur_clk = reg_read32(SYSCTL_CUR_CLK_STS); 244 | 245 | xtal_sel = (bs & XTAL_MODE_SEL_M) >> XTAL_MODE_SEL_S; 246 | 247 | if (xtal_sel <= 2) 248 | xtal_clk = 20 * 1000 * 1000; 249 | else if (xtal_sel <= 5) 250 | xtal_clk = 40 * 1000 * 1000; 251 | else 252 | xtal_clk = 25 * 1000 * 1000; 253 | 254 | switch ((clkcfg0 & CPU_CLK_SEL_M) >> CPU_CLK_SEL_S) { 255 | case 0: 256 | cpu_clk = 500 * 1000 * 1000; 257 | break; 258 | case 1: 259 | mempll18 = reg_read32(DRAMC_CPLL_REG); 260 | dividx = (mempll18 & CPLL_PREDIV_M) >> CPLL_PREDIV_S; 261 | fb = (mempll18 & CPLL_FBDIV_M) >> CPLL_FBDIV_S; 262 | xtal_div = 1 << xtal_div_tbl[dividx]; 263 | cpu_clk = (fb + 1) * xtal_clk / xtal_div; 264 | break; 265 | default: 266 | cpu_clk = xtal_clk; 267 | } 268 | 269 | ffiv = (cur_clk & CUR_CPU_FDIV_M) >> CUR_CPU_FDIV_S; 270 | ffrac = (cur_clk & CUR_CPU_FFRAC_M) >> CUR_CPU_FFRAC_S; 271 | cpu_clk = cpu_clk / ffiv * ffrac; 272 | 273 | bus_freq = cpu_clk / 4; 274 | 275 | set_timer_freq(cpu_clk / 2); 276 | } 277 | 278 | static void config_usb_xhci(void) 279 | { 280 | uint32_t syscfg0; 281 | 282 | syscfg0 = reg_read32(SYSCTL_SYSCFG0); 283 | 284 | switch ((syscfg0 & XTAL_MODE_SEL_M) >> XTAL_MODE_SEL_S) { 285 | case 0: 286 | case 1: 287 | case 2: 288 | break; 289 | case 3: 290 | case 4: 291 | case 5: 292 | reg_write32(0xbe1d0784, 0x20201a); 293 | reg_write32(0xbe1d0c20, 0x80104); 294 | reg_write32(0xbe1d0c1c, 0x1818181e); 295 | reg_write32(0xbe1d0c24, 0x1e400000); 296 | reg_write32(0xbe1d0c38, 0x250073); 297 | reg_write32(0xbe1d0c40, 0x71004a); 298 | reg_write32(0xbe1d0b24, 0x140); 299 | reg_write32(0xbe1d0b10, 0x23800000); 300 | reg_write32(0xbe1d0b04, 0x20000005); 301 | reg_write32(0xbe1d0b08, 0x12203200); 302 | reg_write32(0xbe1d0b2c, 0x1400028); 303 | reg_write32(0xbe1d0a40, 0xffff0001); 304 | reg_write32(0xbe1d0a44, 0x60001); 305 | break; 306 | default: 307 | reg_write32(0xbe1d0784, 0x20201a); 308 | reg_write32(0xbe1d0c20, 0x80004); 309 | reg_write32(0xbe1d0c1c, 0x18181819); 310 | reg_write32(0xbe1d0c24, 0x18000000); 311 | reg_write32(0xbe1d0c38, 0x25004a); 312 | reg_write32(0xbe1d0c40, 0x48004a); 313 | reg_write32(0xbe1d0b24, 0x190); 314 | reg_write32(0xbe1d0b10, 0x1c000000); 315 | reg_write32(0xbe1d0b04, 0x20000004); 316 | reg_write32(0xbe1d0b08, 0xf203200); 317 | reg_write32(0xbe1d0b2c, 0x1400028); 318 | reg_write32(0xbe1d0a40, 0xffff0001); 319 | reg_write32(0xbe1d0a44, 0x60001); 320 | } 321 | } 322 | -------------------------------------------------------------------------------- /src/mt7621/target.mk: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | # Copyright (C) 2020 Weijie Gao 3 | 4 | COBJS += $(TARGET)/serial.o \ 5 | $(TARGET)/spi.o 6 | 7 | include $(TARGET)/$(STAGE)/build.mk 8 | 9 | LDFLAGS += -Wl,-Ttext,$(TEXT_BASE) 10 | CFLAGS += -march=mips32r2 -mtune=1004kc -msoft-float -EL -fno-PIC -fno-PIE -mno-abicalls -mips16 11 | CPPFLAGS += -I$(TARGET)/include -DTEXT_BASE=$(TEXT_BASE) 12 | CROSS_COMPILE ?= mipsel-linux- 13 | -------------------------------------------------------------------------------- /src/stage1/console.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Simple console implementation 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | static const char hexchars[] = "0123456789abcdef"; 12 | 13 | void putc(char c) 14 | { 15 | serial_putc(c); 16 | } 17 | 18 | void puts(const char *s) 19 | { 20 | while (*s) { 21 | if (*s == '\n') 22 | putc('\r'); 23 | putc(*s++); 24 | } 25 | } 26 | 27 | void print_dec(uint32_t n) 28 | { 29 | uint8_t chs[10]; 30 | uint32_t t = 0; 31 | 32 | if (!n) { 33 | putc('0'); 34 | return; 35 | } 36 | 37 | while (n) { 38 | chs[t++] = n % 10; 39 | n /= 10; 40 | } 41 | 42 | while (t) { 43 | putc('0' + chs[t - 1]); 44 | t--; 45 | } 46 | } 47 | 48 | void print_hex(uint32_t n, uint32_t padding) 49 | { 50 | if (n) 51 | print_hex(n >> 4, padding); 52 | else 53 | return; 54 | 55 | putc(hexchars[n & 0xf]); 56 | } 57 | 58 | void print_hex2(uint8_t n) 59 | { 60 | putc(hexchars[(n >> 4) & 0xf]); 61 | putc(hexchars[n & 0xf]); 62 | } 63 | -------------------------------------------------------------------------------- /src/stage1/main.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * 1st-stage main routine 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | static void load_stage2(void); 15 | 16 | void __noreturn stage1_main(void) 17 | { 18 | target_init(); 19 | 20 | puts("Bootcode for Micron SPI-NAND [Version 1.0]\n"); 21 | puts("Copyright (C) 2019 Weijie Gao \n"); 22 | puts("\n"); 23 | 24 | spi_nand_init(); 25 | load_stage2(); 26 | 27 | unreachable(); 28 | } 29 | 30 | static void load_stage2(void) 31 | { 32 | struct stage2_header s2h; 33 | uint32_t addr, end, pa, ca; 34 | uintptr_t dstaddr; 35 | 36 | addr = get_stage2_offset() & ~(PAGESIZE - 1); 37 | 38 | spi_nand_addr_to_pa_ca(addr, &pa, &ca); 39 | spi_nand_read_page_to_cache(pa); 40 | 41 | spi_nand_read_page_cache(ca, &s2h, sizeof(s2h)); 42 | 43 | target_stage2_pre_setup(s2h.loadaddr, s2h.size); 44 | 45 | dstaddr = s2h.loadaddr; 46 | end = (addr + s2h.size + PAGESIZE - 1) & ~(PAGESIZE - 1); 47 | 48 | do { 49 | target_stage2_data_process(dstaddr, ca); 50 | 51 | dstaddr += PAGESIZE; 52 | addr += PAGESIZE; 53 | if (addr >= end) 54 | break; 55 | 56 | spi_nand_addr_to_pa_ca(addr, &pa, &ca); 57 | spi_nand_read_page_to_cache(pa); 58 | } while (1); 59 | 60 | spi_nand_read_page_to_cache(0); 61 | 62 | target_stage2_post_setup(s2h.loadaddr, s2h.size); 63 | } 64 | -------------------------------------------------------------------------------- /src/stage1/spi-nand.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Simple SPI-NAND driver for 1st-stage 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #define SPI_NAND_CMD_READ_CACHE 0x03 18 | #define SPI_NAND_CMD_GET_FEATURE 0x0f 19 | #define SPI_NAND_CMD_READ_PAGE_TO_CACHE 0x13 20 | #define SPI_NAND_CMD_SET_FEATURE 0x1f 21 | #define SPI_NAND_CMD_RESET 0xff 22 | 23 | #define SPI_NAND_FEATURE_CONFIG_ADDR 0xb0 24 | #define SPI_NAND_CR_BIT_ECCEN 0x10 25 | 26 | #define SPI_NAND_FEATURE_STATUS 0xc0 27 | #define SPI_NAND_SR_BIT_OIP 0x01 28 | 29 | #define SPI_NAND_TIMING_RESET 1000 30 | 31 | #define PLANEBIT ((PAGESIZE) << 1) 32 | 33 | static void spi_nand_reset(void) 34 | { 35 | uint8_t op = SPI_NAND_CMD_RESET; 36 | 37 | spi_en(); 38 | spi_write(&op, 1); 39 | spi_dis(); 40 | 41 | udelay(SPI_NAND_TIMING_RESET); 42 | } 43 | 44 | static uint8_t spi_nand_get_feature(uint8_t addr) 45 | { 46 | uint8_t op[2] = { SPI_NAND_CMD_GET_FEATURE, addr }; 47 | uint8_t val; 48 | 49 | spi_en(); 50 | spi_write(op, sizeof(op)); 51 | spi_read(&val, 1); 52 | spi_dis(); 53 | 54 | return val; 55 | } 56 | 57 | static void spi_nand_set_feature(uint8_t addr, uint8_t val) 58 | { 59 | uint8_t op[3] = { SPI_NAND_CMD_SET_FEATURE, addr, val }; 60 | 61 | spi_en(); 62 | spi_write(op, sizeof(op)); 63 | spi_dis(); 64 | } 65 | 66 | static void spi_nand_enable_ecc(void) 67 | { 68 | uint8_t val; 69 | 70 | val = spi_nand_get_feature(SPI_NAND_FEATURE_CONFIG_ADDR); 71 | val |= SPI_NAND_CR_BIT_ECCEN; 72 | spi_nand_set_feature(SPI_NAND_FEATURE_CONFIG_ADDR, val); 73 | } 74 | 75 | static void spi_nand_poll(void) 76 | { 77 | uint8_t op[2] = { SPI_NAND_CMD_GET_FEATURE, SPI_NAND_FEATURE_STATUS }; 78 | uint8_t val; 79 | 80 | while (1) { 81 | spi_en(); 82 | spi_write(op, sizeof(op)); 83 | spi_read(&val, sizeof(val)); 84 | spi_dis(); 85 | 86 | if ((val & SPI_NAND_SR_BIT_OIP) == 0) 87 | break; 88 | } 89 | } 90 | 91 | void spi_nand_init(void) 92 | { 93 | spi_nand_reset(); 94 | spi_nand_enable_ecc(); 95 | } 96 | 97 | void spi_nand_addr_to_pa_ca(uint32_t addr, uint32_t *pa, uint32_t *ca) 98 | { 99 | *pa = addr / PAGESIZE; 100 | *ca = addr & (PAGESIZE - 1); 101 | 102 | if ((addr / BLOCKSIZE) & 1) 103 | *ca |= PLANEBIT; 104 | } 105 | 106 | void spi_nand_read_page_to_cache(uint32_t pa) 107 | { 108 | uint8_t op[4]; 109 | 110 | op[0] = SPI_NAND_CMD_READ_PAGE_TO_CACHE; 111 | op[1] = (pa >> 16) & 0xff; 112 | op[2] = (pa >> 8) & 0xff; 113 | op[3] = pa & 0xff; 114 | 115 | spi_en(); 116 | spi_write(op, sizeof(op)); 117 | spi_dis(); 118 | 119 | spi_nand_poll(); 120 | } 121 | 122 | void spi_nand_read_page_cache(uint32_t ca, void *buf, uint32_t len) 123 | { 124 | uint8_t op[4]; 125 | 126 | op[0] = SPI_NAND_CMD_READ_CACHE; 127 | op[1] = 0; 128 | op[2] = (ca >> 8) & 0xff; 129 | op[3] = ca & 0xff; 130 | 131 | spi_en(); 132 | spi_write(op, sizeof(op)); 133 | spi_read(buf, len); 134 | spi_dis(); 135 | } 136 | 137 | static void spi_nand_read_page(uint32_t addr, void *buf, uint32_t len) 138 | { 139 | uint32_t pa, ca; 140 | 141 | spi_nand_addr_to_pa_ca(addr, &pa, &ca); 142 | 143 | spi_nand_read_page_to_cache(pa); 144 | spi_nand_read_page_cache(ca, buf, len); 145 | } 146 | 147 | void spi_nand_load(uint32_t addr, void *buf, uint32_t len, void *page_cache) 148 | { 149 | uint32_t chksz, leading; 150 | uint32_t off = addr, curr_addr; 151 | uint8_t *ptr = buf; 152 | 153 | while (len) { 154 | leading = off & (PAGESIZE - 1); 155 | chksz = PAGESIZE - leading; 156 | if (chksz > len) 157 | chksz = len; 158 | 159 | curr_addr = off & (~(PAGESIZE - 1)); 160 | spi_nand_read_page(curr_addr, page_cache, PAGESIZE); 161 | 162 | memcpy(ptr, page_cache + leading, chksz); 163 | 164 | off += chksz; 165 | ptr += chksz; 166 | len -= chksz; 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/stage1/stage.mk: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | # Copyright (C) 2020 Weijie Gao 3 | 4 | CFLAGS += -flto 5 | 6 | CPPFLAGS += -DPAGESIZE=$(PAGESIZE) -DBLOCKSIZE=$(BLOCKSIZE) 7 | 8 | COBJS += stage1/main.o \ 9 | stage1/timer.o \ 10 | stage1/console.o \ 11 | stage1/spi-nand.o 12 | 13 | BIN_OUT := $(OUTDIR)/$(STAGE)-pad.bin 14 | 15 | all: $(OUTDIR)/$(STAGE)-pad.bin 16 | 17 | cmd_page_pad = $(TOOLS_DIR)/padutil -a $(PAGESIZE) -m $(PAGESIZE) $< $@ 18 | 19 | $(OUTDIR)/$(STAGE)-pad.bin: $(OUTDIR)/$(STAGE).bin FORCE 20 | $(call if_changed,page_pad) 21 | -------------------------------------------------------------------------------- /src/stage1/timer.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Simple delay timer for MIPS platform 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | static uint32_t timer_freq; 12 | 13 | static uint32_t __nomips16 get_ticks(void) 14 | { 15 | uint32_t val; 16 | 17 | asm volatile ("mfc0\t%0,$9" : "=r"(val)); 18 | 19 | return val; 20 | } 21 | 22 | void udelay(uint32_t usec) 23 | { 24 | uint32_t cp0_count; 25 | uint32_t t_delay, t_expire; 26 | 27 | cp0_count = get_ticks(); 28 | t_delay = usec * (timer_freq / 1000000); 29 | 30 | if (~cp0_count < t_delay) { 31 | t_expire = t_delay - ~cp0_count; 32 | while (get_ticks() > t_expire); 33 | } else { 34 | t_expire = cp0_count + t_delay; 35 | while (get_ticks() < t_expire); 36 | } 37 | } 38 | 39 | void set_timer_freq(uint32_t freq) 40 | { 41 | timer_freq = freq; 42 | } 43 | -------------------------------------------------------------------------------- /src/stage2/console.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | void putc(char c) 10 | { 11 | serial_putc(c); 12 | } 13 | 14 | void puts(const char *s) 15 | { 16 | while (*s) { 17 | if (*s == '\n') 18 | putc('\r'); 19 | putc(*s++); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/stage2/div64.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. 3 | * Copyright (c) 2014 Mellanox Technologies, Ltd. All rights reserved. 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice unmodified, this list of conditions, and the following 11 | * disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 | * 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 | 30 | uint32_t __div64_32(uint64_t *n, uint32_t base) 31 | { 32 | uint64_t rem = *n; 33 | uint64_t b = base; 34 | uint64_t res, d = 1; 35 | uint32_t high = rem >> 32; 36 | 37 | /* Reduce the thing a bit first */ 38 | res = 0; 39 | if (high >= base) { 40 | high /= base; 41 | res = (uint64_t)high << 32; 42 | rem -= (uint64_t)(high * base) << 32; 43 | } 44 | 45 | while ((int64_t)b > 0 && b < rem) { 46 | b = b + b; 47 | d = d + d; 48 | } 49 | 50 | do { 51 | if (rem >= b) { 52 | rem -= b; 53 | res += d; 54 | } 55 | b >>= 1; 56 | d >>= 1; 57 | } while (d); 58 | 59 | *n = res; 60 | return rem; 61 | } 62 | -------------------------------------------------------------------------------- /src/stage2/lshr64.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Implementation for 64-bit logical right shift 6 | */ 7 | 8 | #include 9 | 10 | uint64_t __lshr64(uint64_t val, uint32_t sh) 11 | { 12 | uint32_t hi, lo; 13 | 14 | hi = val >> 32; 15 | lo = val & 0xffffffff; 16 | 17 | if (!hi) 18 | return lo >> sh; 19 | 20 | if (sh >= 32) 21 | return hi >> (sh - 32); 22 | 23 | if (!sh) 24 | return val; 25 | 26 | return ((uint64_t)(hi >> sh) << 32) | (hi << (32 - sh)) | (lo >> sh); 27 | } 28 | -------------------------------------------------------------------------------- /src/stage2/lzma/LzmaDec.c: -------------------------------------------------------------------------------- 1 | /* LzmaDec.c -- LZMA Decoder 2 | 2009-09-20 : Igor Pavlov : Public domain */ 3 | 4 | #include "LzmaDec.h" 5 | 6 | #define kNumTopBits 24 7 | #define kTopValue ((UInt32)1 << kNumTopBits) 8 | 9 | #define kNumBitModelTotalBits 11 10 | #define kBitModelTotal (1 << kNumBitModelTotalBits) 11 | #define kNumMoveBits 5 12 | 13 | #define RC_INIT_SIZE 5 14 | 15 | #define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } 16 | 17 | #define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) 18 | #define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); 19 | #define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); 20 | #define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \ 21 | { UPDATE_0(p); i = (i + i); A0; } else \ 22 | { UPDATE_1(p); i = (i + i) + 1; A1; } 23 | #define GET_BIT(p, i) GET_BIT2(p, i, ; , ;) 24 | 25 | #define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); } 26 | #define TREE_DECODE(probs, limit, i) \ 27 | { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; } 28 | 29 | /* #define _LZMA_SIZE_OPT */ 30 | 31 | #ifdef _LZMA_SIZE_OPT 32 | #define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i) 33 | #else 34 | #define TREE_6_DECODE(probs, i) \ 35 | { i = 1; \ 36 | TREE_GET_BIT(probs, i); \ 37 | TREE_GET_BIT(probs, i); \ 38 | TREE_GET_BIT(probs, i); \ 39 | TREE_GET_BIT(probs, i); \ 40 | TREE_GET_BIT(probs, i); \ 41 | TREE_GET_BIT(probs, i); \ 42 | i -= 0x40; } 43 | #endif 44 | 45 | #define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } 46 | 47 | #define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) 48 | #define UPDATE_0_CHECK range = bound; 49 | #define UPDATE_1_CHECK range -= bound; code -= bound; 50 | #define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \ 51 | { UPDATE_0_CHECK; i = (i + i); A0; } else \ 52 | { UPDATE_1_CHECK; i = (i + i) + 1; A1; } 53 | #define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;) 54 | #define TREE_DECODE_CHECK(probs, limit, i) \ 55 | { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; } 56 | 57 | 58 | #define kNumPosBitsMax 4 59 | #define kNumPosStatesMax (1 << kNumPosBitsMax) 60 | 61 | #define kLenNumLowBits 3 62 | #define kLenNumLowSymbols (1 << kLenNumLowBits) 63 | #define kLenNumMidBits 3 64 | #define kLenNumMidSymbols (1 << kLenNumMidBits) 65 | #define kLenNumHighBits 8 66 | #define kLenNumHighSymbols (1 << kLenNumHighBits) 67 | 68 | #define LenChoice 0 69 | #define LenChoice2 (LenChoice + 1) 70 | #define LenLow (LenChoice2 + 1) 71 | #define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits)) 72 | #define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) 73 | #define kNumLenProbs (LenHigh + kLenNumHighSymbols) 74 | 75 | 76 | #define kNumStates 12 77 | #define kNumLitStates 7 78 | 79 | #define kStartPosModelIndex 4 80 | #define kEndPosModelIndex 14 81 | #define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) 82 | 83 | #define kNumPosSlotBits 6 84 | #define kNumLenToPosStates 4 85 | 86 | #define kNumAlignBits 4 87 | #define kAlignTableSize (1 << kNumAlignBits) 88 | 89 | #define kMatchMinLen 2 90 | #define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols) 91 | 92 | #define IsMatch 0 93 | #define IsRep (IsMatch + (kNumStates << kNumPosBitsMax)) 94 | #define IsRepG0 (IsRep + kNumStates) 95 | #define IsRepG1 (IsRepG0 + kNumStates) 96 | #define IsRepG2 (IsRepG1 + kNumStates) 97 | #define IsRep0Long (IsRepG2 + kNumStates) 98 | #define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax)) 99 | #define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) 100 | #define Align (SpecPos + kNumFullDistances - kEndPosModelIndex) 101 | #define LenCoder (Align + kAlignTableSize) 102 | #define RepLenCoder (LenCoder + kNumLenProbs) 103 | #define Literal (RepLenCoder + kNumLenProbs) 104 | 105 | #define LZMA_BASE_SIZE 1846 106 | #define LZMA_LIT_SIZE 768 107 | 108 | #define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp))) 109 | 110 | #if Literal != LZMA_BASE_SIZE 111 | StopCompilingDueBUG 112 | #endif 113 | 114 | #define LZMA_DIC_MIN (1 << 12) 115 | 116 | /* First LZMA-symbol is always decoded. 117 | And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is without last normalization 118 | Out: 119 | Result: 120 | SZ_OK - OK 121 | SZ_ERROR_DATA - Error 122 | p->remainLen: 123 | < kMatchSpecLenStart : normal remain 124 | = kMatchSpecLenStart : finished 125 | = kMatchSpecLenStart + 1 : Flush marker 126 | = kMatchSpecLenStart + 2 : State Init Marker 127 | */ 128 | 129 | static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit) 130 | { 131 | CLzmaProb *probs = p->probs; 132 | 133 | unsigned state = p->state; 134 | UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3]; 135 | unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1; 136 | unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1; 137 | unsigned lc = p->prop.lc; 138 | 139 | Byte *dic = p->dic; 140 | SizeT dicBufSize = p->dicBufSize; 141 | SizeT dicPos = p->dicPos; 142 | 143 | UInt32 processedPos = p->processedPos; 144 | UInt32 checkDicSize = p->checkDicSize; 145 | unsigned len = 0; 146 | 147 | const Byte *buf = p->buf; 148 | UInt32 range = p->range; 149 | UInt32 code = p->code; 150 | 151 | do 152 | { 153 | CLzmaProb *prob; 154 | UInt32 bound; 155 | unsigned ttt; 156 | unsigned posState = processedPos & pbMask; 157 | 158 | prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; 159 | IF_BIT_0(prob) 160 | { 161 | unsigned symbol; 162 | UPDATE_0(prob); 163 | prob = probs + Literal; 164 | if (checkDicSize != 0 || processedPos != 0) 165 | prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) + 166 | (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc)))); 167 | 168 | if (state < kNumLitStates) 169 | { 170 | state -= (state < 4) ? state : 3; 171 | symbol = 1; 172 | 173 | do { GET_BIT(prob + symbol, symbol) } while (symbol < 0x100); 174 | } 175 | else 176 | { 177 | unsigned matchByte = p->dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; 178 | unsigned offs = 0x100; 179 | state -= (state < 10) ? 3 : 6; 180 | symbol = 1; 181 | 182 | do 183 | { 184 | unsigned bit; 185 | CLzmaProb *probLit; 186 | matchByte <<= 1; 187 | bit = (matchByte & offs); 188 | probLit = prob + offs + bit + symbol; 189 | GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit) 190 | } 191 | while (symbol < 0x100); 192 | } 193 | dic[dicPos++] = (Byte)symbol; 194 | processedPos++; 195 | continue; 196 | } 197 | else 198 | { 199 | UPDATE_1(prob); 200 | prob = probs + IsRep + state; 201 | IF_BIT_0(prob) 202 | { 203 | UPDATE_0(prob); 204 | state += kNumStates; 205 | prob = probs + LenCoder; 206 | } 207 | else 208 | { 209 | UPDATE_1(prob); 210 | if (checkDicSize == 0 && processedPos == 0) 211 | return SZ_ERROR_DATA; 212 | prob = probs + IsRepG0 + state; 213 | IF_BIT_0(prob) 214 | { 215 | UPDATE_0(prob); 216 | prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; 217 | IF_BIT_0(prob) 218 | { 219 | UPDATE_0(prob); 220 | dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; 221 | dicPos++; 222 | processedPos++; 223 | state = state < kNumLitStates ? 9 : 11; 224 | continue; 225 | } 226 | UPDATE_1(prob); 227 | } 228 | else 229 | { 230 | UInt32 distance; 231 | UPDATE_1(prob); 232 | prob = probs + IsRepG1 + state; 233 | IF_BIT_0(prob) 234 | { 235 | UPDATE_0(prob); 236 | distance = rep1; 237 | } 238 | else 239 | { 240 | UPDATE_1(prob); 241 | prob = probs + IsRepG2 + state; 242 | IF_BIT_0(prob) 243 | { 244 | UPDATE_0(prob); 245 | distance = rep2; 246 | } 247 | else 248 | { 249 | UPDATE_1(prob); 250 | distance = rep3; 251 | rep3 = rep2; 252 | } 253 | rep2 = rep1; 254 | } 255 | rep1 = rep0; 256 | rep0 = distance; 257 | } 258 | state = state < kNumLitStates ? 8 : 11; 259 | prob = probs + RepLenCoder; 260 | } 261 | { 262 | unsigned limit, offset; 263 | CLzmaProb *probLen = prob + LenChoice; 264 | IF_BIT_0(probLen) 265 | { 266 | UPDATE_0(probLen); 267 | probLen = prob + LenLow + (posState << kLenNumLowBits); 268 | offset = 0; 269 | limit = (1 << kLenNumLowBits); 270 | } 271 | else 272 | { 273 | UPDATE_1(probLen); 274 | probLen = prob + LenChoice2; 275 | IF_BIT_0(probLen) 276 | { 277 | UPDATE_0(probLen); 278 | probLen = prob + LenMid + (posState << kLenNumMidBits); 279 | offset = kLenNumLowSymbols; 280 | limit = (1 << kLenNumMidBits); 281 | } 282 | else 283 | { 284 | UPDATE_1(probLen); 285 | probLen = prob + LenHigh; 286 | offset = kLenNumLowSymbols + kLenNumMidSymbols; 287 | limit = (1 << kLenNumHighBits); 288 | } 289 | } 290 | TREE_DECODE(probLen, limit, len); 291 | len += offset; 292 | } 293 | 294 | if (state >= kNumStates) 295 | { 296 | UInt32 distance; 297 | prob = probs + PosSlot + 298 | ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); 299 | TREE_6_DECODE(prob, distance); 300 | if (distance >= kStartPosModelIndex) 301 | { 302 | unsigned posSlot = (unsigned)distance; 303 | int numDirectBits = (int)(((distance >> 1) - 1)); 304 | distance = (2 | (distance & 1)); 305 | if (posSlot < kEndPosModelIndex) 306 | { 307 | distance <<= numDirectBits; 308 | prob = probs + SpecPos + distance - posSlot - 1; 309 | { 310 | UInt32 mask = 1; 311 | unsigned i = 1; 312 | 313 | do 314 | { 315 | GET_BIT2(prob + i, i, ; , distance |= mask); 316 | mask <<= 1; 317 | } 318 | while (--numDirectBits != 0); 319 | } 320 | } 321 | else 322 | { 323 | numDirectBits -= kNumAlignBits; 324 | 325 | do 326 | { 327 | NORMALIZE 328 | range >>= 1; 329 | 330 | { 331 | UInt32 t; 332 | code -= range; 333 | t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */ 334 | distance = (distance << 1) + (t + 1); 335 | code += range & t; 336 | } 337 | /* 338 | distance <<= 1; 339 | if (code >= range) 340 | { 341 | code -= range; 342 | distance |= 1; 343 | } 344 | */ 345 | } 346 | while (--numDirectBits != 0); 347 | prob = probs + Align; 348 | distance <<= kNumAlignBits; 349 | { 350 | unsigned i = 1; 351 | GET_BIT2(prob + i, i, ; , distance |= 1); 352 | GET_BIT2(prob + i, i, ; , distance |= 2); 353 | GET_BIT2(prob + i, i, ; , distance |= 4); 354 | GET_BIT2(prob + i, i, ; , distance |= 8); 355 | } 356 | if (distance == (UInt32)0xFFFFFFFF) 357 | { 358 | len += kMatchSpecLenStart; 359 | state -= kNumStates; 360 | break; 361 | } 362 | } 363 | } 364 | rep3 = rep2; 365 | rep2 = rep1; 366 | rep1 = rep0; 367 | rep0 = distance + 1; 368 | if (checkDicSize == 0) 369 | { 370 | if (distance >= processedPos) 371 | return SZ_ERROR_DATA; 372 | } 373 | else if (distance >= checkDicSize) 374 | return SZ_ERROR_DATA; 375 | state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; 376 | } 377 | 378 | len += kMatchMinLen; 379 | 380 | if (limit == dicPos) 381 | return SZ_ERROR_DATA; 382 | { 383 | SizeT rem = limit - dicPos; 384 | unsigned curLen = ((rem < len) ? (unsigned)rem : len); 385 | SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0); 386 | 387 | processedPos += curLen; 388 | 389 | len -= curLen; 390 | if (pos + curLen <= dicBufSize) 391 | { 392 | Byte *dest = dic + dicPos; 393 | ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos; 394 | const Byte *lim = dest + curLen; 395 | dicPos += curLen; 396 | 397 | do 398 | *(dest) = (Byte)*(dest + src); 399 | while (++dest != lim); 400 | } 401 | else 402 | { 403 | do 404 | { 405 | dic[dicPos++] = dic[pos]; 406 | if (++pos == dicBufSize) 407 | pos = 0; 408 | } 409 | while (--curLen != 0); 410 | } 411 | } 412 | } 413 | } 414 | while (dicPos < limit && buf < bufLimit); 415 | 416 | NORMALIZE; 417 | p->buf = buf; 418 | p->range = range; 419 | p->code = code; 420 | p->remainLen = len; 421 | p->dicPos = dicPos; 422 | p->processedPos = processedPos; 423 | p->reps[0] = rep0; 424 | p->reps[1] = rep1; 425 | p->reps[2] = rep2; 426 | p->reps[3] = rep3; 427 | p->state = state; 428 | 429 | return SZ_OK; 430 | } 431 | 432 | static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit) 433 | { 434 | if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart) 435 | { 436 | Byte *dic = p->dic; 437 | SizeT dicPos = p->dicPos; 438 | SizeT dicBufSize = p->dicBufSize; 439 | unsigned len = p->remainLen; 440 | UInt32 rep0 = p->reps[0]; 441 | if (limit - dicPos < len) 442 | len = (unsigned)(limit - dicPos); 443 | 444 | if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len) 445 | p->checkDicSize = p->prop.dicSize; 446 | 447 | p->processedPos += len; 448 | p->remainLen -= len; 449 | while (len-- != 0) 450 | { 451 | dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; 452 | dicPos++; 453 | } 454 | p->dicPos = dicPos; 455 | } 456 | } 457 | 458 | static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit) 459 | { 460 | do 461 | { 462 | SizeT limit2 = limit; 463 | if (p->checkDicSize == 0) 464 | { 465 | UInt32 rem = p->prop.dicSize - p->processedPos; 466 | if (limit - p->dicPos > rem) 467 | limit2 = p->dicPos + rem; 468 | } 469 | RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit)); 470 | if (p->processedPos >= p->prop.dicSize) 471 | p->checkDicSize = p->prop.dicSize; 472 | LzmaDec_WriteRem(p, limit); 473 | } 474 | while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart); 475 | 476 | if (p->remainLen > kMatchSpecLenStart) 477 | { 478 | p->remainLen = kMatchSpecLenStart; 479 | } 480 | return 0; 481 | } 482 | 483 | typedef enum 484 | { 485 | DUMMY_ERROR, /* unexpected end of input stream */ 486 | DUMMY_LIT, 487 | DUMMY_MATCH, 488 | DUMMY_REP 489 | } ELzmaDummy; 490 | 491 | static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize) 492 | { 493 | UInt32 range = p->range; 494 | UInt32 code = p->code; 495 | const Byte *bufLimit = buf + inSize; 496 | CLzmaProb *probs = p->probs; 497 | unsigned state = p->state; 498 | ELzmaDummy res; 499 | 500 | { 501 | CLzmaProb *prob; 502 | UInt32 bound; 503 | unsigned ttt; 504 | unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1); 505 | 506 | prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; 507 | IF_BIT_0_CHECK(prob) 508 | { 509 | UPDATE_0_CHECK 510 | 511 | /* if (bufLimit - buf >= 7) return DUMMY_LIT; */ 512 | 513 | prob = probs + Literal; 514 | if (p->checkDicSize != 0 || p->processedPos != 0) 515 | prob += (LZMA_LIT_SIZE * 516 | ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) + 517 | (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc)))); 518 | 519 | if (state < kNumLitStates) 520 | { 521 | unsigned symbol = 1; 522 | do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100); 523 | } 524 | else 525 | { 526 | unsigned matchByte = p->dic[p->dicPos - p->reps[0] + 527 | ((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)]; 528 | unsigned offs = 0x100; 529 | unsigned symbol = 1; 530 | do 531 | { 532 | unsigned bit; 533 | CLzmaProb *probLit; 534 | matchByte <<= 1; 535 | bit = (matchByte & offs); 536 | probLit = prob + offs + bit + symbol; 537 | GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit) 538 | } 539 | while (symbol < 0x100); 540 | } 541 | res = DUMMY_LIT; 542 | } 543 | else 544 | { 545 | unsigned len; 546 | UPDATE_1_CHECK; 547 | 548 | prob = probs + IsRep + state; 549 | IF_BIT_0_CHECK(prob) 550 | { 551 | UPDATE_0_CHECK; 552 | state = 0; 553 | prob = probs + LenCoder; 554 | res = DUMMY_MATCH; 555 | } 556 | else 557 | { 558 | UPDATE_1_CHECK; 559 | res = DUMMY_REP; 560 | prob = probs + IsRepG0 + state; 561 | IF_BIT_0_CHECK(prob) 562 | { 563 | UPDATE_0_CHECK; 564 | prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; 565 | IF_BIT_0_CHECK(prob) 566 | { 567 | UPDATE_0_CHECK; 568 | NORMALIZE_CHECK; 569 | return DUMMY_REP; 570 | } 571 | else 572 | { 573 | UPDATE_1_CHECK; 574 | } 575 | } 576 | else 577 | { 578 | UPDATE_1_CHECK; 579 | prob = probs + IsRepG1 + state; 580 | IF_BIT_0_CHECK(prob) 581 | { 582 | UPDATE_0_CHECK; 583 | } 584 | else 585 | { 586 | UPDATE_1_CHECK; 587 | prob = probs + IsRepG2 + state; 588 | IF_BIT_0_CHECK(prob) 589 | { 590 | UPDATE_0_CHECK; 591 | } 592 | else 593 | { 594 | UPDATE_1_CHECK; 595 | } 596 | } 597 | } 598 | state = kNumStates; 599 | prob = probs + RepLenCoder; 600 | } 601 | { 602 | unsigned limit, offset; 603 | CLzmaProb *probLen = prob + LenChoice; 604 | IF_BIT_0_CHECK(probLen) 605 | { 606 | UPDATE_0_CHECK; 607 | probLen = prob + LenLow + (posState << kLenNumLowBits); 608 | offset = 0; 609 | limit = 1 << kLenNumLowBits; 610 | } 611 | else 612 | { 613 | UPDATE_1_CHECK; 614 | probLen = prob + LenChoice2; 615 | IF_BIT_0_CHECK(probLen) 616 | { 617 | UPDATE_0_CHECK; 618 | probLen = prob + LenMid + (posState << kLenNumMidBits); 619 | offset = kLenNumLowSymbols; 620 | limit = 1 << kLenNumMidBits; 621 | } 622 | else 623 | { 624 | UPDATE_1_CHECK; 625 | probLen = prob + LenHigh; 626 | offset = kLenNumLowSymbols + kLenNumMidSymbols; 627 | limit = 1 << kLenNumHighBits; 628 | } 629 | } 630 | TREE_DECODE_CHECK(probLen, limit, len); 631 | len += offset; 632 | } 633 | 634 | if (state < 4) 635 | { 636 | unsigned posSlot; 637 | prob = probs + PosSlot + 638 | ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << 639 | kNumPosSlotBits); 640 | TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot); 641 | if (posSlot >= kStartPosModelIndex) 642 | { 643 | int numDirectBits = ((posSlot >> 1) - 1); 644 | 645 | /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */ 646 | 647 | if (posSlot < kEndPosModelIndex) 648 | { 649 | prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1; 650 | } 651 | else 652 | { 653 | numDirectBits -= kNumAlignBits; 654 | do 655 | { 656 | NORMALIZE_CHECK 657 | range >>= 1; 658 | code -= range & (((code - range) >> 31) - 1); 659 | /* if (code >= range) code -= range; */ 660 | } 661 | while (--numDirectBits != 0); 662 | prob = probs + Align; 663 | numDirectBits = kNumAlignBits; 664 | } 665 | { 666 | unsigned i = 1; 667 | do 668 | { 669 | GET_BIT_CHECK(prob + i, i); 670 | } 671 | while (--numDirectBits != 0); 672 | } 673 | } 674 | } 675 | } 676 | } 677 | NORMALIZE_CHECK; 678 | return res; 679 | } 680 | 681 | 682 | static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data) 683 | { 684 | p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]); 685 | p->range = 0xFFFFFFFF; 686 | p->needFlush = 0; 687 | } 688 | 689 | void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) 690 | { 691 | p->needFlush = 1; 692 | p->remainLen = 0; 693 | p->tempBufSize = 0; 694 | 695 | if (initDic) 696 | { 697 | p->processedPos = 0; 698 | p->checkDicSize = 0; 699 | p->needInitState = 1; 700 | } 701 | if (initState) 702 | p->needInitState = 1; 703 | } 704 | 705 | void LzmaDec_Init(CLzmaDec *p) 706 | { 707 | p->dicPos = 0; 708 | LzmaDec_InitDicAndState(p, True, True); 709 | } 710 | 711 | static void LzmaDec_InitStateReal(CLzmaDec *p) 712 | { 713 | UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp)); 714 | UInt32 i; 715 | CLzmaProb *probs = p->probs; 716 | for (i = 0; i < numProbs; i++) 717 | probs[i] = kBitModelTotal >> 1; 718 | p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1; 719 | p->state = 0; 720 | p->needInitState = 0; 721 | } 722 | 723 | SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, 724 | ELzmaFinishMode finishMode, ELzmaStatus *status) 725 | { 726 | SizeT inSize = *srcLen; 727 | (*srcLen) = 0; 728 | LzmaDec_WriteRem(p, dicLimit); 729 | 730 | *status = LZMA_STATUS_NOT_SPECIFIED; 731 | 732 | while (p->remainLen != kMatchSpecLenStart) 733 | { 734 | int checkEndMarkNow; 735 | 736 | if (p->needFlush != 0) 737 | { 738 | for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--) 739 | p->tempBuf[p->tempBufSize++] = *src++; 740 | if (p->tempBufSize < RC_INIT_SIZE) 741 | { 742 | *status = LZMA_STATUS_NEEDS_MORE_INPUT; 743 | return SZ_OK; 744 | } 745 | if (p->tempBuf[0] != 0) 746 | return SZ_ERROR_DATA; 747 | 748 | LzmaDec_InitRc(p, p->tempBuf); 749 | p->tempBufSize = 0; 750 | } 751 | 752 | checkEndMarkNow = 0; 753 | if (p->dicPos >= dicLimit) 754 | { 755 | if (p->remainLen == 0 && p->code == 0) 756 | { 757 | *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK; 758 | return SZ_OK; 759 | } 760 | if (finishMode == LZMA_FINISH_ANY) 761 | { 762 | *status = LZMA_STATUS_NOT_FINISHED; 763 | return SZ_OK; 764 | } 765 | if (p->remainLen != 0) 766 | { 767 | *status = LZMA_STATUS_NOT_FINISHED; 768 | return SZ_ERROR_DATA; 769 | } 770 | checkEndMarkNow = 1; 771 | } 772 | 773 | if (p->needInitState) 774 | LzmaDec_InitStateReal(p); 775 | 776 | if (p->tempBufSize == 0) 777 | { 778 | SizeT processed; 779 | const Byte *bufLimit; 780 | if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) 781 | { 782 | int dummyRes = LzmaDec_TryDummy(p, src, inSize); 783 | if (dummyRes == DUMMY_ERROR) 784 | { 785 | memcpy(p->tempBuf, src, inSize); 786 | p->tempBufSize = (unsigned)inSize; 787 | (*srcLen) += inSize; 788 | *status = LZMA_STATUS_NEEDS_MORE_INPUT; 789 | return SZ_OK; 790 | } 791 | if (checkEndMarkNow && dummyRes != DUMMY_MATCH) 792 | { 793 | *status = LZMA_STATUS_NOT_FINISHED; 794 | return SZ_ERROR_DATA; 795 | } 796 | bufLimit = src; 797 | } 798 | else 799 | bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX; 800 | p->buf = src; 801 | if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0) 802 | return SZ_ERROR_DATA; 803 | processed = (SizeT)(p->buf - src); 804 | (*srcLen) += processed; 805 | src += processed; 806 | inSize -= processed; 807 | } 808 | else 809 | { 810 | unsigned rem = p->tempBufSize, lookAhead = 0; 811 | while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize) 812 | p->tempBuf[rem++] = src[lookAhead++]; 813 | p->tempBufSize = rem; 814 | if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) 815 | { 816 | int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem); 817 | if (dummyRes == DUMMY_ERROR) 818 | { 819 | (*srcLen) += lookAhead; 820 | *status = LZMA_STATUS_NEEDS_MORE_INPUT; 821 | return SZ_OK; 822 | } 823 | if (checkEndMarkNow && dummyRes != DUMMY_MATCH) 824 | { 825 | *status = LZMA_STATUS_NOT_FINISHED; 826 | return SZ_ERROR_DATA; 827 | } 828 | } 829 | p->buf = p->tempBuf; 830 | if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0) 831 | return SZ_ERROR_DATA; 832 | lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf)); 833 | (*srcLen) += lookAhead; 834 | src += lookAhead; 835 | inSize -= lookAhead; 836 | p->tempBufSize = 0; 837 | } 838 | } 839 | if (p->code == 0) 840 | *status = LZMA_STATUS_FINISHED_WITH_MARK; 841 | return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA; 842 | } 843 | 844 | SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) 845 | { 846 | SizeT outSize = *destLen; 847 | SizeT inSize = *srcLen; 848 | *srcLen = *destLen = 0; 849 | for (;;) 850 | { 851 | SizeT inSizeCur = inSize, outSizeCur, dicPos; 852 | ELzmaFinishMode curFinishMode; 853 | SRes res; 854 | if (p->dicPos == p->dicBufSize) 855 | p->dicPos = 0; 856 | dicPos = p->dicPos; 857 | if (outSize > p->dicBufSize - dicPos) 858 | { 859 | outSizeCur = p->dicBufSize; 860 | curFinishMode = LZMA_FINISH_ANY; 861 | } 862 | else 863 | { 864 | outSizeCur = dicPos + outSize; 865 | curFinishMode = finishMode; 866 | } 867 | 868 | res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status); 869 | src += inSizeCur; 870 | inSize -= inSizeCur; 871 | *srcLen += inSizeCur; 872 | outSizeCur = p->dicPos - dicPos; 873 | memcpy(dest, p->dic + dicPos, outSizeCur); 874 | dest += outSizeCur; 875 | outSize -= outSizeCur; 876 | *destLen += outSizeCur; 877 | if (res != 0) 878 | return res; 879 | if (outSizeCur == 0 || outSize == 0) 880 | return SZ_OK; 881 | } 882 | } 883 | 884 | void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc) 885 | { 886 | alloc->Free(alloc, p->probs); 887 | p->probs = 0; 888 | } 889 | 890 | static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc) 891 | { 892 | alloc->Free(alloc, p->dic); 893 | p->dic = 0; 894 | } 895 | 896 | void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc) 897 | { 898 | LzmaDec_FreeProbs(p, alloc); 899 | LzmaDec_FreeDict(p, alloc); 900 | } 901 | 902 | SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) 903 | { 904 | UInt32 dicSize; 905 | Byte d; 906 | 907 | if (size < LZMA_PROPS_SIZE) 908 | return SZ_ERROR_UNSUPPORTED; 909 | else 910 | dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24); 911 | 912 | if (dicSize < LZMA_DIC_MIN) 913 | dicSize = LZMA_DIC_MIN; 914 | p->dicSize = dicSize; 915 | 916 | d = data[0]; 917 | if (d >= (9 * 5 * 5)) 918 | return SZ_ERROR_UNSUPPORTED; 919 | 920 | p->lc = d % 9; 921 | d /= 9; 922 | p->pb = d / 5; 923 | p->lp = d % 5; 924 | 925 | return SZ_OK; 926 | } 927 | 928 | static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc) 929 | { 930 | UInt32 numProbs = LzmaProps_GetNumProbs(propNew); 931 | if (p->probs == 0 || numProbs != p->numProbs) 932 | { 933 | LzmaDec_FreeProbs(p, alloc); 934 | p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb)); 935 | p->numProbs = numProbs; 936 | if (p->probs == 0) 937 | return SZ_ERROR_MEM; 938 | } 939 | return SZ_OK; 940 | } 941 | 942 | SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) 943 | { 944 | CLzmaProps propNew; 945 | RINOK(LzmaProps_Decode(&propNew, props, propsSize)); 946 | RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); 947 | p->prop = propNew; 948 | return SZ_OK; 949 | } 950 | 951 | SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) 952 | { 953 | CLzmaProps propNew; 954 | SizeT dicBufSize; 955 | RINOK(LzmaProps_Decode(&propNew, props, propsSize)); 956 | RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); 957 | dicBufSize = propNew.dicSize; 958 | if (p->dic == 0 || dicBufSize != p->dicBufSize) 959 | { 960 | LzmaDec_FreeDict(p, alloc); 961 | p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize); 962 | if (p->dic == 0) 963 | { 964 | LzmaDec_FreeProbs(p, alloc); 965 | return SZ_ERROR_MEM; 966 | } 967 | } 968 | p->dicBufSize = dicBufSize; 969 | p->prop = propNew; 970 | return SZ_OK; 971 | } 972 | 973 | SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, 974 | const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, 975 | ELzmaStatus *status, ISzAlloc *alloc) 976 | { 977 | CLzmaDec p; 978 | SRes res; 979 | SizeT inSize = *srcLen; 980 | SizeT outSize = *destLen; 981 | *srcLen = *destLen = 0; 982 | if (inSize < RC_INIT_SIZE) 983 | return SZ_ERROR_INPUT_EOF; 984 | 985 | LzmaDec_Construct(&p); 986 | res = LzmaDec_AllocateProbs(&p, propData, propSize, alloc); 987 | if (res != 0) 988 | return res; 989 | p.dic = dest; 990 | p.dicBufSize = outSize; 991 | 992 | LzmaDec_Init(&p); 993 | 994 | *srcLen = inSize; 995 | res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); 996 | 997 | if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) 998 | res = SZ_ERROR_INPUT_EOF; 999 | 1000 | (*destLen) = p.dicPos; 1001 | LzmaDec_FreeProbs(&p, alloc); 1002 | return res; 1003 | } 1004 | -------------------------------------------------------------------------------- /src/stage2/lzma/LzmaDec.h: -------------------------------------------------------------------------------- 1 | /* LzmaDec.h -- LZMA Decoder 2 | 2009-02-07 : Igor Pavlov : Public domain */ 3 | 4 | #ifndef __LZMA_DEC_H 5 | #define __LZMA_DEC_H 6 | 7 | #include "Types.h" 8 | 9 | /* #define _LZMA_PROB32 */ 10 | /* _LZMA_PROB32 can increase the speed on some CPUs, 11 | but memory usage for CLzmaDec::probs will be doubled in that case */ 12 | 13 | #ifdef _LZMA_PROB32 14 | #define CLzmaProb UInt32 15 | #else 16 | #define CLzmaProb UInt16 17 | #endif 18 | 19 | 20 | /* ---------- LZMA Properties ---------- */ 21 | 22 | #define LZMA_PROPS_SIZE 5 23 | 24 | typedef struct _CLzmaProps 25 | { 26 | unsigned lc, lp, pb; 27 | UInt32 dicSize; 28 | } CLzmaProps; 29 | 30 | /* LzmaProps_Decode - decodes properties 31 | Returns: 32 | SZ_OK 33 | SZ_ERROR_UNSUPPORTED - Unsupported properties 34 | */ 35 | 36 | SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size); 37 | 38 | 39 | /* ---------- LZMA Decoder state ---------- */ 40 | 41 | /* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case. 42 | Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */ 43 | 44 | #define LZMA_REQUIRED_INPUT_MAX 20 45 | 46 | typedef struct 47 | { 48 | CLzmaProps prop; 49 | CLzmaProb *probs; 50 | Byte *dic; 51 | const Byte *buf; 52 | UInt32 range, code; 53 | SizeT dicPos; 54 | SizeT dicBufSize; 55 | UInt32 processedPos; 56 | UInt32 checkDicSize; 57 | unsigned state; 58 | UInt32 reps[4]; 59 | unsigned remainLen; 60 | int needFlush; 61 | int needInitState; 62 | UInt32 numProbs; 63 | unsigned tempBufSize; 64 | Byte tempBuf[LZMA_REQUIRED_INPUT_MAX]; 65 | } CLzmaDec; 66 | 67 | #define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; } 68 | 69 | void LzmaDec_Init(CLzmaDec *p); 70 | 71 | /* There are two types of LZMA streams: 72 | 0) Stream with end mark. That end mark adds about 6 bytes to compressed size. 73 | 1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */ 74 | 75 | typedef enum 76 | { 77 | LZMA_FINISH_ANY, /* finish at any point */ 78 | LZMA_FINISH_END /* block must be finished at the end */ 79 | } ELzmaFinishMode; 80 | 81 | /* ELzmaFinishMode has meaning only if the decoding reaches output limit !!! 82 | 83 | You must use LZMA_FINISH_END, when you know that current output buffer 84 | covers last bytes of block. In other cases you must use LZMA_FINISH_ANY. 85 | 86 | If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK, 87 | and output value of destLen will be less than output buffer size limit. 88 | You can check status result also. 89 | 90 | You can use multiple checks to test data integrity after full decompression: 91 | 1) Check Result and "status" variable. 92 | 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize. 93 | 3) Check that output(srcLen) = compressedSize, if you know real compressedSize. 94 | You must use correct finish mode in that case. */ 95 | 96 | typedef enum 97 | { 98 | LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */ 99 | LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ 100 | LZMA_STATUS_NOT_FINISHED, /* stream was not finished */ 101 | LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */ 102 | LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */ 103 | } ELzmaStatus; 104 | 105 | /* ELzmaStatus is used only as output value for function call */ 106 | 107 | 108 | /* ---------- Interfaces ---------- */ 109 | 110 | /* There are 3 levels of interfaces: 111 | 1) Dictionary Interface 112 | 2) Buffer Interface 113 | 3) One Call Interface 114 | You can select any of these interfaces, but don't mix functions from different 115 | groups for same object. */ 116 | 117 | 118 | /* There are two variants to allocate state for Dictionary Interface: 119 | 1) LzmaDec_Allocate / LzmaDec_Free 120 | 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs 121 | You can use variant 2, if you set dictionary buffer manually. 122 | For Buffer Interface you must always use variant 1. 123 | 124 | LzmaDec_Allocate* can return: 125 | SZ_OK 126 | SZ_ERROR_MEM - Memory allocation error 127 | SZ_ERROR_UNSUPPORTED - Unsupported properties 128 | */ 129 | 130 | SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc); 131 | void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc); 132 | 133 | SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc); 134 | void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc); 135 | 136 | /* ---------- Dictionary Interface ---------- */ 137 | 138 | /* You can use it, if you want to eliminate the overhead for data copying from 139 | dictionary to some other external buffer. 140 | You must work with CLzmaDec variables directly in this interface. 141 | 142 | STEPS: 143 | LzmaDec_Constr() 144 | LzmaDec_Allocate() 145 | for (each new stream) 146 | { 147 | LzmaDec_Init() 148 | while (it needs more decompression) 149 | { 150 | LzmaDec_DecodeToDic() 151 | use data from CLzmaDec::dic and update CLzmaDec::dicPos 152 | } 153 | } 154 | LzmaDec_Free() 155 | */ 156 | 157 | /* LzmaDec_DecodeToDic 158 | 159 | The decoding to internal dictionary buffer (CLzmaDec::dic). 160 | You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!! 161 | 162 | finishMode: 163 | It has meaning only if the decoding reaches output limit (dicLimit). 164 | LZMA_FINISH_ANY - Decode just dicLimit bytes. 165 | LZMA_FINISH_END - Stream must be finished after dicLimit. 166 | 167 | Returns: 168 | SZ_OK 169 | status: 170 | LZMA_STATUS_FINISHED_WITH_MARK 171 | LZMA_STATUS_NOT_FINISHED 172 | LZMA_STATUS_NEEDS_MORE_INPUT 173 | LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK 174 | SZ_ERROR_DATA - Data error 175 | */ 176 | 177 | SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, 178 | const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); 179 | 180 | 181 | /* ---------- Buffer Interface ---------- */ 182 | 183 | /* It's zlib-like interface. 184 | See LzmaDec_DecodeToDic description for information about STEPS and return results, 185 | but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need 186 | to work with CLzmaDec variables manually. 187 | 188 | finishMode: 189 | It has meaning only if the decoding reaches output limit (*destLen). 190 | LZMA_FINISH_ANY - Decode just destLen bytes. 191 | LZMA_FINISH_END - Stream must be finished after (*destLen). 192 | */ 193 | 194 | SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, 195 | const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); 196 | 197 | 198 | /* ---------- One Call Interface ---------- */ 199 | 200 | /* LzmaDecode 201 | 202 | finishMode: 203 | It has meaning only if the decoding reaches output limit (*destLen). 204 | LZMA_FINISH_ANY - Decode just destLen bytes. 205 | LZMA_FINISH_END - Stream must be finished after (*destLen). 206 | 207 | Returns: 208 | SZ_OK 209 | status: 210 | LZMA_STATUS_FINISHED_WITH_MARK 211 | LZMA_STATUS_NOT_FINISHED 212 | LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK 213 | SZ_ERROR_DATA - Data error 214 | SZ_ERROR_MEM - Memory allocation error 215 | SZ_ERROR_UNSUPPORTED - Unsupported properties 216 | SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). 217 | */ 218 | 219 | SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, 220 | const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, 221 | ELzmaStatus *status, ISzAlloc *alloc); 222 | 223 | #endif 224 | -------------------------------------------------------------------------------- /src/stage2/lzma/Types.h: -------------------------------------------------------------------------------- 1 | /* Types.h -- Basic types 2 | 2010-10-09 : Igor Pavlov : Public domain */ 3 | 4 | #ifndef __7Z_TYPES_H 5 | #define __7Z_TYPES_H 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #ifdef _WIN32 12 | #include 13 | #endif 14 | 15 | #define SZ_OK 0 16 | 17 | #define SZ_ERROR_DATA 1 18 | #define SZ_ERROR_MEM 2 19 | #define SZ_ERROR_CRC 3 20 | #define SZ_ERROR_UNSUPPORTED 4 21 | #define SZ_ERROR_PARAM 5 22 | #define SZ_ERROR_INPUT_EOF 6 23 | #define SZ_ERROR_OUTPUT_EOF 7 24 | #define SZ_ERROR_READ 8 25 | #define SZ_ERROR_WRITE 9 26 | #define SZ_ERROR_PROGRESS 10 27 | #define SZ_ERROR_FAIL 11 28 | #define SZ_ERROR_THREAD 12 29 | 30 | #define SZ_ERROR_ARCHIVE 16 31 | #define SZ_ERROR_NO_ARCHIVE 17 32 | 33 | typedef int SRes; 34 | 35 | #ifdef _WIN32 36 | typedef DWORD WRes; 37 | #else 38 | typedef int WRes; 39 | #endif 40 | 41 | #ifndef RINOK 42 | #define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; } 43 | #endif 44 | 45 | typedef unsigned char Byte; 46 | typedef short Int16; 47 | typedef unsigned short UInt16; 48 | 49 | #ifdef _LZMA_UINT32_IS_ULONG 50 | typedef long Int32; 51 | typedef unsigned long UInt32; 52 | #else 53 | typedef int Int32; 54 | typedef unsigned int UInt32; 55 | #endif 56 | 57 | #ifdef _SZ_NO_INT_64 58 | 59 | /* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers. 60 | NOTES: Some code will work incorrectly in that case! */ 61 | 62 | typedef long Int64; 63 | typedef unsigned long UInt64; 64 | 65 | #else 66 | 67 | #if defined(_MSC_VER) || defined(__BORLANDC__) 68 | typedef __int64 Int64; 69 | typedef unsigned __int64 UInt64; 70 | #define UINT64_CONST(n) n 71 | #else 72 | typedef long long int Int64; 73 | typedef unsigned long long int UInt64; 74 | #define UINT64_CONST(n) n ## ULL 75 | #endif 76 | 77 | #endif 78 | 79 | #ifdef _LZMA_NO_SYSTEM_SIZE_T 80 | typedef UInt32 SizeT; 81 | #else 82 | typedef size_t SizeT; 83 | #endif 84 | 85 | typedef int Bool; 86 | #define True 1 87 | #define False 0 88 | 89 | 90 | #ifdef _MSC_VER 91 | 92 | #if _MSC_VER >= 1300 93 | #define MY_NO_INLINE __declspec(noinline) 94 | #else 95 | #define MY_NO_INLINE 96 | #endif 97 | 98 | #define MY_CDECL __cdecl 99 | #define MY_FAST_CALL __fastcall 100 | 101 | #else 102 | 103 | #define MY_CDECL 104 | #define MY_FAST_CALL 105 | 106 | #endif 107 | 108 | 109 | /* The following interfaces use first parameter as pointer to structure */ 110 | 111 | typedef struct 112 | { 113 | Byte (*Read)(void *p); /* reads one byte, returns 0 in case of EOF or error */ 114 | } IByteIn; 115 | 116 | typedef struct 117 | { 118 | void (*Write)(void *p, Byte b); 119 | } IByteOut; 120 | 121 | typedef struct 122 | { 123 | SRes (*Read)(void *p, void *buf, size_t *size); 124 | /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. 125 | (output(*size) < input(*size)) is allowed */ 126 | } ISeqInStream; 127 | 128 | /* it can return SZ_ERROR_INPUT_EOF */ 129 | SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size); 130 | SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType); 131 | SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf); 132 | 133 | typedef struct 134 | { 135 | size_t (*Write)(void *p, const void *buf, size_t size); 136 | /* Returns: result - the number of actually written bytes. 137 | (result < size) means error */ 138 | } ISeqOutStream; 139 | 140 | typedef enum 141 | { 142 | SZ_SEEK_SET = 0, 143 | SZ_SEEK_CUR = 1, 144 | SZ_SEEK_END = 2 145 | } ESzSeek; 146 | 147 | typedef struct 148 | { 149 | SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */ 150 | SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); 151 | } ISeekInStream; 152 | 153 | typedef struct 154 | { 155 | SRes (*Look)(void *p, const void **buf, size_t *size); 156 | /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. 157 | (output(*size) > input(*size)) is not allowed 158 | (output(*size) < input(*size)) is allowed */ 159 | SRes (*Skip)(void *p, size_t offset); 160 | /* offset must be <= output(*size) of Look */ 161 | 162 | SRes (*Read)(void *p, void *buf, size_t *size); 163 | /* reads directly (without buffer). It's same as ISeqInStream::Read */ 164 | SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); 165 | } ILookInStream; 166 | 167 | SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size); 168 | SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset); 169 | 170 | /* reads via ILookInStream::Read */ 171 | SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType); 172 | SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size); 173 | 174 | #define LookToRead_BUF_SIZE (1 << 14) 175 | 176 | typedef struct 177 | { 178 | ILookInStream s; 179 | ISeekInStream *realStream; 180 | size_t pos; 181 | size_t size; 182 | Byte buf[LookToRead_BUF_SIZE]; 183 | } CLookToRead; 184 | 185 | void LookToRead_CreateVTable(CLookToRead *p, int lookahead); 186 | void LookToRead_Init(CLookToRead *p); 187 | 188 | typedef struct 189 | { 190 | ISeqInStream s; 191 | ILookInStream *realStream; 192 | } CSecToLook; 193 | 194 | void SecToLook_CreateVTable(CSecToLook *p); 195 | 196 | typedef struct 197 | { 198 | ISeqInStream s; 199 | ILookInStream *realStream; 200 | } CSecToRead; 201 | 202 | void SecToRead_CreateVTable(CSecToRead *p); 203 | 204 | typedef struct 205 | { 206 | SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize); 207 | /* Returns: result. (result != SZ_OK) means break. 208 | Value (UInt64)(Int64)-1 for size means unknown value. */ 209 | } ICompressProgress; 210 | 211 | typedef struct 212 | { 213 | void *(*Alloc)(void *p, size_t size); 214 | void (*Free)(void *p, void *address); /* address can be 0 */ 215 | } ISzAlloc; 216 | 217 | #define IAlloc_Alloc(p, size) (p)->Alloc((p), size) 218 | #define IAlloc_Free(p, a) (p)->Free((p), a) 219 | 220 | #ifdef _WIN32 221 | 222 | #define CHAR_PATH_SEPARATOR '\\' 223 | #define WCHAR_PATH_SEPARATOR L'\\' 224 | #define STRING_PATH_SEPARATOR "\\" 225 | #define WSTRING_PATH_SEPARATOR L"\\" 226 | 227 | #else 228 | 229 | #define CHAR_PATH_SEPARATOR '/' 230 | #define WCHAR_PATH_SEPARATOR L'/' 231 | #define STRING_PATH_SEPARATOR "/" 232 | #define WSTRING_PATH_SEPARATOR L"/" 233 | 234 | #endif 235 | 236 | #endif 237 | -------------------------------------------------------------------------------- /src/stage2/lzma/lzma.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Wrapper for LZMA decompression 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "LzmaDec.h" 13 | 14 | #define LZMA_DATA_OFFSET (LZMA_PROPS_SIZE + sizeof(uint64_t)) 15 | 16 | static void *lzma_malloc(void *p, size_t size) 17 | { 18 | return malloc(size); 19 | } 20 | 21 | static void lzma_free(void *p, void *address) 22 | { 23 | } 24 | 25 | int lzma_uncompress(const void *comp_data, uint32_t comp_size, 26 | void *decomp_data, uint32_t *decomp_size) 27 | { 28 | int i, ret; 29 | const uint8_t *p; 30 | ELzmaStatus state; 31 | ISzAlloc lzma_alloc; 32 | SizeT dst_len, src_len; 33 | uint32_t real_decomp_size = 0; 34 | 35 | p = comp_data + LZMA_PROPS_SIZE; 36 | 37 | for (i = 0; i < 4; i++) 38 | real_decomp_size |= (uint32_t)p[i + 4] << (i * 8); 39 | 40 | if (real_decomp_size) { 41 | puts("LZMA uncompressed data is too large\n"); 42 | return -ENOTSUPP; 43 | } 44 | 45 | real_decomp_size = 0; 46 | 47 | for (i = 0; i < 4; i++) 48 | real_decomp_size |= (uint32_t)p[i] << (i * 8); 49 | 50 | if (!*decomp_size) 51 | dst_len = real_decomp_size; 52 | else 53 | dst_len = real_decomp_size < *decomp_size ? real_decomp_size : 54 | *decomp_size; 55 | 56 | src_len = comp_size - LZMA_PROPS_SIZE; 57 | 58 | lzma_alloc.Alloc = lzma_malloc; 59 | lzma_alloc.Free = lzma_free; 60 | 61 | memset(&state, 0, sizeof(state)); 62 | 63 | ret = LzmaDecode(decomp_data, &dst_len, comp_data + LZMA_DATA_OFFSET, 64 | &src_len, comp_data, LZMA_PROPS_SIZE, LZMA_FINISH_END, 65 | &state, &lzma_alloc); 66 | if (ret != SZ_OK) 67 | return ret; 68 | 69 | *decomp_size = dst_len; 70 | 71 | return 0; 72 | } 73 | -------------------------------------------------------------------------------- /src/stage2/main.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * 2nd-stage main routine 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | static void load_stage3(void); 21 | 22 | static uint32_t membase, memsize, stage3_offset; 23 | 24 | void __noreturn stage2_main(void) 25 | { 26 | target_init(); 27 | 28 | puts("\n"); 29 | puts("Low-level initialization program for MT7621 [Version 1.0]\n"); 30 | puts("Copyright (C) 2020 Weijie Gao \n"); 31 | printf("DRAM: %uMB\n", memsize >> 20); 32 | puts("\n"); 33 | 34 | malloc_init(membase + memsize); 35 | make_crc32_table(); 36 | spi_nand_load_init(); 37 | load_stage3(); 38 | 39 | while (1); 40 | 41 | unreachable(); 42 | } 43 | 44 | void set_meminfo(uint32_t base, uint32_t size) 45 | { 46 | membase = base; 47 | memsize = size; 48 | } 49 | 50 | void set_stage3_offset(uint32_t offset) 51 | { 52 | stage3_offset = offset; 53 | } 54 | 55 | static void load_stage3_breed(bootstrap_kernel_header_t *hdr) 56 | { 57 | uint32_t size, load_addr, ep, decsize = 0; 58 | kernel_entry_point_t breed_ep; 59 | void *payload; 60 | int ret; 61 | 62 | size = be32_to_cpu(hdr->length); 63 | load_addr = be32_to_cpu(hdr->load_address); 64 | ep = be32_to_cpu(hdr->entry_point); 65 | 66 | puts("\n"); 67 | puts("Stage3 is Breed\n"); 68 | printf("Payload size : 0x%x\n", size); 69 | printf("Payload load address : 0x%x\n", load_addr); 70 | printf("Payload entry point : 0x%x\n", ep); 71 | puts("\n"); 72 | 73 | payload = malloc(size); 74 | 75 | ret = spi_nand_load_skip_bad(stage3_offset + sizeof(*hdr), payload, 76 | size); 77 | spi_nand_read_page_to_cache(0); 78 | if (ret && ret != -EBADMSG) { 79 | puts("Failed to load stage3!\n"); 80 | return; 81 | } 82 | 83 | ret = lzma_uncompress(payload, size, (void *)load_addr, &decsize); 84 | if (ret) { 85 | printf("LZMA decompression error %u\n", ret); 86 | return; 87 | } 88 | 89 | flush_l1_cache_range(load_addr, decsize); 90 | 91 | breed_ep = (kernel_entry_point_t)ep; 92 | breed_ep(memsize); 93 | 94 | unreachable(); 95 | } 96 | 97 | static void load_stage3_u_boot(uboot_image_header_t *hdr) 98 | { 99 | uint32_t size, load_addr, ep, ocrc, ncrc, decsize = 0; 100 | u_boot_entry_point_t u_boot_ep; 101 | void *payload; 102 | int ret; 103 | 104 | ocrc = be32_to_cpu(hdr->ih_hcrc); 105 | hdr->ih_hcrc = 0; 106 | ncrc = crc32(0, hdr, sizeof(*hdr)); 107 | 108 | if (ocrc != ncrc) { 109 | printf("Wrong header CRC. Expect %08x, got %08x\n", ocrc, ncrc); 110 | return; 111 | } 112 | 113 | size = be32_to_cpu(hdr->ih_size); 114 | load_addr = be32_to_cpu(hdr->ih_load); 115 | ep = be32_to_cpu(hdr->ih_ep); 116 | 117 | puts("\n"); 118 | puts("Stage3 is U-Boot\n"); 119 | printf("Payload size : 0x%x\n", size); 120 | printf("Payload load address : 0x%x\n", load_addr); 121 | printf("Payload entry point : 0x%x\n", ep); 122 | puts("\n"); 123 | 124 | if (hdr->ih_comp == UBOOT_IH_COMP_NONE) { 125 | ret = spi_nand_load_skip_bad(stage3_offset + sizeof(*hdr), 126 | (void *)load_addr, size); 127 | spi_nand_read_page_to_cache(0); 128 | if (ret && ret != -EBADMSG) { 129 | puts("Failed to load stage3!\n"); 130 | return; 131 | } 132 | 133 | flush_l1_cache_range(load_addr, size); 134 | } else if (hdr->ih_comp == UBOOT_IH_COMP_LZMA) { 135 | payload = malloc(size); 136 | 137 | ret = spi_nand_load_skip_bad(stage3_offset + sizeof(*hdr), 138 | payload, size); 139 | spi_nand_read_page_to_cache(0); 140 | if (ret && ret != -EBADMSG) { 141 | puts("Failed to load stage3!\n"); 142 | return; 143 | } 144 | 145 | ret = lzma_uncompress(payload, size, (void *)load_addr, 146 | &decsize); 147 | if (ret) { 148 | printf("LZMA decompression error %u\n", ret); 149 | return; 150 | } 151 | 152 | flush_l1_cache_range(load_addr, decsize); 153 | } else { 154 | printf("Unsupported compression method %u\n", hdr->ih_comp); 155 | return; 156 | } 157 | 158 | u_boot_ep = (u_boot_entry_point_t)ep; 159 | u_boot_ep(); 160 | 161 | unreachable(); 162 | } 163 | 164 | static void load_stage3(void) 165 | { 166 | int ret; 167 | 168 | union { 169 | uboot_image_header_t u_boot; 170 | bootstrap_kernel_header_t breed; 171 | } hdr; 172 | 173 | ret = spi_nand_load_skip_bad(stage3_offset, &hdr, sizeof(hdr)); 174 | spi_nand_read_page_to_cache(0); 175 | if (ret && ret != -EBADMSG) { 176 | puts("Failed to read stage3 header!\n"); 177 | return; 178 | } 179 | 180 | if (be32_to_cpu(hdr.breed.magic) == BOOTSTRAP_HDR_MAGIC) 181 | load_stage3_breed(&hdr.breed); 182 | else if (be32_to_cpu(hdr.u_boot.ih_magic) == UBOOT_IH_MAGIC) 183 | load_stage3_u_boot(&hdr.u_boot); 184 | else 185 | puts("Unrecognized stage3 payload!\n"); 186 | } 187 | -------------------------------------------------------------------------------- /src/stage2/malloc.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Simple memory pool 6 | */ 7 | 8 | #include 9 | 10 | static uintptr_t malloc_base; 11 | 12 | void malloc_init(uintptr_t base) 13 | { 14 | malloc_base = base; 15 | } 16 | 17 | void *malloc(size_t size) 18 | { 19 | if (size < sizeof(uintptr_t)) 20 | size = sizeof(uintptr_t); 21 | 22 | malloc_base -= size; 23 | malloc_base &= ~(16 - 1); 24 | 25 | return (void *)malloc_base; 26 | } 27 | -------------------------------------------------------------------------------- /src/stage2/memsize.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Memory size detection for MIPS platform 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | static void __nomips16 sync(void) 12 | { 13 | asm volatile ("sync"); 14 | } 15 | 16 | uintptr_t get_mem_size(uintptr_t base, uintptr_t limit) 17 | { 18 | volatile uintptr_t *check_base, *check_ptr; 19 | uintptr_t size, off, curr, orig_base, orig_ptr; 20 | int addrbit; 21 | 22 | check_base = (volatile uintptr_t *)base; 23 | 24 | /* Backup original base data */ 25 | sync(); 26 | orig_base = *check_base; 27 | sync(); 28 | 29 | for (addrbit = 3; ; addrbit++) { 30 | size = (uintptr_t)1 << addrbit; 31 | if (size >= limit) { 32 | size = limit; 33 | break; 34 | } 35 | 36 | off = base + size; 37 | check_ptr = (volatile uintptr_t *)off; 38 | 39 | /* Backup original ptr data */ 40 | sync(); 41 | orig_ptr = *check_ptr; 42 | 43 | /* Write differnet value to base then ptr */ 44 | sync(); 45 | *check_base = off; 46 | sync(); 47 | *check_ptr = ~off; 48 | 49 | /* Fetch value from base after ptr is written */ 50 | sync(); 51 | curr = *check_base; 52 | 53 | /* Check if the value of base got changed */ 54 | if (curr != off) 55 | break; 56 | 57 | /* Restore value of ptr */ 58 | sync(); 59 | *check_ptr = orig_ptr; 60 | } 61 | 62 | /* Restore value of base */ 63 | sync(); 64 | *check_base = orig_base; 65 | sync(); 66 | 67 | return size; 68 | } 69 | -------------------------------------------------------------------------------- /src/stage2/printf.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Simple printf implementation 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | static const char hex2chars[] = "0123456789abcdef"; 14 | 15 | static bool isdigit(char c) 16 | { 17 | return c >= '0' && c <= '9'; 18 | } 19 | 20 | static uint32_t uintptr_to_dec(uintptr_t value, char *buff) 21 | { 22 | char tmpbuf[3 * sizeof(value)]; 23 | uint32_t numdigits = 0, p; 24 | 25 | do { 26 | tmpbuf[numdigits++] = value % 10 + '0'; 27 | value /= 10; 28 | } while (value); 29 | 30 | p = 0; 31 | while (p < numdigits) { 32 | *buff++ = tmpbuf[numdigits - p - 1]; 33 | p++; 34 | } 35 | 36 | *buff = 0; 37 | 38 | return numdigits; 39 | } 40 | 41 | static uint32_t uintptr_to_hex(uintptr_t value, char *buff) 42 | { 43 | char tmpbuf[2 * sizeof(value) + 1]; 44 | uint32_t numdigits = 0, p; 45 | 46 | do { 47 | tmpbuf[numdigits++] = hex2chars[value & 0xf]; 48 | value >>= 4; 49 | } while (value); 50 | 51 | p = 0; 52 | while (p < numdigits) { 53 | *buff++ = tmpbuf[numdigits - p - 1]; 54 | p++; 55 | } 56 | 57 | *buff = 0; 58 | 59 | return numdigits; 60 | } 61 | 62 | static uintptr_t dec_to_uintptr(const char *str, char **end) 63 | { 64 | uintptr_t value = 0, numdigits = 0; 65 | bool neg = false; 66 | 67 | if (end) 68 | *end = (char *)str; 69 | 70 | if (*str == '-') { 71 | neg = true; 72 | str++; 73 | } 74 | 75 | while (isdigit(*str)) { 76 | value *= 10; 77 | value += *str - '0'; 78 | str++; 79 | numdigits++; 80 | } 81 | 82 | if (!numdigits) 83 | return 0; 84 | 85 | if (*end) 86 | *end = (char *)str; 87 | 88 | if (neg) 89 | value = -(intptr_t)value; 90 | 91 | return value; 92 | } 93 | 94 | static uint32_t print_fmt_one(const char *str, uintptr_t size, uintptr_t width, 95 | bool zeropfx) 96 | { 97 | uintptr_t bodylen; 98 | uint32_t numdigits = 0; 99 | char padding; 100 | 101 | if (zeropfx) 102 | padding = '0'; 103 | else 104 | padding = ' '; 105 | 106 | bodylen = size; 107 | 108 | while (width > bodylen) { 109 | putc(padding); 110 | numdigits++; 111 | width--; 112 | } 113 | 114 | while (size) { 115 | putc(*str++); 116 | numdigits++; 117 | size--; 118 | } 119 | 120 | return numdigits; 121 | } 122 | 123 | int vprintf(const char *fmt, va_list args) 124 | { 125 | uint32_t numdigits = 0, buflen; 126 | uintptr_t width, slen; 127 | bool zeropfx; 128 | uintptr_t num; 129 | char buff[32], *s; 130 | const char *fmt_start = fmt; 131 | 132 | while (*fmt) { 133 | width = 0; 134 | 135 | if (*fmt != '%') { 136 | if (*fmt == '\n') { 137 | if (fmt > fmt_start) { 138 | if (fmt[-1] != '\r') 139 | putc('\r'); 140 | } else { 141 | if (fmt[1] == 0) 142 | putc('\r'); 143 | } 144 | } 145 | 146 | putc(*fmt++); 147 | numdigits++; 148 | continue; 149 | } 150 | 151 | zeropfx = false; 152 | fmt++; 153 | 154 | if (*fmt == '0') { 155 | fmt++; 156 | if (isdigit(*fmt)) { 157 | width = dec_to_uintptr(fmt, (char **)&fmt); 158 | zeropfx = true; 159 | } 160 | } 161 | 162 | switch (*fmt) { 163 | case 'u': 164 | num = va_arg(args, unsigned int); 165 | buflen = uintptr_to_dec(num, buff); 166 | numdigits += print_fmt_one(buff, buflen, width, zeropfx); 167 | break; 168 | case 'x': 169 | num = va_arg(args, unsigned int); 170 | buflen = uintptr_to_hex(num, buff); 171 | numdigits += print_fmt_one(buff, buflen, width, zeropfx); 172 | break; 173 | case 's': 174 | s = va_arg(args, char *); 175 | slen = strlen(s); 176 | numdigits += print_fmt_one(s, slen, width, zeropfx); 177 | break; 178 | case '%': 179 | putc(*fmt++); 180 | numdigits++; 181 | break; 182 | default: 183 | putc('%'); 184 | numdigits++; 185 | 186 | if (*fmt) { 187 | putc(*fmt); 188 | numdigits++; 189 | break; 190 | } 191 | 192 | return numdigits; 193 | } 194 | 195 | fmt++; 196 | } 197 | 198 | return numdigits; 199 | } 200 | 201 | int printf(const char *fmt, ...) 202 | { 203 | va_list args; 204 | int len; 205 | 206 | va_start(args, fmt); 207 | len = vprintf(fmt, args); 208 | va_end(args); 209 | 210 | return len; 211 | } 212 | -------------------------------------------------------------------------------- /src/stage2/spi-nand-load.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * SPI-NAND driver with bad block skipping mechanism 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #define SPI_NAND_CMD_READ_CACHE 0x03 22 | #define SPI_NAND_CMD_GET_FEATURE 0x0f 23 | #define SPI_NAND_CMD_READ_PAGE_TO_CACHE 0x13 24 | #define SPI_NAND_CMD_SET_FEATURE 0x1f 25 | #define SPI_NAND_CMD_READ_ID 0x9f 26 | #define SPI_NAND_CMD_RESET 0xff 27 | 28 | #define SPI_NAND_FEATURE_CONFIG_ADDR 0xb0 29 | #define SPI_NAND_CR_BIT_ECCEN BIT(4) 30 | 31 | #define SPI_NAND_FEATURE_STATUS 0xc0 32 | #define SPI_NAND_SR_BIT_OIP BIT(0) 33 | 34 | #define SPI_NAND_FEATURE_MICRON_DIE_ADDR 0xd0 35 | #define SPI_NAND_MICRON_DIE_SEL_1 BIT(6) 36 | 37 | #define TIMEOUT 1000000 38 | #define SPI_NAND_TIMING_RESET 1000 39 | 40 | 41 | #define SPI_NAND_ID_MAX_LEN 4 42 | 43 | struct spi_nand_id { 44 | uint8_t len; 45 | uint8_t id[SPI_NAND_ID_MAX_LEN]; 46 | }; 47 | 48 | #define SPI_NAND_ID(...) \ 49 | { .id = { __VA_ARGS__ }, .len = sizeof((uint8_t[]){ __VA_ARGS__ }) } 50 | 51 | struct spi_nand_memorg { 52 | uint16_t pagesize; 53 | uint16_t sparesize; 54 | uint16_t pages_per_block; 55 | uint16_t blocks_per_die; 56 | uint16_t planes_per_die; 57 | uint16_t ndies; 58 | }; 59 | 60 | #define SPI_NAND_MEMORG(_ps, _ss, _ppb, _bpd, _ppd, _nd) \ 61 | { .pagesize = (_ps), .sparesize = (_ss), .pages_per_block = (_ppb), \ 62 | .blocks_per_die = (_bpd), .planes_per_die = (_ppd), .ndies = (_nd)} 63 | 64 | struct spi_nand_ecccfg { 65 | uint16_t msb; 66 | uint16_t lsb; 67 | const int8_t *bitflips; 68 | }; 69 | 70 | #define SPI_NAND_ECCCFG(_msb, _lsb, _bitflips) \ 71 | { .msb = (_msb), .lsb = (_lsb), .bitflips = (_bitflips) } 72 | 73 | typedef int (*snand_select_die_t)(uint32_t dieidx); 74 | 75 | struct spi_nand_info { 76 | const char *model; 77 | struct spi_nand_id id; 78 | struct spi_nand_memorg memorg; 79 | struct spi_nand_ecccfg ecccfg; 80 | snand_select_die_t select_die; 81 | }; 82 | 83 | #define SPI_NAND_INFO(_model, _id, _memorg, _ecccfg, ...) \ 84 | { .model = (_model), .id = _id, .memorg = _memorg, .ecccfg = _ecccfg, \ 85 | __VA_ARGS__ } 86 | 87 | #define SPI_NAND_MEMORG_1G_2K_64 SPI_NAND_MEMORG(2048, 64, 64, 1024, 1, 1) 88 | #define SPI_NAND_MEMORG_1G_2K_128 SPI_NAND_MEMORG(2048, 128, 64, 1024, 1, 1) 89 | #define SPI_NAND_MEMORG_2G_2K_128_2P SPI_NAND_MEMORG(2048, 128, 64, 2048, 2, 1) 90 | #define SPI_NAND_MEMORG_4G_4K_256 SPI_NAND_MEMORG(4096, 256, 64, 2048, 1, 1) 91 | #define SPI_NAND_MEMORG_4G_2K_128_2P_2D SPI_NAND_MEMORG(2048, 128, 64, 2048, 2, 2) 92 | #define SPI_NAND_MEMORG_8G_4K_256_2D SPI_NAND_MEMORG(4096, 256, 64, 2048, 1, 2) 93 | 94 | static int micron_select_die(uint32_t dieidx); 95 | 96 | static const int8_t ecc_bitflips_2[] = { 0, 4, -1, -1 }; 97 | static const int8_t ecc_bitflips_3[] = { 0, 3, -1, 6, -1, 8, -1, -1 }; 98 | 99 | static const struct spi_nand_info spi_nand_ids[] = { 100 | SPI_NAND_INFO("MT29F1G01AAADD", SPI_NAND_ID(0x2c, 0x12), 101 | SPI_NAND_MEMORG_1G_2K_64, 102 | SPI_NAND_ECCCFG(5, 4, ecc_bitflips_2)), 103 | SPI_NAND_INFO("MT29F1G01ABAFD", SPI_NAND_ID(0x2c, 0x14), 104 | SPI_NAND_MEMORG_1G_2K_128, 105 | SPI_NAND_ECCCFG(6, 4, ecc_bitflips_3)), 106 | SPI_NAND_INFO("MT29F2G01ABAGD", SPI_NAND_ID(0x2c, 0x24), 107 | SPI_NAND_MEMORG_2G_2K_128_2P, 108 | SPI_NAND_ECCCFG(6, 4, ecc_bitflips_3)), 109 | SPI_NAND_INFO("MT29F4G01ABAFD", SPI_NAND_ID(0x2c, 0x34), 110 | SPI_NAND_MEMORG_4G_4K_256, 111 | SPI_NAND_ECCCFG(6, 4, ecc_bitflips_3)), 112 | SPI_NAND_INFO("MT29F4G01ADAGD", SPI_NAND_ID(0x2c, 0x36), 113 | SPI_NAND_MEMORG_4G_2K_128_2P_2D, 114 | SPI_NAND_ECCCFG(6, 4, ecc_bitflips_3), 115 | micron_select_die), 116 | SPI_NAND_INFO("MT29F8G01ADAFD", SPI_NAND_ID(0x2c, 0x46), 117 | SPI_NAND_MEMORG_8G_4K_256_2D, 118 | SPI_NAND_ECCCFG(6, 4, ecc_bitflips_3), 119 | micron_select_die), 120 | }; 121 | 122 | static const struct spi_nand_info *spi_nand_chip; 123 | static uint32_t writesize, writesize_mask, writesize_shift; 124 | static uint32_t erasesize, erasesize_mask, erasesize_shift; 125 | static uint64_t diesize, diesize_mask, chipsize; 126 | static uint32_t diesize_shift, ndies, oobsize; 127 | static uint32_t eccmask, eccshift; 128 | static const int8_t *ecc_bitflips; 129 | static snand_select_die_t select_die; 130 | static uint8_t *page_cache; 131 | static uint32_t curr_dieidx; 132 | 133 | static void spi_nand_reset(void) 134 | { 135 | uint8_t op = SPI_NAND_CMD_RESET; 136 | 137 | spi_en(); 138 | spi_write(&op, 1); 139 | spi_dis(); 140 | 141 | udelay(SPI_NAND_TIMING_RESET); 142 | } 143 | 144 | static void spi_nand_read_id(uint8_t *id) 145 | { 146 | uint8_t op[2] = { SPI_NAND_CMD_READ_ID, 0 }; 147 | 148 | spi_en(); 149 | spi_write(op, sizeof(op)); 150 | spi_read(id, 4); 151 | spi_dis(); 152 | } 153 | 154 | static uint8_t spi_nand_get_feature(uint8_t addr) 155 | { 156 | uint8_t op[2] = { SPI_NAND_CMD_GET_FEATURE, addr }; 157 | uint8_t val; 158 | 159 | spi_en(); 160 | spi_write(op, sizeof(op)); 161 | spi_read(&val, 1); 162 | spi_dis(); 163 | 164 | return val; 165 | } 166 | 167 | static void spi_nand_set_feature(uint8_t addr, uint8_t val) 168 | { 169 | uint8_t op[3] = { SPI_NAND_CMD_SET_FEATURE, addr, val }; 170 | 171 | spi_en(); 172 | spi_write(op, sizeof(op)); 173 | spi_dis(); 174 | } 175 | 176 | static void spi_nand_enable_ecc(void) 177 | { 178 | uint8_t val; 179 | 180 | val = spi_nand_get_feature(SPI_NAND_FEATURE_CONFIG_ADDR); 181 | val |= SPI_NAND_CR_BIT_ECCEN; 182 | spi_nand_set_feature(SPI_NAND_FEATURE_CONFIG_ADDR, val); 183 | } 184 | 185 | static int micron_select_die(uint32_t dieidx) 186 | { 187 | uint8_t val; 188 | 189 | val = spi_nand_get_feature(SPI_NAND_FEATURE_MICRON_DIE_ADDR); 190 | if (!dieidx) 191 | val &= ~SPI_NAND_MICRON_DIE_SEL_1; 192 | else 193 | val |= SPI_NAND_MICRON_DIE_SEL_1; 194 | spi_nand_set_feature(SPI_NAND_FEATURE_MICRON_DIE_ADDR, val); 195 | 196 | return 0; 197 | } 198 | 199 | static int spi_nand_select_die(uint32_t dieidx) 200 | { 201 | int ret; 202 | 203 | if (ndies == 1 || !select_die) 204 | return 0; 205 | 206 | if (dieidx >= ndies) { 207 | printf("Invalid die index: %u\n", dieidx); 208 | return -EINVAL; 209 | } 210 | 211 | if (curr_dieidx == dieidx) 212 | return 0; 213 | 214 | ret = select_die(dieidx); 215 | if (!ret) 216 | curr_dieidx = dieidx; 217 | 218 | return ret; 219 | } 220 | 221 | static int spi_nand_poll(void) 222 | { 223 | uint8_t val; 224 | uint64_t start_time = get_timer(0); 225 | 226 | while (1) { 227 | val = spi_nand_get_feature(SPI_NAND_FEATURE_STATUS); 228 | 229 | if ((val & SPI_NAND_SR_BIT_OIP) == 0) 230 | return 0; 231 | 232 | if (get_timer(start_time) > TIMEOUT) 233 | return -ETIMEDOUT; 234 | } 235 | } 236 | 237 | static void spi_nand_init_chip(void) 238 | { 239 | uint32_t i; 240 | 241 | for (i = 0; i < ndies; i++) { 242 | spi_nand_select_die(i); 243 | spi_nand_enable_ecc(); 244 | } 245 | 246 | if (ndies > 1) 247 | spi_nand_select_die(0); 248 | } 249 | 250 | static void spi_nand_addr_to_pa_ca(uint64_t addr, uint32_t *pa, uint32_t *ca) 251 | { 252 | *pa = __lshr64(addr, writesize_shift); 253 | *ca = addr & writesize_mask; 254 | 255 | if (__lshr64(addr, erasesize_shift) & 1) 256 | *ca |= (1 << (writesize_shift + 1)); 257 | } 258 | 259 | int spi_nand_read_page_to_cache(uint32_t pa) 260 | { 261 | uint8_t op[4]; 262 | 263 | op[0] = SPI_NAND_CMD_READ_PAGE_TO_CACHE; 264 | op[1] = (pa >> 16) & 0xff; 265 | op[2] = (pa >> 8) & 0xff; 266 | op[3] = pa & 0xff; 267 | 268 | spi_en(); 269 | spi_write(op, sizeof(op)); 270 | spi_dis(); 271 | 272 | return spi_nand_poll(); 273 | } 274 | 275 | static void spi_nand_read_page_cache(uint32_t ca, void *buf, uint32_t len) 276 | { 277 | uint8_t op[4]; 278 | 279 | op[0] = SPI_NAND_CMD_READ_CACHE; 280 | op[1] = 0; 281 | op[2] = (ca >> 8) & 0xff; 282 | op[3] = ca & 0xff; 283 | 284 | spi_en(); 285 | spi_write(op, sizeof(op)); 286 | spi_read(buf, len); 287 | spi_dis(); 288 | } 289 | 290 | static int spi_nand_get_ecc_status(void) 291 | { 292 | uint8_t val = spi_nand_get_feature(SPI_NAND_FEATURE_STATUS); 293 | uint32_t ecc_status = (val & eccmask) >> eccshift; 294 | 295 | if (ecc_bitflips[ecc_status] < 0) 296 | return -EBADMSG; 297 | 298 | return ecc_bitflips[ecc_status]; 299 | } 300 | 301 | static int spi_nand_read_page(uint64_t addr, void *buf, uint32_t len) 302 | { 303 | uint32_t pa, ca, dieidx = 0; 304 | uint64_t die_addr = addr; 305 | int ret; 306 | 307 | if (addr >= chipsize) 308 | return -EINVAL; 309 | 310 | if (ndies > 1) { 311 | die_addr = addr & diesize_mask; 312 | dieidx = __lshr64(addr, diesize_shift); 313 | } 314 | 315 | spi_nand_select_die(dieidx); 316 | 317 | spi_nand_addr_to_pa_ca(die_addr, &pa, &ca); 318 | 319 | if ((ca & writesize_mask) + len >= writesize + oobsize) 320 | return -EINVAL; 321 | 322 | ret = spi_nand_read_page_to_cache(pa); 323 | if (ret) { 324 | spi_nand_reset(); 325 | spi_nand_init_chip(); 326 | return ret; 327 | } 328 | 329 | ret = spi_nand_get_ecc_status(); 330 | 331 | spi_nand_read_page_cache(ca, buf, len); 332 | 333 | if (ret < 0) 334 | return ret; 335 | 336 | return 0; 337 | } 338 | 339 | static void spi_nand_print_error(int ret, uint64_t addr) 340 | { 341 | uint32_t page = __lshr64(addr, writesize_shift); 342 | 343 | if (ret == -EBADMSG) 344 | printf("Uncorrectable bitflips in page %u\n", page); 345 | else if (ret == -ETIMEDOUT) 346 | printf("Timed out while reading page %u\n", page); 347 | else 348 | printf("Failed to read page %u\n", page); 349 | } 350 | 351 | int spi_nand_load_init(void) 352 | { 353 | uint8_t id[SPI_NAND_ID_MAX_LEN]; 354 | const struct spi_nand_id *fid = NULL; 355 | uint32_t i; 356 | 357 | spi_nand_reset(); 358 | spi_nand_read_id(id); 359 | 360 | for (i = 0; i < ARRAY_SIZE(spi_nand_ids); i++) { 361 | fid = &spi_nand_ids[i].id; 362 | 363 | if (!memcmp(fid->id, id, fid->len)) { 364 | spi_nand_chip = &spi_nand_ids[i]; 365 | break; 366 | } 367 | } 368 | 369 | if (!spi_nand_chip) { 370 | printf("SPI-NAND: Unrecognized ID: %02x %02x %02x %02x\n", 371 | id[0], id[1], id[2], id[3]); 372 | return -ENODEV; 373 | } 374 | 375 | oobsize = spi_nand_chip->memorg.sparesize; 376 | 377 | writesize = spi_nand_chip->memorg.pagesize; 378 | writesize_mask = writesize - 1; 379 | writesize_shift = ffs(writesize) - 1; 380 | 381 | erasesize = spi_nand_chip->memorg.pagesize * 382 | spi_nand_chip->memorg.pages_per_block; 383 | erasesize_mask = erasesize - 1; 384 | erasesize_shift = ffs(erasesize) - 1; 385 | 386 | diesize = (uint64_t)erasesize * spi_nand_chip->memorg.blocks_per_die; 387 | diesize_mask = diesize - 1; 388 | diesize_shift = ffs64(diesize) - 1; 389 | 390 | ndies = spi_nand_chip->memorg.ndies; 391 | chipsize = diesize * ndies; 392 | 393 | eccmask = GENMASK(spi_nand_chip->ecccfg.msb, spi_nand_chip->ecccfg.lsb); 394 | eccshift = spi_nand_chip->ecccfg.lsb; 395 | ecc_bitflips = spi_nand_chip->ecccfg.bitflips; 396 | 397 | select_die = spi_nand_chip->select_die; 398 | 399 | page_cache = malloc(writesize + oobsize); 400 | 401 | spi_nand_init_chip(); 402 | 403 | printf("SPI-NAND: %s (%uMB)\n", spi_nand_chip->model, 404 | (uint32_t)(__lshr64(chipsize, 20))); 405 | 406 | return 0; 407 | } 408 | 409 | int spi_nand_load_skip_bad(uint64_t addr, void *buff, uint32_t size) 410 | { 411 | uint32_t chksz, leading, blkofs; 412 | uint64_t off = addr, curr_addr; 413 | bool curr_page_read, check_bad = true; 414 | uint8_t *ptr = buff; 415 | int ret; 416 | 417 | while (size) { 418 | if (off >= chipsize) { 419 | printf("Reading exceeds flash size, %u bytes left\n", 420 | size); 421 | return -EIO; 422 | } 423 | 424 | curr_page_read = false; 425 | leading = off & writesize_mask; 426 | chksz = writesize - leading; 427 | if (chksz > size) 428 | chksz = size; 429 | 430 | if ((off & erasesize_mask) == 0 || check_bad) { 431 | curr_addr = off & (~erasesize_mask); 432 | ret = spi_nand_read_page(curr_addr, page_cache, 433 | writesize + 1); 434 | if (ret < 0) { 435 | spi_nand_print_error(ret, curr_addr); 436 | goto skip_block; 437 | } 438 | 439 | if (page_cache[writesize] != 0xff) { 440 | printf("Bad block at 0x%x\n", curr_addr); 441 | goto skip_block; 442 | } 443 | 444 | if (curr_addr == (off & (~writesize_mask))) 445 | curr_page_read = true; 446 | 447 | check_bad = false; 448 | } 449 | 450 | if (!curr_page_read) { 451 | curr_addr = off & (~writesize_mask); 452 | ret = spi_nand_read_page(curr_addr, page_cache, writesize); 453 | if (ret < 0) { 454 | spi_nand_print_error(ret, curr_addr); 455 | if (ret != -EBADMSG) 456 | return ret; 457 | } 458 | } 459 | 460 | memcpy(ptr, page_cache + leading, chksz); 461 | 462 | off += chksz; 463 | ptr += chksz; 464 | size -= chksz; 465 | 466 | continue; 467 | 468 | skip_block: 469 | blkofs = off & erasesize_mask; 470 | off |= erasesize_mask; 471 | off += blkofs + 1; 472 | check_bad = true; 473 | } 474 | 475 | return 0; 476 | } 477 | -------------------------------------------------------------------------------- /src/stage2/stage.mk: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | # Copyright (C) 2020 Weijie Gao 3 | 4 | ifeq ($(STAGE3_PAYLOAD),) 5 | ifneq ($(STAGE3_OFFSET),) 6 | CPPFLAGS += -DSTAGE3_OFFSET=$(STAGE3_OFFSET) 7 | endif 8 | endif 9 | 10 | COBJS += stage2/main.o \ 11 | stage2/printf.o \ 12 | stage2/console.o \ 13 | stage2/memsize.o \ 14 | stage2/timer.o \ 15 | stage2/div64.o \ 16 | stage2/lshr64.o \ 17 | stage2/malloc.o \ 18 | stage2/spi-nand-load.o \ 19 | stage2/lzma/LzmaDec.o \ 20 | stage2/lzma/lzma.o \ 21 | common/crc32.o 22 | 23 | BIN_OUT := $(OUTDIR)/$(STAGE)-pad.bin 24 | 25 | all: $(OUTDIR)/$(STAGE)-pad.bin 26 | 27 | cmd_page_pad = $(TOOLS_DIR)/padutil -a $(PAGESIZE) $< $@ 28 | 29 | $(OUTDIR)/$(STAGE)-pad.bin: $(OUTDIR)/$(STAGE).bin FORCE 30 | $(call if_changed,page_pad) -------------------------------------------------------------------------------- /src/stage2/timer.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Simple timer utilities for MIPS platform 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | static uint32_t timer_freq; 13 | static uint32_t ticks_hi, ticks_lo; 14 | 15 | static uint32_t __nomips16 get_counter(void) 16 | { 17 | uint32_t val; 18 | 19 | asm volatile ("mfc0\t%0,$9" : "=r"(val)); 20 | 21 | return val; 22 | } 23 | 24 | uint64_t get_ticks(void) 25 | { 26 | uint32_t new_ticks_lo = get_counter(); 27 | 28 | if (new_ticks_lo <= ticks_lo) 29 | ticks_hi++; 30 | 31 | ticks_lo = new_ticks_lo; 32 | 33 | return ((uint64_t)ticks_hi << 32) | ticks_lo; 34 | } 35 | 36 | static uint64_t tick_to_usec(uint64_t tick) 37 | { 38 | tick *= 1000000; 39 | __div64_32(&tick, timer_freq); 40 | 41 | return tick; 42 | } 43 | 44 | uint64_t get_timer(uint64_t base) 45 | { 46 | return tick_to_usec(get_ticks()) - base; 47 | } 48 | 49 | void udelay(uint32_t usec) 50 | { 51 | uint64_t tmo = get_timer(0) + usec; 52 | 53 | while (get_timer(0) < tmo) 54 | ; 55 | } 56 | 57 | void set_timer_freq(uint32_t freq) 58 | { 59 | timer_freq = freq; 60 | } 61 | -------------------------------------------------------------------------------- /toolchain/mipsel32r2-gcc_7.2.0-uClibc-ng_1.0.27-Win64.tar.xz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackpascal/mt7621-boot-spi-nand/799379a3b0e71a3e549eff5db3e34631f4354a76/toolchain/mipsel32r2-gcc_7.2.0-uClibc-ng_1.0.27-Win64.tar.xz -------------------------------------------------------------------------------- /tools/Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | # Copyright (C) 2020 Weijie Gao 3 | 4 | PROGS := padutil 5 | 6 | padutil_OBJS := padutil.o 7 | 8 | all: $(PROGS) 9 | 10 | $(PROGS): 11 | $(MAKE) -f Makefile.host PROG=$@ SRCDIR=$(SRCDIR) OUTDIR=$(OUTDIR)/build-$@ INSTALLDIR=$(OUTDIR) OBJS="$($(@F)_OBJS)" 12 | -------------------------------------------------------------------------------- /tools/Makefile.host: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | # Copyright (C) 2020 Weijie Gao 3 | 4 | include $(TOPDIR)/Makefile.build 5 | 6 | HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \ 7 | sed -e 's/\(cygwin\).*/cygwin/' \ 8 | -e 's/\(msys\).*/cygwin/' \ 9 | -e 's/\(mingw\).*/mingw/') 10 | 11 | ifneq ($(filter cygwin mingw,$(HOSTOS)),) 12 | EXE := .exe 13 | endif 14 | 15 | HOST_CFLAGS := -O2 -Wall -ffunction-sections -fdata-sections -ggdb -gdwarf-4 -flto 16 | HOST_LDFLAGS := -Wl,--gc-sections 17 | 18 | HOSTCC ?= gcc 19 | HOSTSTRIP ?= strip 20 | 21 | OBJS_OUT := $(addprefix $(OUTDIR)/,$(OBJS)) 22 | 23 | DEPS := $(addsuffix .dep,$(OBJS_OUT)) 24 | 25 | .SECONDEXPANSION: 26 | 27 | all: $(OUTDIR)/$(PROG)$(EXE) 28 | 29 | cmd_link = $(HOSTCC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ -Wl,--start-group $(OBJS_OUT) -Wl,--end-group 30 | 31 | $(OUTDIR)/$(PROG)$(EXE): $(OBJS_OUT) 32 | $(call if_changed,link) 33 | ifneq ($(INSTALLDIR),) 34 | $(HOSTSTRIP) -o $(INSTALLDIR)/$(@F) $@ 35 | endif 36 | 37 | cmd_compile = $(HOSTCC) $(HOST_CFLAGS) $(HOST_CPPFLAGS) -MD -c -o $@ $< 38 | 39 | $(OBJS_OUT): $(OUTDIR)/%.o: $(SRCDIR)/%.c | $$(@D)/ 40 | $(call if_changed_dep,compile) 41 | 42 | .PRECIOUS: $(OUTDIR)/ $(OUTDIR)%/ 43 | 44 | $(OUTDIR)/: 45 | mkdir -p $@ 46 | 47 | $(OUTDIR)%/: 48 | mkdir -p $@ 49 | 50 | clean: 51 | rm -f $(OUTDIR)/$(PROG) $(OBJS_OUT) $(DEPS) 52 | 53 | .PHONY: clean 54 | 55 | -include $(DEPS) 56 | -------------------------------------------------------------------------------- /tools/padutil.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* 3 | * Copyright (C) 2020 Weijie Gao 4 | * 5 | * Binary file padding utility 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | static uint32_t align_size; 17 | static uint32_t max_size; 18 | static uint8_t fill_char = 0xff; 19 | static bool show_verbose; 20 | static const char *input_file; 21 | static const char *output_file; 22 | 23 | static uint32_t input_file_size; 24 | static uint32_t padding_size; 25 | 26 | static void usage(FILE *con, const char *progname, int exitcode) 27 | { 28 | size_t proglen = strlen(progname); 29 | const char *prog = progname + proglen - 1; 30 | 31 | while (prog > progname) { 32 | if (*prog == '/' || *prog == '\\') { 33 | prog++; 34 | break; 35 | } 36 | 37 | prog--; 38 | } 39 | 40 | fprintf(con, 41 | "Binary pad utility\n" 42 | "\n" 43 | "Usage: %s [options] \n" 44 | "\n" 45 | "Options:\n" 46 | " -a File size aligned to \n" 47 | " -m Set max output file size\n" 48 | " -f Fill padding space with character \n" 49 | " -v Display file information\n" 50 | " -h Show this help\n", 51 | prog 52 | ); 53 | 54 | exit(exitcode); 55 | } 56 | 57 | static uint32_t parse_value(const char *optarg, const char optchar) 58 | { 59 | char *end; 60 | uint32_t val; 61 | 62 | val = strtoul(optarg, &end, 0); 63 | if ((end == optarg) || *end) { 64 | fprintf(stderr, "Error: -%c: '%s' is not a valid number\n", optchar, optarg); 65 | exit(1); 66 | } 67 | 68 | return val; 69 | } 70 | 71 | static void parse_arg(int argc, char *argv[]) 72 | { 73 | static const char optstr[] = "a:m:f:vh"; 74 | int opt; 75 | 76 | if (argc <= 1) 77 | usage(stdout, argv[0], 0); 78 | 79 | while ((opt = getopt(argc, argv, optstr)) != -1) { 80 | switch (opt) { 81 | case 'a': 82 | align_size = parse_value(optarg, opt); 83 | if (align_size <= 1) { 84 | fprintf(stderr, "Error: alignment size must be larger than 1\n"); 85 | exit(1); 86 | } 87 | break; 88 | case 'm': 89 | max_size = parse_value(optarg, opt); 90 | if (!max_size) { 91 | fprintf(stderr, "Error: max file size can't be zero\n"); 92 | exit(1); 93 | } 94 | break; 95 | case 'f': 96 | fill_char = parse_value(optarg, opt) & 0xff; 97 | break; 98 | case 'v': 99 | show_verbose = true; 100 | break; 101 | case 'h': 102 | usage(stdout, argv[0], 0); 103 | break; 104 | default: 105 | usage(stderr, argv[0], 1); 106 | break; 107 | } 108 | } 109 | 110 | if (argc <= optind) { 111 | fprintf(stderr, "Error: input file not specified\n"); 112 | exit(1); 113 | } 114 | 115 | if (argc - optind == 1) { 116 | fprintf(stderr, "Error: output file not specified\n"); 117 | exit(1); 118 | } 119 | 120 | input_file = argv[optind]; 121 | output_file = argv[optind + 1]; 122 | } 123 | 124 | static void process_file(void) 125 | { 126 | FILE *fin, *fout; 127 | uint8_t buff[64 << 10]; 128 | size_t rdsize, wrsize, sz2pad, padsize = 0; 129 | 130 | if (!strcmp(input_file, "-")) { 131 | if (freopen(NULL, "rb", stdin) != stdin) { 132 | fprintf(stderr, "Error: Failed to change mode of \n"); 133 | exit(1); 134 | } 135 | fin = stdin; 136 | input_file = ""; 137 | } else { 138 | fin = fopen(input_file, "rb"); 139 | if (!fin) { 140 | fprintf(stderr, "Error: Failed to open input file '%s'\n", input_file); 141 | exit(1); 142 | } 143 | } 144 | 145 | if (!strcmp(output_file, "-")) { 146 | if (freopen(NULL, "wb", stdout) != stdout) { 147 | fprintf(stderr, "Error: Failed to change mode of \n"); 148 | exit(1); 149 | } 150 | fout = stdout; 151 | output_file = ""; 152 | } else { 153 | fout = fopen(output_file, "wb"); 154 | if (!fout) { 155 | fprintf(stderr, "Error: failed to open output file '%s'\n", output_file); 156 | exit(1); 157 | } 158 | } 159 | 160 | while (true) { 161 | rdsize = fread(buff, 1, sizeof(buff), fin); 162 | if (!rdsize) { 163 | if (feof(fin)) 164 | break; 165 | 166 | fprintf(stderr, "Error occured while reading file '%s', error code %d\n", 167 | input_file, ferror(fin)); 168 | exit(1); 169 | } 170 | 171 | wrsize = fwrite(buff, 1, rdsize, fout); 172 | if (wrsize != rdsize) { 173 | fprintf(stderr, "Error occured while writing file '%s', error code %d\n", 174 | output_file, ferror(fout)); 175 | 176 | if (fout != stdout) { 177 | fclose(fout); 178 | remove(output_file); 179 | } 180 | 181 | exit(1); 182 | } 183 | 184 | input_file_size += wrsize; 185 | } 186 | 187 | if (fin != stdin) 188 | fclose(fin); 189 | 190 | if (align_size) { 191 | padding_size = input_file_size % align_size; 192 | if (padding_size) 193 | padding_size = align_size - padding_size; 194 | } 195 | 196 | if (max_size) { 197 | if (input_file_size + padding_size > max_size) { 198 | fprintf(stderr, "Error: output file is larger than %u bytes\n", max_size); 199 | 200 | if (fout != stdout) { 201 | fclose(fout); 202 | remove(output_file); 203 | } 204 | 205 | exit(1); 206 | } 207 | } 208 | 209 | if (padding_size) { 210 | memset(buff, fill_char, sizeof(buff)); 211 | 212 | while (padsize < padding_size) { 213 | sz2pad = padding_size - padsize; 214 | if (sz2pad > sizeof(buff)) 215 | sz2pad = sizeof(buff); 216 | 217 | wrsize = fwrite(buff, 1, sz2pad, fout); 218 | if (wrsize != sz2pad) { 219 | fprintf(stderr, "Error occured while padding file '%s', error code %d\n", 220 | output_file, ferror(fout)); 221 | 222 | if (fout != stdout) { 223 | fclose(fout); 224 | remove(output_file); 225 | } 226 | 227 | exit(1); 228 | } 229 | 230 | padsize += sz2pad; 231 | } 232 | } 233 | 234 | if (fout != stdout) 235 | fclose(fout); 236 | } 237 | 238 | static void display_info(void) 239 | { 240 | if (!show_verbose) 241 | return; 242 | 243 | printf( 244 | "Input file: %s\n" 245 | "Input size: %u (0x%x)\n", 246 | input_file, 247 | input_file_size, input_file_size 248 | ); 249 | 250 | printf("----------------------------------------\n"); 251 | 252 | printf( 253 | "Output file: %s\n" 254 | "Output size: %u (0x%x)\n", 255 | output_file, 256 | input_file_size + padding_size, input_file_size + padding_size 257 | ); 258 | 259 | if (padding_size) { 260 | printf( 261 | "Padding size: %u (0x%x)\n" 262 | "Fill char: 0x%02x\n", 263 | padding_size, padding_size, 264 | fill_char 265 | ); 266 | } 267 | 268 | if (max_size) { 269 | printf( 270 | "Maximum size: %u (0x%x)\n" 271 | "Space usage: %u%%", 272 | max_size, max_size, 273 | ((input_file_size + padding_size) * 100) / max_size 274 | ); 275 | } 276 | } 277 | 278 | int main(int argc, char *argv[]) 279 | { 280 | parse_arg(argc, argv); 281 | 282 | process_file(); 283 | 284 | display_info(); 285 | 286 | return 0; 287 | } 288 | --------------------------------------------------------------------------------