diff --git a/examples/rules.mk b/examples/rules.mk index 4cc35cb22..6314380ec 100644 --- a/examples/rules.mk +++ b/examples/rules.mk @@ -182,6 +182,11 @@ flash-jlink: $(BUILD)/$(PROJECT).hex flash-stlink: $(BUILD)/$(PROJECT).elf STM32_Programmer_CLI --connect port=swd --write $< --go +flash-xfel: $(BUILD)/$(PROJECT).bin + xfel ddr + xfel write 0x80000000 $< + xfel exec 0x80000000 + # Flash using pyocd PYOCD_OPTION ?= flash-pyocd: $(BUILD)/$(PROJECT).hex diff --git a/hw/bsp/f1c100s/README.md b/hw/bsp/f1c100s/README.md new file mode 100644 index 000000000..a4865b925 --- /dev/null +++ b/hw/bsp/f1c100s/README.md @@ -0,0 +1,17 @@ +# BSP support for F1Cx00s boards + +This folder contains necessary file and scripts to run TinyUSB examples on F1Cx00s boards. + +Currently tested on: + +* Lichee Pi Nano (F1C100s) + +## make flash +`make flash` will use [xfel](https://github.com/xboot/xfel) to write the code to onchip DDR memory and execute it. It will not write the program to SPI Flash. + +To enter FEL mode, you have to press BOOT button, then press RESET once, and release BOOT button. You will find VID/PID=1f3a:efe8 on your PC. + +## TODO +* Test on Tiny200 v2 (F1C200s) +* Make it able to load .bin directly to SPI Flash and boot +* Add F1C100s to `#if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX` high speed MCU check in examples (maybe we should extract the logic?) \ No newline at end of file diff --git a/hw/bsp/f1c100s/board.h b/hw/bsp/f1c100s/board.h new file mode 100644 index 000000000..238ac796d --- /dev/null +++ b/hw/bsp/f1c100s/board.h @@ -0,0 +1 @@ +// Nothing valuable here \ No newline at end of file diff --git a/hw/bsp/f1c100s/board.mk b/hw/bsp/f1c100s/board.mk new file mode 100644 index 000000000..993aa0d24 --- /dev/null +++ b/hw/bsp/f1c100s/board.mk @@ -0,0 +1,45 @@ +DEFINES += -D__ARM32_ARCH__=5 -D__ARM926EJS__ + +CFLAGS += \ + -ffreestanding \ + -std=gnu99 \ + -march=armv5te \ + -mtune=arm926ej-s \ + -mfloat-abi=soft \ + -marm \ + -mno-thumb-interwork \ + -Wno-unused-parameter \ + -Wno-float-equal \ + -DCFG_TUSB_MCU=OPT_MCU_F1C100S \ + -Wno-error=cast-align \ + -Wno-error=address-of-packed-member \ + $(DEFINES) + +LD_FILE = hw/mcu/allwinner/f1c100s/f1c100s.ld +LDFLAGS += -nostdlib -lgcc +MCU_DIR = hw/mcu/allwinner/f1c100s + +SRC_C += \ + src/portable/sunxi/dcd_sunxi_musb.c \ + $(MCU_DIR)/machine/sys-uart.c \ + $(MCU_DIR)/machine/exception.c \ + $(MCU_DIR)/machine/sys-clock.c \ + $(MCU_DIR)/machine/sys-copyself.c \ + $(MCU_DIR)/machine/sys-dram.c \ + $(MCU_DIR)/machine/sys-mmu.c \ + $(MCU_DIR)/machine/sys-spi-flash.c \ + $(MCU_DIR)/machine/f1c100s-intc.c \ + $(MCU_DIR)/lib/malloc.c \ + $(MCU_DIR)/lib/printf.c + +SRC_S += \ + $(MCU_DIR)/machine/start.S \ + $(MCU_DIR)/lib/memcpy.S \ + $(MCU_DIR)/lib/memset.S + +INC += \ + $(TOP)/$(MCU_DIR)/include \ + $(TOP)/$(BOARD_PATH) + +# flash target using on-board stlink +flash: flash-xfel diff --git a/hw/bsp/f1c100s/f1c100s.c b/hw/bsp/f1c100s/f1c100s.c new file mode 100644 index 000000000..6cf18597c --- /dev/null +++ b/hw/bsp/f1c100s/f1c100s.c @@ -0,0 +1,130 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include +#include +#include +#include +#include "bsp/board.h" +#include "board.h" + +extern void sys_uart_putc(char c); + +//--------------------------------------------------------------------+ +// Board porting API +//--------------------------------------------------------------------+ + +static void timer_init(void); + +void board_init(void) +{ + arch_local_irq_disable(); + do_init_mem_pool(); + f1c100s_intc_init(); + timer_init(); + printf("Timer INIT done\n"); + arch_local_irq_enable(); +} + +// No LED, no button, sorry +void board_led_write(bool state) +{ + +} + +uint32_t board_button_read(void) +{ + return 0; +} + +int board_uart_read(uint8_t* buf, int len) +{ + return 0; +} + +int board_uart_write(void const * buf, int len) +{ + int txsize = len; + while (txsize--) { + sys_uart_putc(*(uint8_t const*)buf); + buf++; + } + return len; +} + +#if CFG_TUSB_OS == OPT_OS_NONE +volatile uint32_t system_ticks = 0; + +uint32_t board_millis(void) +{ + return system_ticks; +} + +static void timer_handler(void) +{ + volatile uint32_t *temp_addr = (uint32_t *)(0x01C20C00 + 0x04); + + /* clear timer */ + *temp_addr |= 0x01; + + system_ticks++; +} + +static void timer_init(void) { + uint32_t temp; + volatile uint32_t *temp_addr; + + /* reload value */ + temp = 12000000 / 1000; + temp_addr = (uint32_t *)(0x01C20C00 + 0x14); + *temp_addr = temp; + + /* continuous | /2 | 24Mhz | reload*/ + temp = (0x00 << 7) | (0x01 << 4) | (0x01 << 2) | (0x00 << 1); + temp_addr = (uint32_t *)(0x01C20C00 + 0x10); + *temp_addr &= 0xffffff00; + *temp_addr |= temp; + + /* open timer irq */ + temp = 0x01 << 0; + temp_addr = (uint32_t *)(0x01C20C00); + *temp_addr |= temp; + + /* set init value */ + temp_addr = (uint32_t *)(0x01C20C00 + 0x18); + *temp_addr = 0; + + /* begin run timer */ + temp = 0x01 << 0; + temp_addr = (uint32_t *)(0x01C20C00 + 0x10); + *temp_addr |= temp; + + f1c100s_intc_set_isr(F1C100S_IRQ_TIMER0, timer_handler); + f1c100s_intc_enable_irq(F1C100S_IRQ_TIMER0); +} +#else +static void timer_init(void) { } +#endif diff --git a/hw/mcu/allwinner/f1c100s/f1c100s.ld b/hw/mcu/allwinner/f1c100s/f1c100s.ld new file mode 100644 index 000000000..a261618e5 --- /dev/null +++ b/hw/mcu/allwinner/f1c100s/f1c100s.ld @@ -0,0 +1,137 @@ +OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) + +STACK_UND_SIZE = 0x10000; +STACK_ABT_SIZE = 0x10000; +STACK_IRQ_SIZE = 0x10000; +STACK_FIQ_SIZE = 0x10000; +STACK_SRV_SIZE = 0x40000; + +MEMORY +{ + ram : org = 0x80000000, len = 8M + heap : org = 0x81000000, len = 16M +} + +SECTIONS +{ + .bootloader : + { + PROVIDE(__bootloader_start = .); + PROVIDE(__image_start = .); + PROVIDE(__text_start = .); + */machine/start.o (.text) + */lib/memcpy.o (.text) + */lib/memset.o (.text) + */machine/sys-uart.o (.text) + */machine/sys-clock.o (.text) + */machine/sys-dram.o (.text) + */machine/sys-mmu.o (.text) + */machine/sys-spi-flash.o (.text) + */machine/sys-copyself.o (.text) + PROVIDE(__bootloader_end = .); + } > ram + + __bootloader_size = SIZEOF(.bootloader); + + .text : + { + */main.o (.text) + *(.text*) + *(.glue*) + *(.note.gnu.build-id) + PROVIDE(__text_end = .); + } > ram + + .rodata ALIGN(8) : + { + PROVIDE(__rodata_start = .); + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) + PROVIDE(__rodata_end = .); + } > ram + + .data_shadow ALIGN(8) : + { + PROVIDE(__data_shadow_start = .); + PROVIDE(__data_shadow_end = (. + SIZEOF(.data))); + PROVIDE(__image_end = __data_shadow_end); + } > ram + + .data : AT(ADDR(.data_shadow)) + { + PROVIDE(__data_start = .); + *(.data*) + . = ALIGN(8); + PROVIDE(__data_end = .); + } > ram + + .ARM.exidx ALIGN(8) : + { + PROVIDE (__exidx_start = .); + *(.ARM.exidx*) + PROVIDE (__exidx_end = .); + } > ram + + .ARM.extab ALIGN(8) : + { + PROVIDE (__extab_start = .); + *(.ARM.extab*) + PROVIDE (__extab_end = .); + } > ram + + .bss ALIGN(8) (NOLOAD) : + { + PROVIDE(__bss_start = .); + *(.bss*) + *(.sbss*) + *(COMMON) + . = ALIGN(8); + PROVIDE(__bss_end = .); + } > ram + + .stack ALIGN(8) (NOLOAD) : + { + PROVIDE(__stack_start = .); + PROVIDE(__stack_und_start = .); + . += STACK_UND_SIZE; + PROVIDE(__stack_und_end = .); + . = ALIGN(8); + PROVIDE(__stack_abt_start = .); + . += STACK_ABT_SIZE; + PROVIDE(__stack_abt_end = .); + . = ALIGN(8); + PROVIDE(__stack_irq_start = .); + . += STACK_IRQ_SIZE; + PROVIDE(__stack_irq_end = .); + . = ALIGN(8); + PROVIDE(__stack_fiq_start = .); + . += STACK_FIQ_SIZE; + PROVIDE(__stack_fiq_end = .); + . = ALIGN(8); + PROVIDE(__stack_srv_start = .); + . += STACK_SRV_SIZE; + PROVIDE(__stack_srv_end = .); + . = ALIGN(8); + PROVIDE(__stack_end = .); + } > ram + + .heap ALIGN(8) (NOLOAD) : + { + PROVIDE(__heap_start = ORIGIN(heap)); + PROVIDE(__heap_end = ORIGIN(heap) + LENGTH(heap)); + } > heap + + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_info 0 : { *(.debug_info) } + .debug_line 0 : { *(.debug_line) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_aranges 0 : { *(.debug_aranges) } +} diff --git a/hw/mcu/allwinner/f1c100s/include/arm32.h b/hw/mcu/allwinner/f1c100s/include/arm32.h new file mode 100644 index 000000000..a3a254551 --- /dev/null +++ b/hw/mcu/allwinner/f1c100s/include/arm32.h @@ -0,0 +1,150 @@ +#ifndef __ARM32_H__ +#define __ARM32_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +struct arm_regs_t { + uint32_t r[13]; + uint32_t sp; + uint32_t lr; + uint32_t pc; + uint32_t cpsr; +}; + +static inline uint32_t arm32_read_p15_c1(void) +{ + uint32_t value; + + __asm__ __volatile__( + "mrc p15, 0, %0, c1, c0, 0" + : "=r" (value) + : + : "memory"); + + return value; +} + +static inline void arm32_write_p15_c1(uint32_t value) +{ + __asm__ __volatile__( + "mcr p15, 0, %0, c1, c0, 0" + : + : "r" (value) + : "memory"); + arm32_read_p15_c1(); +} + +static inline void arm32_interrupt_enable(void) +{ + uint32_t tmp; + + __asm__ __volatile__( + "mrs %0, cpsr\n" + "bic %0, %0, #(1<<7)\n" + "msr cpsr_cxsf, %0" + : "=r" (tmp) + : + : "memory"); +} + +static inline void arm32_interrupt_disable(void) +{ + uint32_t tmp; + + __asm__ __volatile__( + "mrs %0, cpsr\n" + "orr %0, %0, #(1<<7)\n" + "msr cpsr_cxsf, %0" + : "=r" (tmp) + : + : "memory"); +} + +static inline void arm32_mmu_enable(void) +{ + uint32_t value = arm32_read_p15_c1(); + arm32_write_p15_c1(value | (1 << 0)); +} + +static inline void arm32_mmu_disable(void) +{ + uint32_t value = arm32_read_p15_c1(); + arm32_write_p15_c1(value & ~(1 << 0)); +} + +static inline void arm32_dcache_enable(void) +{ + uint32_t value = arm32_read_p15_c1(); + arm32_write_p15_c1(value | (1 << 2)); +} + +static inline void arm32_dcache_disable(void) +{ + uint32_t value = arm32_read_p15_c1(); + arm32_write_p15_c1(value & ~(1 << 2)); +} + +static inline void arm32_icache_enable(void) +{ + uint32_t value = arm32_read_p15_c1(); + arm32_write_p15_c1(value | (1 << 12)); +} + +static inline void arm32_icache_disable(void) +{ + uint32_t value = arm32_read_p15_c1(); + arm32_write_p15_c1(value & ~(1 << 12)); +} + +static inline uint32_t arm32_smp_processor_id(void) +{ + uint32_t tmp; + + __asm__ __volatile__( + "mrc p15,0,%0,c0,c0,5\n" + "and %0,%0,#0x3\n" + : "=r" (tmp) + : + : "memory"); + return tmp; +} + +static inline void arm32_ttb_set(uint32_t base) +{ + __asm__ __volatile__( + "mcr p15, 0, %0, c2, c0, 0" + : + : "r" (base) + : "memory"); +} + +static inline void arm32_domain_set(uint32_t domain) +{ + __asm__ __volatile__( + "mcr p15, 0, %0, c3, c0, 0" + : + : "r" (domain) + : "memory"); +} + +static inline void arm32_tlb_invalidate(void) +{ + __asm__ __volatile__( + "mov r0, #0\n" + "mcr p15, 0, r0, c7, c10, 4\n" + "mcr p15, 0, r0, c8, c6, 0\n" + "mcr p15, 0, r0, c8, c5, 0\n" + : + : + : "r0"); +} + +#ifdef __cplusplus +} +#endif + +#endif /* __ARM32_H__ */ diff --git a/hw/mcu/allwinner/f1c100s/include/f1c100s-gpio.h b/hw/mcu/allwinner/f1c100s/include/f1c100s-gpio.h new file mode 100644 index 000000000..3dbe8bf13 --- /dev/null +++ b/hw/mcu/allwinner/f1c100s/include/f1c100s-gpio.h @@ -0,0 +1,66 @@ +#ifndef __F1C100S_GPIO_H__ +#define __F1C100S_GPIO_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define F1C100S_GPIOA0 (0) +#define F1C100S_GPIOA1 (1) +#define F1C100S_GPIOA2 (2) +#define F1C100S_GPIOA3 (3) + +#define F1C100S_GPIOC0 (64) +#define F1C100S_GPIOC1 (65) +#define F1C100S_GPIOC2 (66) +#define F1C100S_GPIOC3 (67) + +#define F1C100S_GPIOD0 (96) +#define F1C100S_GPIOD1 (97) +#define F1C100S_GPIOD2 (98) +#define F1C100S_GPIOD3 (99) +#define F1C100S_GPIOD4 (100) +#define F1C100S_GPIOD5 (101) +#define F1C100S_GPIOD6 (102) +#define F1C100S_GPIOD7 (103) +#define F1C100S_GPIOD8 (104) +#define F1C100S_GPIOD9 (105) +#define F1C100S_GPIOD10 (106) +#define F1C100S_GPIOD11 (107) +#define F1C100S_GPIOD12 (108) +#define F1C100S_GPIOD13 (109) +#define F1C100S_GPIOD14 (110) +#define F1C100S_GPIOD15 (111) +#define F1C100S_GPIOD16 (112) +#define F1C100S_GPIOD17 (113) +#define F1C100S_GPIOD18 (114) +#define F1C100S_GPIOD19 (115) +#define F1C100S_GPIOD20 (116) +#define F1C100S_GPIOD21 (117) + +#define F1C100S_GPIOE0 (128) +#define F1C100S_GPIOE1 (129) +#define F1C100S_GPIOE2 (130) +#define F1C100S_GPIOE3 (131) +#define F1C100S_GPIOE4 (132) +#define F1C100S_GPIOE5 (133) +#define F1C100S_GPIOE6 (134) +#define F1C100S_GPIOE7 (135) +#define F1C100S_GPIOE8 (136) +#define F1C100S_GPIOE9 (137) +#define F1C100S_GPIOE10 (138) +#define F1C100S_GPIOE11 (139) +#define F1C100S_GPIOE12 (140) + +#define F1C100S_GPIOF0 (160) +#define F1C100S_GPIOF1 (161) +#define F1C100S_GPIOF2 (162) +#define F1C100S_GPIOF3 (163) +#define F1C100S_GPIOF4 (164) +#define F1C100S_GPIOF5 (165) + +#ifdef __cplusplus +} +#endif + +#endif /* __F1C100S_GPIO_H__ */ diff --git a/hw/mcu/allwinner/f1c100s/include/f1c100s-irq.h b/hw/mcu/allwinner/f1c100s/include/f1c100s-irq.h new file mode 100644 index 000000000..410d1be93 --- /dev/null +++ b/hw/mcu/allwinner/f1c100s/include/f1c100s-irq.h @@ -0,0 +1,104 @@ +#ifndef __F1C100S_IRQ_H__ +#define __F1C100S_IRQ_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define F1C100S_IRQ_NMI (0) +#define F1C100S_IRQ_UART0 (1) +#define F1C100S_IRQ_UART1 (2) +#define F1C100S_IRQ_UART2 (3) +#define F1C100S_IRQ_SPDIF (5) +#define F1C100S_IRQ_CIR (6) +#define F1C100S_IRQ_I2C0 (7) +#define F1C100S_IRQ_I2C1 (8) +#define F1C100S_IRQ_I2C2 (9) +#define F1C100S_IRQ_SPI0 (10) +#define F1C100S_IRQ_SPI1 (11) +#define F1C100S_IRQ_TIMER0 (13) +#define F1C100S_IRQ_TIMER1 (14) +#define F1C100S_IRQ_TIMER2 (15) +#define F1C100S_IRQ_WDOG (16) +#define F1C100S_IRQ_RSB (17) +#define F1C100S_IRQ_DMA (18) +#define F1C100S_IRQ_TP (20) +#define F1C100S_IRQ_AUDIO (21) +#define F1C100S_IRQ_LRADC (22) +#define F1C100S_IRQ_MMC0 (23) +#define F1C100S_IRQ_MMC1 (24) +#define F1C100S_IRQ_USBOTG (26) +#define F1C100S_IRQ_TVD (27) +#define F1C100S_IRQ_TVE (28) +#define F1C100S_IRQ_LCD (29) +#define F1C100S_IRQ_DEFE (30) +#define F1C100S_IRQ_DEBE (31) +#define F1C100S_IRQ_CSI (32) +#define F1C100S_IRQ_DEITLA (33) +#define F1C100S_IRQ_VE (34) +#define F1C100S_IRQ_I2S (35) +#define F1C100S_IRQ_GPIOD (38) +#define F1C100S_IRQ_GPIOE (39) +#define F1C100S_IRQ_GPIOF (40) + +#define F1C100S_IRQ_GPIOD0 (64) +#define F1C100S_IRQ_GPIOD1 (65) +#define F1C100S_IRQ_GPIOD2 (66) +#define F1C100S_IRQ_GPIOD3 (67) +#define F1C100S_IRQ_GPIOD4 (68) +#define F1C100S_IRQ_GPIOD5 (69) +#define F1C100S_IRQ_GPIOD6 (70) +#define F1C100S_IRQ_GPIOD7 (71) +#define F1C100S_IRQ_GPIOD8 (72) +#define F1C100S_IRQ_GPIOD9 (73) +#define F1C100S_IRQ_GPIOD10 (74) +#define F1C100S_IRQ_GPIOD11 (75) +#define F1C100S_IRQ_GPIOD12 (76) +#define F1C100S_IRQ_GPIOD13 (77) +#define F1C100S_IRQ_GPIOD14 (78) +#define F1C100S_IRQ_GPIOD15 (79) +#define F1C100S_IRQ_GPIOD17 (80) +#define F1C100S_IRQ_GPIOD18 (81) +#define F1C100S_IRQ_GPIOD19 (82) +#define F1C100S_IRQ_GPIOD20 (83) +#define F1C100S_IRQ_GPIOD21 (84) + +#define F1C100S_IRQ_GPIOE0 (96) +#define F1C100S_IRQ_GPIOE1 (97) +#define F1C100S_IRQ_GPIOE2 (98) +#define F1C100S_IRQ_GPIOE3 (99) +#define F1C100S_IRQ_GPIOE4 (100) +#define F1C100S_IRQ_GPIOE5 (101) +#define F1C100S_IRQ_GPIOE6 (102) +#define F1C100S_IRQ_GPIOE7 (103) +#define F1C100S_IRQ_GPIOE8 (104) +#define F1C100S_IRQ_GPIOE9 (105) +#define F1C100S_IRQ_GPIOE10 (106) +#define F1C100S_IRQ_GPIOE11 (107) +#define F1C100S_IRQ_GPIOE12 (108) + +#define F1C100S_IRQ_GPIOF0 (128) +#define F1C100S_IRQ_GPIOF1 (129) +#define F1C100S_IRQ_GPIOF2 (130) +#define F1C100S_IRQ_GPIOF3 (131) +#define F1C100S_IRQ_GPIOF4 (132) +#define F1C100S_IRQ_GPIOF5 (133) + +typedef void (*IRQHandleTypeDef)(void); + +uint8_t f1c100s_intc_get_nirq(void); +void f1c100s_intc_dispatch(uint8_t nIRQ); +void f1c100s_intc_set_isr(uint8_t nIRQ, IRQHandleTypeDef handle); +void f1c100s_intc_enable_irq(uint8_t nIRQ); +void f1c100s_intc_disable_irq(uint8_t nIRQ); +void f1c100s_intc_unmask_irq(uint8_t nIRQ); +void f1c100s_intc_mask_irq(uint8_t nIRQ); +void f1c100s_intc_force_irq(uint8_t nIRQ); +void f1c100s_intc_clear_pend(uint8_t nIRQ); +void f1c100s_intc_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __F1C100S_IRQ_H__ */ diff --git a/hw/mcu/allwinner/f1c100s/include/f1c100s-reset.h b/hw/mcu/allwinner/f1c100s/include/f1c100s-reset.h new file mode 100644 index 000000000..e787a1ac1 --- /dev/null +++ b/hw/mcu/allwinner/f1c100s/include/f1c100s-reset.h @@ -0,0 +1,39 @@ +#ifndef __F1C100S_RESET_H__ +#define __F1C100S_RESET_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define F1C100S_RESET_DMA (6) +#define F1C100S_RESET_SD0 (8) +#define F1C100S_RESET_SD1 (9) +#define F1C100S_RESET_SDRAM (14) +#define F1C100S_RESET_SPI0 (20) +#define F1C100S_RESET_SPI1 (21) +#define F1C100S_RESET_USB_OTG (24) +#define F1C100S_RESET_VE (32) +#define F1C100S_RESET_LCD (36) +#define F1C100S_RESET_DEINTERLACE (37) +#define F1C100S_RESET_CSI (40) +#define F1C100S_RESET_TVD (41) +#define F1C100S_RESET_TVE (42) +#define F1C100S_RESET_DEBE (44) +#define F1C100S_RESET_DEFE (46) +#define F1C100S_RESET_ADDA (64) +#define F1C100S_RESET_SPDIF (65) +#define F1C100S_RESET_CIR (66) +#define F1C100S_RESET_RSB (67) +#define F1C100S_RESET_DAUDIO (76) +#define F1C100S_RESET_I2C0 (80) +#define F1C100S_RESET_I2C1 (81) +#define F1C100S_RESET_I2C2 (82) +#define F1C100S_RESET_UART0 (84) +#define F1C100S_RESET_UART1 (85) +#define F1C100S_RESET_UART2 (86) + +#ifdef __cplusplus +} +#endif + +#endif /* __F1C100S_RESET_H__ */ diff --git a/hw/mcu/allwinner/f1c100s/include/f1c100s-util.h b/hw/mcu/allwinner/f1c100s/include/f1c100s-util.h new file mode 100644 index 000000000..cb3829f82 --- /dev/null +++ b/hw/mcu/allwinner/f1c100s/include/f1c100s-util.h @@ -0,0 +1,139 @@ +// Designed by Hong Xuyao + +#ifndef __TARGET_H__ +#define __TARGET_H__ +//////////////////////////////////////////////////////////////////////////////// +#include +typedef unsigned long ubase_t; + +#define MEM_PI_SRAM __attribute__((section("SRAM"))) + +#define MEM_PI_SUMMARY __attribute__((section("SUMMARY"))) + +#define MEM_PI_NOINIT __attribute__((section("NOINIT"),zero_init)) + +#define MEM_PI_CPUONLY __attribute__((section("CPUONLY"),zero_init)) + +#define MEM_PI_HARDWARE __attribute__((section("HARDWARE"),zero_init,aligned(32))) + +#define MEM_PI_NCNB __attribute__((section("NCNB"),zero_init,aligned(32))) + +#define MEM_PI_STACK __attribute__((section("STACK"),zero_init,aligned(8))) + +#define CACHE_ALIGNED __attribute__((aligned(32))) + +#ifndef INLINE +#define INLINE __attribute__((always_inline)) +#endif + +#ifndef NOINLINE +#define NOINLINE __attribute__((noinline)) +#endif + +#ifndef NOINLINE_FUNC +#define NOINLINE_FUNC __attribute__((noinline)) +#endif + +#ifndef ALIGN +#define ALIGN(n) __attribute__((aligned(n))) +#endif + +#define CPU_SR_DECL ubase_t cpu_sr + +#ifdef __thumb__ +#define __SWITCH_TO_ARM__ +#pragma arm +#endif + +#if 0 +#define CPU_ENTER_CRITICAL() do{cpu_sr = util_enter_critical();}while(0) +#else +#define CPU_ENTER_CRITICAL() do{cpu_sr = __fast_enter_critical();}while(0) +static inline ubase_t __fast_enter_critical(void) +{ + ubase_t cpu_sr, tmp_sr; + __asm volatile { + MRS cpu_sr, CPSR + ORR tmp_sr, cpu_sr, #0xC0 + MSR CPSR_c, tmp_sr + } + return cpu_sr; +} +#endif + +#if 0 +#define CPU_EXIT_CRITICAL() do{util_exit_critical(cpu_sr);}while(0) +#else +#define CPU_EXIT_CRITICAL() do{__fast_exit_critical(cpu_sr);}while(0) +static inline void __fast_exit_critical(ubase_t cpu_sr) +{ + __asm volatile { + MSR CPSR_c, cpu_sr + } +} +#endif + +static inline unsigned CPU_CLZ16(uint16_t val) +{ + __asm volatile { + CLZ val, val + } + return (val - 16); +} + +static inline uint8_t __swap_byte(uint8_t newval, uint8_t volatile* pmem) +{ + uint8_t oldval; + __asm volatile { + SWPB oldval, newval, [pmem] + }; + return oldval; +} + +static inline uint32_t UTL_REV32(uint32_t val) +{ + uint32_t tmpval; + __asm volatile { + EOR tmpval, val, val, ROR #16 + MOV tmpval, tmpval, LSR #8 + BIC tmpval, tmpval, #0xFF00 + EOR val, tmpval, val, ROR #8 + } + return val; +} + +static inline uint16_t UTL_REV16(uint16_t val) +{ + uint32_t tmpval; + __asm volatile { + LSR tmpval, val, #8 + ORR val, tmpval, val, LSL #8 + BIC val, val, #0xFF0000 + } + return val; +} + +#ifdef __SWITCH_TO_ARM__ +#undef __SWITCH_TO_ARM__ +#pragma thumb +#endif + +#ifndef COUNTOF +#define COUNTOF(ar) (sizeof(ar)/sizeof(ar[0])) +#endif +/* +void util_halt(void); +void util_fastloop(ubase_t n); +ubase_t util_getCPSR(void); +ubase_t util_enter_critical(void); +void util_exit_critical(ubase_t sr); +void util_enable_interrupt(void); +void util_disable_interrupt(void); + +void target_wdt_setup(void); +void target_wdt_feed(void); +void target_reset(void); +*/ +//////////////////////////////////////////////////////////////////////////////// +#endif /* __TARGET_H__ */ + diff --git a/hw/mcu/allwinner/f1c100s/include/f1c100s/reg-ccu.h b/hw/mcu/allwinner/f1c100s/include/f1c100s/reg-ccu.h new file mode 100644 index 000000000..1770ad7ff --- /dev/null +++ b/hw/mcu/allwinner/f1c100s/include/f1c100s/reg-ccu.h @@ -0,0 +1,55 @@ +#ifndef __F1C100S_REG_CCU_H__ +#define __F1C100S_REG_CCU_H__ + +#define F1C100S_CCU_BASE (0x01c20000) + +#define CCU_PLL_CPU_CTRL (0x000) +#define CCU_PLL_AUDIO_CTRL (0x008) +#define CCU_PLL_VIDEO_CTRL (0x010) +#define CCU_PLL_VE_CTRL (0x018) +#define CCU_PLL_DDR_CTRL (0x020) +#define CCU_PLL_PERIPH_CTRL (0x028) +#define CCU_CPU_CFG (0x050) +#define CCU_AHB_APB_CFG (0x054) + +#define CCU_BUS_CLK_GATE0 (0x060) +#define CCU_BUS_CLK_GATE1 (0x064) +#define CCU_BUS_CLK_GATE2 (0x068) + +#define CCU_SDMMC0_CLK (0x088) +#define CCU_SDMMC1_CLK (0x08c) +#define CCU_DAUDIO_CLK (0x0b0) +#define CCU_SPDIF_CLK (0x0b4) +#define CCU_I2S_CLK (0x0b8) +#define CCU_USBPHY_CFG (0x0cc) +#define CCU_DRAM_CLK_GATE (0x100) +#define CCU_DEBE_CLK (0x104) +#define CCU_DEFE_CLK (0x10c) +#define CCU_LCD_CLK (0x118) +#define CCU_DEINTERLACE_CLK (0x11c) +#define CCU_TVE_CLK (0x120) +#define CCU_TVD_CLK (0x124) +#define CCU_CSI_CLK (0x134) +#define CCU_VE_CLK (0x13c) +#define CCU_ADDA_CLK (0x140) +#define CCU_AVS_CLK (0x144) + +#define CCU_PLL_STABLE_TIME0 (0x200) +#define CCU_PLL_STABLE_TIME1 (0x204) +#define CCU_PLL_CPU_BIAS (0x220) +#define CCU_PLL_AUDIO_BIAS (0x224) +#define CCU_PLL_VIDEO_BIAS (0x228) +#define CCU_PLL_VE_BIAS (0x22c) +#define CCU_PLL_DDR0_BIAS (0x230) +#define CCU_PLL_PERIPH_BIAS (0x234) +#define CCU_PLL_CPU_TUN (0x250) +#define CCU_PLL_DDR_TUN (0x260) +#define CCU_PLL_AUDIO_PAT (0x284) +#define CCU_PLL_VIDEO_PAT (0x288) +#define CCU_PLL_DDR0_PAT (0x290) + +#define CCU_BUS_SOFT_RST0 (0x2c0) +#define CCU_BUS_SOFT_RST1 (0x2c4) +#define CCU_BUS_SOFT_RST3 (0x2d0) + +#endif /* __F1C100S_REG_CCU_H__ */ diff --git a/hw/mcu/allwinner/f1c100s/include/f1c100s/reg-dram.h b/hw/mcu/allwinner/f1c100s/include/f1c100s/reg-dram.h new file mode 100644 index 000000000..8a0ac3e0e --- /dev/null +++ b/hw/mcu/allwinner/f1c100s/include/f1c100s/reg-dram.h @@ -0,0 +1,39 @@ +#ifndef __F1C100S_REG_DRAM_H__ +#define __F1C100S_REG_DRAM_H__ + +#define F1C100S_DRAM_BASE (0x01c01000) + +#define DRAM_SCONR (0x00) +#define DRAM_STMG0R (0x04) +#define DRAM_STMG1R (0x08) +#define DRAM_SCTLR (0x0c) +#define DRAM_SREFR (0x10) +#define DRAM_SEXTMR (0x14) +#define DRAM_DDLYR (0x24) +#define DRAM_DADRR (0x28) +#define DRAM_DVALR (0x2c) +#define DRAM_DRPTR0 (0x30) +#define DRAM_DRPTR1 (0x34) +#define DRAM_DRPTR2 (0x38) +#define DRAM_DRPTR3 (0x3c) +#define DRAM_SEFR (0x40) +#define DRAM_MAE (0x44) +#define DRAM_ASPR (0x48) +#define DRAM_SDLY0 (0x4C) +#define DRAM_SDLY1 (0x50) +#define DRAM_SDLY2 (0x54) +#define DRAM_MCR0 (0x100) +#define DRAM_MCR1 (0x104) +#define DRAM_MCR2 (0x108) +#define DRAM_MCR3 (0x10c) +#define DRAM_MCR4 (0x110) +#define DRAM_MCR5 (0x114) +#define DRAM_MCR6 (0x118) +#define DRAM_MCR7 (0x11c) +#define DRAM_MCR8 (0x120) +#define DRAM_MCR9 (0x124) +#define DRAM_MCR10 (0x128) +#define DRAM_MCR11 (0x12c) +#define DRAM_BWCR (0x140) + +#endif /* __F1C100S_REG_DRAM_H__ */ diff --git a/hw/mcu/allwinner/f1c100s/include/io.h b/hw/mcu/allwinner/f1c100s/include/io.h new file mode 100644 index 000000000..f0dad1785 --- /dev/null +++ b/hw/mcu/allwinner/f1c100s/include/io.h @@ -0,0 +1,57 @@ +#ifndef __IO_H__ +#define __IO_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +static inline u8_t read8(virtual_addr_t addr) +{ + return( *((volatile u8_t *)(addr)) ); +} + +static inline u16_t read16(virtual_addr_t addr) +{ + return( *((volatile u16_t *)(addr)) ); +} + +static inline u32_t read32(virtual_addr_t addr) +{ + return( *((volatile u32_t *)(addr)) ); +} + +static inline u64_t read64(virtual_addr_t addr) +{ + return( *((volatile u64_t *)(addr)) ); +} + +static inline void write8(virtual_addr_t addr, u8_t value) +{ + *((volatile u8_t *)(addr)) = value; +} + +static inline void write16(virtual_addr_t addr, u16_t value) +{ + *((volatile u16_t *)(addr)) = value; +} + +static inline void write32(virtual_addr_t addr, u32_t value) +{ + *((volatile u32_t *)(addr)) = value; +} + +static inline void write64(virtual_addr_t addr, u64_t value) +{ + *((volatile u64_t *)(addr)) = value; +} + +virtual_addr_t phys_to_virt(physical_addr_t phys); +physical_addr_t virt_to_phys(virtual_addr_t virt); + +#ifdef __cplusplus +} +#endif + +#endif /* __IO_H__ */ diff --git a/hw/mcu/allwinner/f1c100s/include/irqflags.h b/hw/mcu/allwinner/f1c100s/include/irqflags.h new file mode 100644 index 000000000..e4ef97cd2 --- /dev/null +++ b/hw/mcu/allwinner/f1c100s/include/irqflags.h @@ -0,0 +1,104 @@ +#ifndef __ARM32_IRQFLAGS_H__ +#define __ARM32_IRQFLAGS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#if __ARM32_ARCH__ == 5 + +static inline void arch_local_irq_enable(void) +{ + irq_flags_t temp; + + __asm__ __volatile__( + "mrs %0, cpsr\n" + "bic %0, %0, #(1<<7)\n" + "msr cpsr_c, %0" + : "=r" (temp) + : + : "memory", "cc"); +} + +static inline void arch_local_irq_disable(void) +{ + irq_flags_t temp; + + __asm__ __volatile__( + "mrs %0, cpsr\n" + "orr %0, %0, #(1<<7)\n" + "msr cpsr_c, %0" + : "=r" (temp) + : + : "memory", "cc"); +} + +static inline irq_flags_t arch_local_irq_save(void) +{ + irq_flags_t flags, temp; + + __asm__ __volatile__( + "mrs %0, cpsr\n" + "orr %1, %0, #(1<<7)\n" + "msr cpsr_c, %1" + : "=r" (flags), "=r" (temp) + : + : "memory", "cc"); + + return flags; +} + +static inline void arch_local_irq_restore(irq_flags_t flags) +{ + __asm__ __volatile__( + "msr cpsr_c, %0" + : + : "r" (flags) + : "memory", "cc"); +} +#else +static inline void arch_local_irq_enable(void) +{ + __asm__ __volatile__("cpsie i" ::: "memory", "cc"); +} + +static inline void arch_local_irq_disable(void) +{ + __asm__ __volatile__("cpsid i" ::: "memory", "cc"); +} + +static inline irq_flags_t arch_local_irq_save(void) +{ + irq_flags_t flags; + + __asm__ __volatile__( + "mrs %0, cpsr\n" + "cpsid i" + : "=r" (flags) + : + : "memory", "cc"); + return flags; +} + +static inline void arch_local_irq_restore(irq_flags_t flags) +{ + __asm__ __volatile__( + "msr cpsr_c, %0" + : + : "r" (flags) + : "memory", "cc"); +} +#endif + +#define local_irq_enable() do { arch_local_irq_enable(); } while(0) +#define local_irq_disable() do { arch_local_irq_disable(); } while(0) +#define local_irq_save(flags) do { flags = arch_local_irq_save(); } while(0) +#define local_irq_restore(flags) do { arch_local_irq_restore(flags); } while(0) + +#ifdef __cplusplus +} +#endif + +#endif /* __ARM32_IRQFLAGS_H__ */ diff --git a/hw/mcu/allwinner/f1c100s/include/malloc.h b/hw/mcu/allwinner/f1c100s/include/malloc.h new file mode 100644 index 000000000..6669fe48c --- /dev/null +++ b/hw/mcu/allwinner/f1c100s/include/malloc.h @@ -0,0 +1,35 @@ +#ifndef __MALLOC_H__ +#define __MALLOC_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include + +void * mm_create(void * mem, size_t bytes); +void mm_destroy(void * mm); +void * mm_get_pool(void * mm); +void * mm_add_pool(void * mm, void * mem, size_t bytes); +void mm_remove_pool(void * mm, void * pool); +void * mm_malloc(void * mm, size_t size); +void * mm_memalign(void * mm, size_t align, size_t size); +void * mm_realloc(void * mm, void * ptr, size_t size); +void mm_free(void * mm, void * ptr); + +void * malloc(size_t size); +void * memalign(size_t align, size_t size); +void * realloc(void * ptr, size_t size); +void * calloc(size_t nmemb, size_t size); +void free(void * ptr); + +void do_init_mem_pool(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __MALLOC_H__ */ diff --git a/hw/mcu/allwinner/f1c100s/include/printf.h b/hw/mcu/allwinner/f1c100s/include/printf.h new file mode 100644 index 000000000..632bfc20e --- /dev/null +++ b/hw/mcu/allwinner/f1c100s/include/printf.h @@ -0,0 +1,99 @@ +/////////////////////////////////////////////////////////////////////////////// +// \author (c) Marco Paland (info@paland.com) +// 2014-2018, PALANDesign Hannover, Germany +// +// \license The MIT License (MIT) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// \brief Tiny printf, sprintf and snprintf implementation, optimized for speed on +// embedded systems with a very limited resources. +// Use this instead of bloated standard/newlib printf. +// These routines are thread safe and reentrant! +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _PRINTF_H_ +#define _PRINTF_H_ + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * Output a character to a custom device like UART, used by the printf() function + * This function is declared here only. You have to write your custom implementation somewhere + * \param character Character to output + */ +void _putchar(char character); + + +/** + * Tiny printf implementation + * You have to implement _putchar if you use printf() + * \param format A string that specifies the format of the output + * \return The number of characters that are written into the array, not counting the terminating null character + */ +int printf(const char* format, ...); + + +/** + * Tiny sprintf implementation + * Due to security reasons (buffer overflow) YOU SHOULD CONSIDER USING (V)SNPRINTF INSTEAD! + * \param buffer A pointer to the buffer where to store the formatted string. MUST be big enough to store the output! + * \param format A string that specifies the format of the output + * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character + */ +int sprintf(char* buffer, const char* format, ...); + + +/** + * Tiny snprintf/vsnprintf implementation + * \param buffer A pointer to the buffer where to store the formatted string + * \param count The maximum number of characters to store in the buffer, including a terminating null character + * \param format A string that specifies the format of the output + * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character + * If the formatted string is truncated the buffer size (count) is returned + */ +int snprintf(char* buffer, size_t count, const char* format, ...); +int vsnprintf(char* buffer, size_t count, const char* format, va_list va); + + +/** + * printf with output function + * You may use this as dynamic alternative to printf() with its fixed _putchar() output + * \param out An output function which takes one character and an argument pointer + * \param arg An argument pointer for user data passed to output function + * \param format A string that specifies the format of the output + * \return The number of characters that are sent to the output function, not counting the terminating null character + */ +int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...); + + +#ifdef __cplusplus +} +#endif + + +#endif // _PRINTF_H_ diff --git a/hw/mcu/allwinner/f1c100s/include/sizes.h b/hw/mcu/allwinner/f1c100s/include/sizes.h new file mode 100644 index 000000000..3edeed503 --- /dev/null +++ b/hw/mcu/allwinner/f1c100s/include/sizes.h @@ -0,0 +1,42 @@ +#ifndef __SIZES_H__ +#define __SIZES_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define SZ_16 (0x00000010) +#define SZ_256 (0x00000100) +#define SZ_512 (0x00000200) + +#define SZ_1K (0x00000400) +#define SZ_4K (0x00001000) +#define SZ_8K (0x00002000) +#define SZ_16K (0x00004000) +#define SZ_32K (0x00008000) +#define SZ_64K (0x00010000) +#define SZ_128K (0x00020000) +#define SZ_256K (0x00040000) +#define SZ_512K (0x00080000) + +#define SZ_1M (0x00100000) +#define SZ_2M (0x00200000) +#define SZ_4M (0x00400000) +#define SZ_8M (0x00800000) +#define SZ_16M (0x01000000) +#define SZ_32M (0x02000000) +#define SZ_64M (0x04000000) +#define SZ_128M (0x08000000) +#define SZ_256M (0x10000000) +#define SZ_512M (0x20000000) + +#define SZ_1G (0x40000000) +#define SZ_2G (0x80000000) + +#define ARRAY_SIZE(array) ( sizeof(array) / sizeof((array)[0]) ) + +#ifdef __cplusplus +} +#endif + +#endif /* __SIZES_H__ */ diff --git a/hw/mcu/allwinner/f1c100s/include/types.h b/hw/mcu/allwinner/f1c100s/include/types.h new file mode 100644 index 000000000..61b87b6d7 --- /dev/null +++ b/hw/mcu/allwinner/f1c100s/include/types.h @@ -0,0 +1,55 @@ +#ifndef __ARM32_TYPES_H__ +#define __ARM32_TYPES_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef signed char s8_t; +typedef unsigned char u8_t; + +typedef signed short s16_t; +typedef unsigned short u16_t; + +typedef signed int s32_t; +typedef unsigned int u32_t; + +typedef signed long long s64_t; +typedef unsigned long long u64_t; + +typedef signed long long intmax_t; +typedef unsigned long long uintmax_t; + +typedef signed int ptrdiff_t; +typedef signed int intptr_t; +typedef unsigned int uintptr_t; + +typedef unsigned int size_t; +typedef signed int ssize_t; + +// typedef signed int off_t; +typedef signed long long loff_t; + +typedef signed int bool_t; + +typedef signed int register_t; +typedef unsigned int irq_flags_t; + +typedef unsigned int virtual_addr_t; +typedef unsigned int virtual_size_t; +typedef unsigned int physical_addr_t; +typedef unsigned int physical_size_t; + +typedef struct { + volatile long counter; +} atomic_t; + +typedef struct { + volatile long lock; +} spinlock_t; + +#ifdef __cplusplus +} +#endif + +#endif /* __ARM32_TYPES_H__ */ diff --git a/hw/mcu/allwinner/f1c100s/lib/malloc.c b/hw/mcu/allwinner/f1c100s/lib/malloc.c new file mode 100644 index 000000000..763746a47 --- /dev/null +++ b/hw/mcu/allwinner/f1c100s/lib/malloc.c @@ -0,0 +1,834 @@ +/* + * lib/libc/malloc/malloc.c + */ + +#include + +static void * __heap_pool = NULL; + +/* + * Some macros. + */ +#define tlsf_cast(t, exp) ((t)(exp)) +#define tlsf_min(a, b) ((a) < (b) ? (a) : (b)) +#define tlsf_max(a, b) ((a) > (b) ? (a) : (b)) + +#define tlsf_assert assert +#define tlsf_insist(x) { tlsf_assert(x); if (!(x)) { status--; } } + +#if defined(__ARM64__) || defined(__X64__) +# define TLSF_64BIT +#else +# undef TLSF_64BIT +#endif + +/* + * Public constants + */ +enum tlsf_public +{ + /* + * log2 of number of linear subdivisions of block sizes + */ + SL_INDEX_COUNT_LOG2 = 5, +}; + +/* + * Private constants + */ +enum tlsf_private +{ +#if defined(TLSF_64BIT) + /* + * All allocation sizes and addresses are aligned to 8 bytes + */ + ALIGN_SIZE_LOG2 = 3, +#else + /* + * All allocation sizes and addresses are aligned to 4 bytes + */ + ALIGN_SIZE_LOG2 = 2, +#endif + ALIGN_SIZE = (1 << ALIGN_SIZE_LOG2), + +#if defined(TLSF_64BIT) + FL_INDEX_MAX = 32, +#else + FL_INDEX_MAX = 30, +#endif + SL_INDEX_COUNT = (1 << SL_INDEX_COUNT_LOG2), + FL_INDEX_SHIFT = (SL_INDEX_COUNT_LOG2 + ALIGN_SIZE_LOG2), + FL_INDEX_COUNT = (FL_INDEX_MAX - FL_INDEX_SHIFT + 1), + + SMALL_BLOCK_SIZE = (1 << FL_INDEX_SHIFT), +}; + +/* + * Block header structure + */ +typedef struct block_header_t +{ + /* + * Points to the previous physical block + */ + struct block_header_t * prev_phys_block; + + /* + * The size of this block, excluding the block header + */ + size_t size; + + /* + * Next and previous free blocks + */ + struct block_header_t * next_free; + struct block_header_t * prev_free; +} block_header_t; + +/* + * The TLSF control structure. + */ +typedef struct control_t +{ + /* + * Empty lists point at this block to indicate they are free. + */ + block_header_t block_null; + + /* + * Bitmaps for free lists. + */ + unsigned int fl_bitmap; + unsigned int sl_bitmap[FL_INDEX_COUNT]; + + /* + * Head of free lists. + */ + block_header_t * blocks[FL_INDEX_COUNT][SL_INDEX_COUNT]; +} control_t; + +/* + * A type used for casting when doing pointer arithmetic. + */ +typedef ptrdiff_t tlsfptr_t; + +/* + * Associated constants + */ +static const size_t block_header_free_bit = 1 << 0; +static const size_t block_header_prev_free_bit = 1 << 1; +static const size_t block_header_overhead = sizeof(size_t); +static const size_t block_start_offset = offsetof(block_header_t, size) + sizeof(size_t); +static const size_t block_size_min = sizeof(block_header_t) - sizeof(block_header_t *); +static const size_t block_size_max = tlsf_cast(size_t, 1) << FL_INDEX_MAX; + +#if defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) && defined(__GNUC_PATCHLEVEL__) +static int tlsf_ffs(unsigned int word) +{ + return __builtin_ffs(word) - 1; +} + +static int tlsf_fls(unsigned int word) +{ + const int bit = word ? 32 - __builtin_clz(word) : 0; + return bit - 1; +} +#else +static int tlsf_fls_generic(unsigned int word) +{ + int bit = 32; + + if (!word) bit -= 1; + if (!(word & 0xffff0000)) { word <<= 16; bit -= 16; } + if (!(word & 0xff000000)) { word <<= 8; bit -= 8; } + if (!(word & 0xf0000000)) { word <<= 4; bit -= 4; } + if (!(word & 0xc0000000)) { word <<= 2; bit -= 2; } + if (!(word & 0x80000000)) { word <<= 1; bit -= 1; } + + return bit; +} + +static int tlsf_ffs(unsigned int word) +{ + return tlsf_fls_generic(word & (~word + 1)) - 1; +} + +static int tlsf_fls(unsigned int word) +{ + return tlsf_fls_generic(word) - 1; +} +#endif + +#if defined(TLSF_64BIT) +static int tlsf_fls_sizet(size_t size) +{ + int high = (int)(size >> 32); + int bits = 0; + if(high) + { + bits = 32 + tlsf_fls(high); + } + else + { + bits = tlsf_fls((int)size & 0xffffffff); + + } + return bits; +} +#else +#define tlsf_fls_sizet tlsf_fls +#endif + +static size_t block_get_size(const block_header_t * block) +{ + return block->size & ~(block_header_free_bit | block_header_prev_free_bit); +} + +static void block_set_size(block_header_t * block, size_t size) +{ + const size_t oldsize = block->size; + block->size = size | (oldsize & (block_header_free_bit | block_header_prev_free_bit)); +} + +static int block_is_last(const block_header_t * block) +{ + return (0 == block_get_size(block)); +} + +static int block_is_free(const block_header_t * block) +{ + return tlsf_cast(int, block->size & block_header_free_bit); +} + +static void block_set_free(block_header_t * block) +{ + block->size |= block_header_free_bit; +} + +static void block_set_used(block_header_t * block) +{ + block->size &= ~block_header_free_bit; +} + +static int block_is_prev_free(const block_header_t * block) +{ + return tlsf_cast(int, block->size & block_header_prev_free_bit); +} + +static void block_set_prev_free(block_header_t * block) +{ + block->size |= block_header_prev_free_bit; +} + +static void block_set_prev_used(block_header_t * block) +{ + block->size &= ~block_header_prev_free_bit; +} + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-align" +static block_header_t * block_from_ptr(void * ptr) +{ + return tlsf_cast(block_header_t *, tlsf_cast(unsigned char*, ptr) - block_start_offset); +} +#pragma GCC diagnostic pop + +static void * block_to_ptr(block_header_t * block) +{ + return tlsf_cast(void *, tlsf_cast(unsigned char*, block) + block_start_offset); +} + +static block_header_t * offset_to_block(void * ptr, size_t size) +{ + return tlsf_cast(block_header_t *, tlsf_cast(tlsfptr_t, ptr) + size); +} + +static block_header_t * block_prev(block_header_t * block) +{ + return block->prev_phys_block; +} + +static block_header_t * block_next(block_header_t * block) +{ + block_header_t * next = offset_to_block(block_to_ptr(block), block_get_size(block) - block_header_overhead); + tlsf_assert(!block_is_last(block)); + return next; +} + +static block_header_t * block_link_next(block_header_t * block) +{ + block_header_t * next = block_next(block); + next->prev_phys_block = block; + return next; +} + +static void block_mark_as_free(block_header_t * block) +{ + block_header_t * next = block_link_next(block); + block_set_prev_free(next); + block_set_free(block); +} + +static void block_mark_as_used(block_header_t * block) +{ + block_header_t * next = block_next(block); + block_set_prev_used(next); + block_set_used(block); +} + +static size_t align_up(size_t x, size_t align) +{ + tlsf_assert(0 == (align & (align - 1)) && "must align to a power of two"); + return (x + (align - 1)) & ~(align - 1); +} + +static size_t align_down(size_t x, size_t align) +{ + tlsf_assert(0 == (align & (align - 1)) && "must align to a power of two"); + return x - (x & (align - 1)); +} + +static void * align_ptr(const void * ptr, size_t align) +{ + const tlsfptr_t aligned = (tlsf_cast(tlsfptr_t, ptr) + (align - 1)) & ~(align - 1); + tlsf_assert(0 == (align & (align - 1)) && "must align to a power of two"); + return tlsf_cast(void*, aligned); +} + +static size_t adjust_request_size(size_t size, size_t align) +{ + size_t adjust = 0; + if (size && size < block_size_max) + { + const size_t aligned = align_up(size, align); + adjust = tlsf_max(aligned, block_size_min); + } + return adjust; +} + +static void mapping_insert(size_t size, int * fli, int * sli) +{ + int fl, sl; + if (size < SMALL_BLOCK_SIZE) + { + fl = 0; + sl = tlsf_cast(int, size) / (SMALL_BLOCK_SIZE / SL_INDEX_COUNT); + } + else + { + fl = tlsf_fls_sizet(size); + sl = tlsf_cast(int, size >> (fl - SL_INDEX_COUNT_LOG2)) ^ (1 << SL_INDEX_COUNT_LOG2); + fl -= (FL_INDEX_SHIFT - 1); + } + *fli = fl; + *sli = sl; +} + +static void mapping_search(size_t size, int * fli, int * sli) +{ + if (size >= (1 << SL_INDEX_COUNT_LOG2)) + { + const size_t round = (1 << (tlsf_fls_sizet(size) - SL_INDEX_COUNT_LOG2)) - 1; + size += round; + } + mapping_insert(size, fli, sli); +} + +static block_header_t * search_suitable_block(control_t * control, int * fli, int * sli) +{ + int fl = *fli; + int sl = *sli; + + unsigned int sl_map = control->sl_bitmap[fl] & (~0U << sl); + if (!sl_map) + { + const unsigned int fl_map = control->fl_bitmap & (~0U << (fl + 1)); + if (!fl_map) + { + return 0; + } + + fl = tlsf_ffs(fl_map); + *fli = fl; + sl_map = control->sl_bitmap[fl]; + } + tlsf_assert(sl_map && "internal error - second level bitmap is null"); + sl = tlsf_ffs(sl_map); + *sli = sl; + + return control->blocks[fl][sl]; +} + +static void remove_free_block(control_t * control, block_header_t * block, int fl, int sl) +{ + block_header_t * prev = block->prev_free; + block_header_t * next = block->next_free; + tlsf_assert(prev && "prev_free field can not be null"); + tlsf_assert(next && "next_free field can not be null"); + next->prev_free = prev; + prev->next_free = next; + + if (control->blocks[fl][sl] == block) + { + control->blocks[fl][sl] = next; + + if (next == &control->block_null) + { + control->sl_bitmap[fl] &= ~(1 << sl); + + if (!control->sl_bitmap[fl]) + { + control->fl_bitmap &= ~(1 << fl); + } + } + } +} + +static void insert_free_block(control_t * control, block_header_t * block, int fl, int sl) +{ + block_header_t * current = control->blocks[fl][sl]; + tlsf_assert(current && "free list cannot have a null entry"); + tlsf_assert(block && "cannot insert a null entry into the free list"); + block->next_free = current; + block->prev_free = &control->block_null; + current->prev_free = block; + + tlsf_assert(block_to_ptr(block) == align_ptr(block_to_ptr(block), ALIGN_SIZE) && "block not aligned properly"); + + control->blocks[fl][sl] = block; + control->fl_bitmap |= (1 << fl); + control->sl_bitmap[fl] |= (1 << sl); +} + +static void block_remove(control_t * control, block_header_t * block) +{ + int fl, sl; + mapping_insert(block_get_size(block), &fl, &sl); + remove_free_block(control, block, fl, sl); +} + +static void block_insert(control_t * control, block_header_t * block) +{ + int fl, sl; + mapping_insert(block_get_size(block), &fl, &sl); + insert_free_block(control, block, fl, sl); +} + +static int block_can_split(block_header_t * block, size_t size) +{ + return block_get_size(block) >= sizeof(block_header_t) + size; +} + +static block_header_t * block_split(block_header_t * block, size_t size) +{ + block_header_t* remaining = offset_to_block(block_to_ptr(block), size - block_header_overhead); + const size_t remain_size = block_get_size(block) - (size + block_header_overhead); + + tlsf_assert(block_to_ptr(remaining) == align_ptr(block_to_ptr(remaining), ALIGN_SIZE) && "remaining block not aligned properly"); + + tlsf_assert(block_get_size(block) == remain_size + size + block_header_overhead); + block_set_size(remaining, remain_size); + tlsf_assert(block_get_size(remaining) >= block_size_min && "block split with invalid size"); + + block_set_size(block, size); + block_mark_as_free(remaining); + + return remaining; +} + +static block_header_t * block_absorb(block_header_t * prev, block_header_t * block) +{ + tlsf_assert(!block_is_last(prev) && "previous block can't be last!"); + prev->size += block_get_size(block) + block_header_overhead; + block_link_next(prev); + return prev; +} + +static block_header_t * block_merge_prev(control_t * control, block_header_t * block) +{ + if (block_is_prev_free(block)) + { + block_header_t* prev = block_prev(block); + tlsf_assert(prev && "prev physical block can't be null"); + tlsf_assert(block_is_free(prev) && "prev block is not free though marked as such"); + block_remove(control, prev); + block = block_absorb(prev, block); + } + + return block; +} + +static block_header_t * block_merge_next(control_t * control, block_header_t * block) +{ + block_header_t* next = block_next(block); + tlsf_assert(next && "next physical block can't be null"); + + if (block_is_free(next)) + { + tlsf_assert(!block_is_last(block) && "previous block can't be last!"); + block_remove(control, next); + block = block_absorb(block, next); + } + + return block; +} + +static void block_trim_free(control_t * control, block_header_t * block, size_t size) +{ + tlsf_assert(block_is_free(block) && "block must be free"); + if (block_can_split(block, size)) + { + block_header_t* remaining_block = block_split(block, size); + block_link_next(block); + block_set_prev_free(remaining_block); + block_insert(control, remaining_block); + } +} + +static void block_trim_used(control_t * control, block_header_t * block, size_t size) +{ + tlsf_assert(!block_is_free(block) && "block must be used"); + if (block_can_split(block, size)) + { + block_header_t* remaining_block = block_split(block, size); + block_set_prev_used(remaining_block); + + remaining_block = block_merge_next(control, remaining_block); + block_insert(control, remaining_block); + } +} + +static block_header_t * block_trim_free_leading(control_t * control, block_header_t * block, size_t size) +{ + block_header_t * remaining_block = block; + if (block_can_split(block, size)) + { + remaining_block = block_split(block, size - block_header_overhead); + block_set_prev_free(remaining_block); + + block_link_next(block); + block_insert(control, block); + } + + return remaining_block; +} + +static block_header_t * block_locate_free(control_t * control, size_t size) +{ + int fl = 0, sl = 0; + block_header_t * block = 0; + + if (size) + { + mapping_search(size, &fl, &sl); + block = search_suitable_block(control, &fl, &sl); + } + + if (block) + { + tlsf_assert(block_get_size(block) >= size); + remove_free_block(control, block, fl, sl); + } + + return block; +} + +static void * block_prepare_used(control_t * control, block_header_t * block, size_t size) +{ + void* p = 0; + if (block) + { + block_trim_free(control, block, size); + block_mark_as_used(block); + p = block_to_ptr(block); + } + return p; +} + +static void control_construct(control_t * control) +{ + int i, j; + + control->block_null.next_free = &control->block_null; + control->block_null.prev_free = &control->block_null; + + control->fl_bitmap = 0; + for (i = 0; i < FL_INDEX_COUNT; ++i) + { + control->sl_bitmap[i] = 0; + for (j = 0; j < SL_INDEX_COUNT; ++j) + { + control->blocks[i][j] = &control->block_null; + } + } +} + +static inline void * tlsf_add_pool(void * tlsf, void * mem, size_t bytes) +{ + block_header_t * block; + block_header_t * next; + const size_t pool_overhead = 2 * block_header_overhead; + const size_t pool_bytes = align_down(bytes - pool_overhead, ALIGN_SIZE); + + if (((ptrdiff_t)mem % ALIGN_SIZE) != 0) + return 0; + + if (pool_bytes < block_size_min || pool_bytes > block_size_max) + return 0; + + block = offset_to_block(mem, -(tlsfptr_t)block_header_overhead); + block_set_size(block, pool_bytes); + block_set_free(block); + block_set_prev_used(block); + block_insert(tlsf_cast(control_t*, tlsf), block); + + next = block_link_next(block); + block_set_size(next, 0); + block_set_used(next); + block_set_prev_free(next); + + return mem; +} + +static inline void tlsf_remove_pool(void * tlsf, void * pool) +{ + control_t * control = tlsf_cast(control_t *, tlsf); + block_header_t * block = offset_to_block(pool, -(int)block_header_overhead); + int fl = 0, sl = 0; + + tlsf_assert(block_is_free(block) && "block should be free"); + tlsf_assert(!block_is_free(block_next(block)) && "next block should not be free"); + tlsf_assert(block_get_size(block_next(block)) == 0 && "next block size should be zero"); + + mapping_insert(block_get_size(block), &fl, &sl); + remove_free_block(control, block, fl, sl); +} + +static inline void * tlsf_create(void * mem) +{ + if (((tlsfptr_t)mem % ALIGN_SIZE) != 0) + return 0; + + control_construct(tlsf_cast(control_t *, mem)); + return tlsf_cast(void *, mem); +} + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Warray-bounds" +static inline void * tlsf_create_with_pool(void * mem, size_t bytes) +{ + void * tlsf = tlsf_create(mem); + tlsf_add_pool(tlsf, (char *)mem + sizeof(control_t), bytes - sizeof(control_t)); + return tlsf; +} +#pragma GCC diagnostic pop + + +static inline void tlsf_destroy(void * tlsf) +{ + (void)tlsf; +} + +static inline void * tlsf_get_pool(void * tlsf) +{ + return tlsf_cast(void *, (char *)tlsf + sizeof(control_t)); +} + +static inline void * tlsf_malloc(void * tlsf, size_t size) +{ + control_t * control = tlsf_cast(control_t *, tlsf); + const size_t adjust = adjust_request_size(size, ALIGN_SIZE); + block_header_t * block = block_locate_free(control, adjust); + return block_prepare_used(control, block, adjust); +} + +static inline void * tlsf_memalign(void * tlsf, size_t align, size_t size) +{ + control_t * control = tlsf_cast(control_t *, tlsf); + const size_t adjust = adjust_request_size(size, ALIGN_SIZE); + + const size_t gap_minimum = sizeof(block_header_t); + const size_t size_with_gap = adjust_request_size(adjust + align + gap_minimum, align); + + const size_t aligned_size = (align <= ALIGN_SIZE) ? adjust : size_with_gap; + + block_header_t* block = block_locate_free(control, aligned_size); + + tlsf_assert(sizeof(block_header_t) == block_size_min + block_header_overhead); + + if (block) + { + void * ptr = block_to_ptr(block); + void * aligned = align_ptr(ptr, align); + size_t gap = tlsf_cast(size_t, tlsf_cast(tlsfptr_t, aligned) - tlsf_cast(tlsfptr_t, ptr)); + + if (gap && gap < gap_minimum) + { + const size_t gap_remain = gap_minimum - gap; + const size_t offset = tlsf_max(gap_remain, align); + const void * next_aligned = tlsf_cast(void *, tlsf_cast(tlsfptr_t, aligned) + offset); + + aligned = align_ptr(next_aligned, align); + gap = tlsf_cast(size_t, tlsf_cast(tlsfptr_t, aligned) - tlsf_cast(tlsfptr_t, ptr)); + } + + if (gap) + { + tlsf_assert(gap >= gap_minimum && "gap size too small"); + block = block_trim_free_leading(control, block, gap); + } + } + + return block_prepare_used(control, block, adjust); +} + +static inline void tlsf_free(void * tlsf, void * ptr) +{ + if (ptr) + { + control_t * control = tlsf_cast(control_t *, tlsf); + block_header_t * block = block_from_ptr(ptr); + tlsf_assert(!block_is_free(block) && "block already marked as free"); + block_mark_as_free(block); + block = block_merge_prev(control, block); + block = block_merge_next(control, block); + block_insert(control, block); + } +} + +static inline void * tlsf_realloc(void * tlsf, void * ptr, size_t size) +{ + control_t * control = tlsf_cast(control_t *, tlsf); + void * p = 0; + + if (ptr && size == 0) + { + tlsf_free(tlsf, ptr); + } + else if (!ptr) + { + p = tlsf_malloc(tlsf, size); + } + else + { + block_header_t * block = block_from_ptr(ptr); + block_header_t * next = block_next(block); + + const size_t cursize = block_get_size(block); + const size_t combined = cursize + block_get_size(next) + block_header_overhead; + const size_t adjust = adjust_request_size(size, ALIGN_SIZE); + + tlsf_assert(!block_is_free(block) && "block already marked as free"); + + if (adjust > cursize && (!block_is_free(next) || adjust > combined)) + { + p = tlsf_malloc(tlsf, size); + if (p) + { + const size_t minsize = tlsf_min(cursize, size); + memcpy(p, ptr, minsize); + tlsf_free(tlsf, ptr); + } + } + else + { + if (adjust > cursize) + { + block_merge_next(control, block); + block_mark_as_used(block); + } + + block_trim_used(control, block, adjust); + p = ptr; + } + } + + return p; +} + +void * mm_create(void * mem, size_t bytes) +{ + return tlsf_create_with_pool(mem, bytes); +} + +void mm_destroy(void * mm) +{ + tlsf_destroy(mm); +} + +void * mm_get_pool(void * mm) +{ + return tlsf_get_pool(mm); +} + +void * mm_add_pool(void * mm, void * mem, size_t bytes) +{ + return tlsf_add_pool(mm, mem, bytes); +} + +void mm_remove_pool(void * mm, void * pool) +{ + tlsf_remove_pool(mm, pool); +} + +void * mm_malloc(void * mm, size_t size) +{ + return tlsf_malloc(mm, size); +} + +void * mm_memalign(void * mm, size_t align, size_t size) +{ + return tlsf_memalign(mm, align, size); +} + +void * mm_realloc(void * mm, void * ptr, size_t size) +{ + return tlsf_realloc(mm, ptr, size); +} + +void mm_free(void * mm, void * ptr) +{ + tlsf_free(mm, ptr); +} + +void * malloc(size_t size) +{ + return tlsf_malloc(__heap_pool, size); +} + +void * memalign(size_t align, size_t size) +{ + return tlsf_memalign(__heap_pool, align, size); +} + +void * realloc(void * ptr, size_t size) +{ + return tlsf_realloc(__heap_pool, ptr, size); +} + +void * calloc(size_t nmemb, size_t size) +{ + void * ptr; + + if((ptr = malloc(nmemb * size))) + memset(ptr, 0, nmemb * size); + + return ptr; +} + +void free(void * ptr) +{ + tlsf_free(__heap_pool, ptr); +} + +void do_init_mem_pool(void) +{ +#ifndef __SANDBOX__ + extern unsigned char __heap_start; + extern unsigned char __heap_end; + __heap_pool = tlsf_create_with_pool((void *)&__heap_start, (size_t)(&__heap_end - &__heap_start)); +#else + static char __heap_buf[SZ_16M]; + __heap_pool = tlsf_create_with_pool((void *)__heap_buf, (size_t)(sizeof(__heap_buf))); +#endif +} diff --git a/hw/mcu/allwinner/f1c100s/lib/memcpy.S b/hw/mcu/allwinner/f1c100s/lib/memcpy.S new file mode 100644 index 000000000..f7ed3130c --- /dev/null +++ b/hw/mcu/allwinner/f1c100s/lib/memcpy.S @@ -0,0 +1,404 @@ +/* + * memcpy.S + */ + .text + + .global memcpy + .type memcpy, %function + .align 4 + +memcpy: + /* determine copy direction */ + cmp r1, r0 + bcc .Lmemcpy_backwards + + moveq r0, #0 /* quick abort for len=0 */ + moveq pc, lr + + stmdb sp!, {r0, lr} /* memcpy() returns dest addr */ + subs r2, r2, #4 + blt .Lmemcpy_fl4 /* less than 4 bytes */ + ands r12, r0, #3 + bne .Lmemcpy_fdestul /* oh unaligned destination addr */ + ands r12, r1, #3 + bne .Lmemcpy_fsrcul /* oh unaligned source addr */ + +.Lmemcpy_ft8: + /* we have aligned source and destination */ + subs r2, r2, #8 + blt .Lmemcpy_fl12 /* less than 12 bytes (4 from above) */ + subs r2, r2, #0x14 + blt .Lmemcpy_fl32 /* less than 32 bytes (12 from above) */ + stmdb sp!, {r4} /* borrow r4 */ + + /* blat 32 bytes at a time */ +.Lmemcpy_floop32: + ldmia r1!, {r3, r4, r12, lr} + stmia r0!, {r3, r4, r12, lr} + ldmia r1!, {r3, r4, r12, lr} + stmia r0!, {r3, r4, r12, lr} + subs r2, r2, #0x20 + bge .Lmemcpy_floop32 + + cmn r2, #0x10 + ldmgeia r1!, {r3, r4, r12, lr} /* blat a remaining 16 bytes */ + stmgeia r0!, {r3, r4, r12, lr} + subge r2, r2, #0x10 + ldmia sp!, {r4} /* return r4 */ + +.Lmemcpy_fl32: + adds r2, r2, #0x14 + + /* blat 12 bytes at a time */ +.Lmemcpy_floop12: + ldmgeia r1!, {r3, r12, lr} + stmgeia r0!, {r3, r12, lr} + subges r2, r2, #0x0c + bge .Lmemcpy_floop12 + +.Lmemcpy_fl12: + adds r2, r2, #8 + blt .Lmemcpy_fl4 + + subs r2, r2, #4 + ldrlt r3, [r1], #4 + strlt r3, [r0], #4 + ldmgeia r1!, {r3, r12} + stmgeia r0!, {r3, r12} + subge r2, r2, #4 + +.Lmemcpy_fl4: + /* less than 4 bytes to go */ + adds r2, r2, #4 + ldmeqia sp!, {r0, pc} /* done */ + + /* copy the crud byte at a time */ + cmp r2, #2 + ldrb r3, [r1], #1 + strb r3, [r0], #1 + ldrgeb r3, [r1], #1 + strgeb r3, [r0], #1 + ldrgtb r3, [r1], #1 + strgtb r3, [r0], #1 + ldmia sp!, {r0, pc} + + /* erg - unaligned destination */ +.Lmemcpy_fdestul: + rsb r12, r12, #4 + cmp r12, #2 + + /* align destination with byte copies */ + ldrb r3, [r1], #1 + strb r3, [r0], #1 + ldrgeb r3, [r1], #1 + strgeb r3, [r0], #1 + ldrgtb r3, [r1], #1 + strgtb r3, [r0], #1 + subs r2, r2, r12 + blt .Lmemcpy_fl4 /* less the 4 bytes */ + + ands r12, r1, #3 + beq .Lmemcpy_ft8 /* we have an aligned source */ + + /* erg - unaligned source */ + /* This is where it gets nasty ... */ +.Lmemcpy_fsrcul: + bic r1, r1, #3 + ldr lr, [r1], #4 + cmp r12, #2 + bgt .Lmemcpy_fsrcul3 + beq .Lmemcpy_fsrcul2 + cmp r2, #0x0c + blt .Lmemcpy_fsrcul1loop4 + sub r2, r2, #0x0c + stmdb sp!, {r4, r5} + +.Lmemcpy_fsrcul1loop16: + mov r3, lr, lsr #8 + ldmia r1!, {r4, r5, r12, lr} + orr r3, r3, r4, lsl #24 + mov r4, r4, lsr #8 + orr r4, r4, r5, lsl #24 + mov r5, r5, lsr #8 + orr r5, r5, r12, lsl #24 + mov r12, r12, lsr #8 + orr r12, r12, lr, lsl #24 + stmia r0!, {r3-r5, r12} + subs r2, r2, #0x10 + bge .Lmemcpy_fsrcul1loop16 + ldmia sp!, {r4, r5} + adds r2, r2, #0x0c + blt .Lmemcpy_fsrcul1l4 + +.Lmemcpy_fsrcul1loop4: + mov r12, lr, lsr #8 + ldr lr, [r1], #4 + orr r12, r12, lr, lsl #24 + str r12, [r0], #4 + subs r2, r2, #4 + bge .Lmemcpy_fsrcul1loop4 + +.Lmemcpy_fsrcul1l4: + sub r1, r1, #3 + b .Lmemcpy_fl4 + +.Lmemcpy_fsrcul2: + cmp r2, #0x0c + blt .Lmemcpy_fsrcul2loop4 + sub r2, r2, #0x0c + stmdb sp!, {r4, r5} + +.Lmemcpy_fsrcul2loop16: + mov r3, lr, lsr #16 + ldmia r1!, {r4, r5, r12, lr} + orr r3, r3, r4, lsl #16 + mov r4, r4, lsr #16 + orr r4, r4, r5, lsl #16 + mov r5, r5, lsr #16 + orr r5, r5, r12, lsl #16 + mov r12, r12, lsr #16 + orr r12, r12, lr, lsl #16 + stmia r0!, {r3-r5, r12} + subs r2, r2, #0x10 + bge .Lmemcpy_fsrcul2loop16 + ldmia sp!, {r4, r5} + adds r2, r2, #0x0c + blt .Lmemcpy_fsrcul2l4 + +.Lmemcpy_fsrcul2loop4: + mov r12, lr, lsr #16 + ldr lr, [r1], #4 + orr r12, r12, lr, lsl #16 + str r12, [r0], #4 + subs r2, r2, #4 + bge .Lmemcpy_fsrcul2loop4 + +.Lmemcpy_fsrcul2l4: + sub r1, r1, #2 + b .Lmemcpy_fl4 + +.Lmemcpy_fsrcul3: + cmp r2, #0x0c + blt .Lmemcpy_fsrcul3loop4 + sub r2, r2, #0x0c + stmdb sp!, {r4, r5} + +.Lmemcpy_fsrcul3loop16: + mov r3, lr, lsr #24 + ldmia r1!, {r4, r5, r12, lr} + orr r3, r3, r4, lsl #8 + mov r4, r4, lsr #24 + orr r4, r4, r5, lsl #8 + mov r5, r5, lsr #24 + orr r5, r5, r12, lsl #8 + mov r12, r12, lsr #24 + orr r12, r12, lr, lsl #8 + stmia r0!, {r3-r5, r12} + subs r2, r2, #0x10 + bge .Lmemcpy_fsrcul3loop16 + ldmia sp!, {r4, r5} + adds r2, r2, #0x0c + blt .Lmemcpy_fsrcul3l4 + +.Lmemcpy_fsrcul3loop4: + mov r12, lr, lsr #24 + ldr lr, [r1], #4 + orr r12, r12, lr, lsl #8 + str r12, [r0], #4 + subs r2, r2, #4 + bge .Lmemcpy_fsrcul3loop4 + +.Lmemcpy_fsrcul3l4: + sub r1, r1, #1 + b .Lmemcpy_fl4 + +.Lmemcpy_backwards: + add r1, r1, r2 + add r0, r0, r2 + subs r2, r2, #4 + blt .Lmemcpy_bl4 /* less than 4 bytes */ + ands r12, r0, #3 + bne .Lmemcpy_bdestul /* oh unaligned destination addr */ + ands r12, r1, #3 + bne .Lmemcpy_bsrcul /* oh unaligned source addr */ + +.Lmemcpy_bt8: + /* we have aligned source and destination */ + subs r2, r2, #8 + blt .Lmemcpy_bl12 /* less than 12 bytes (4 from above) */ + stmdb sp!, {r4, lr} + subs r2, r2, #0x14 /* less than 32 bytes (12 from above) */ + blt .Lmemcpy_bl32 + + /* blat 32 bytes at a time */ +.Lmemcpy_bloop32: + ldmdb r1!, {r3, r4, r12, lr} + stmdb r0!, {r3, r4, r12, lr} + ldmdb r1!, {r3, r4, r12, lr} + stmdb r0!, {r3, r4, r12, lr} + subs r2, r2, #0x20 + bge .Lmemcpy_bloop32 + +.Lmemcpy_bl32: + cmn r2, #0x10 + ldmgedb r1!, {r3, r4, r12, lr} /* blat a remaining 16 bytes */ + stmgedb r0!, {r3, r4, r12, lr} + subge r2, r2, #0x10 + adds r2, r2, #0x14 + ldmgedb r1!, {r3, r12, lr} /* blat a remaining 12 bytes */ + stmgedb r0!, {r3, r12, lr} + subge r2, r2, #0x0c + ldmia sp!, {r4, lr} + +.Lmemcpy_bl12: + adds r2, r2, #8 + blt .Lmemcpy_bl4 + subs r2, r2, #4 + ldrlt r3, [r1, #-4]! + strlt r3, [r0, #-4]! + ldmgedb r1!, {r3, r12} + stmgedb r0!, {r3, r12} + subge r2, r2, #4 + +.Lmemcpy_bl4: + /* less than 4 bytes to go */ + adds r2, r2, #4 + moveq pc, lr + + /* copy the crud byte at a time */ + cmp r2, #2 + ldrb r3, [r1, #-1]! + strb r3, [r0, #-1]! + ldrgeb r3, [r1, #-1]! + strgeb r3, [r0, #-1]! + ldrgtb r3, [r1, #-1]! + strgtb r3, [r0, #-1]! + mov pc, lr + + /* erg - unaligned destination */ +.Lmemcpy_bdestul: + cmp r12, #2 + + /* align destination with byte copies */ + ldrb r3, [r1, #-1]! + strb r3, [r0, #-1]! + ldrgeb r3, [r1, #-1]! + strgeb r3, [r0, #-1]! + ldrgtb r3, [r1, #-1]! + strgtb r3, [r0, #-1]! + subs r2, r2, r12 + blt .Lmemcpy_bl4 /* less than 4 bytes to go */ + ands r12, r1, #3 + beq .Lmemcpy_bt8 /* we have an aligned source */ + + /* erg - unaligned source */ + /* This is where it gets nasty ... */ +.Lmemcpy_bsrcul: + bic r1, r1, #3 + ldr r3, [r1, #0] + cmp r12, #2 + blt .Lmemcpy_bsrcul1 + beq .Lmemcpy_bsrcul2 + cmp r2, #0x0c + blt .Lmemcpy_bsrcul3loop4 + sub r2, r2, #0x0c + stmdb sp!, {r4, r5, lr} + +.Lmemcpy_bsrcul3loop16: + mov lr, r3, lsl #8 + ldmdb r1!, {r3-r5, r12} + orr lr, lr, r12, lsr #24 + mov r12, r12, lsl #8 + orr r12, r12, r5, lsr #24 + mov r5, r5, lsl #8 + orr r5, r5, r4, lsr #24 + mov r4, r4, lsl #8 + orr r4, r4, r3, lsr #24 + stmdb r0!, {r4, r5, r12, lr} + subs r2, r2, #0x10 + bge .Lmemcpy_bsrcul3loop16 + ldmia sp!, {r4, r5, lr} + adds r2, r2, #0x0c + blt .Lmemcpy_bsrcul3l4 + +.Lmemcpy_bsrcul3loop4: + mov r12, r3, lsl #8 + ldr r3, [r1, #-4]! + orr r12, r12, r3, lsr #24 + str r12, [r0, #-4]! + subs r2, r2, #4 + bge .Lmemcpy_bsrcul3loop4 + +.Lmemcpy_bsrcul3l4: + add r1, r1, #3 + b .Lmemcpy_bl4 + +.Lmemcpy_bsrcul2: + cmp r2, #0x0c + blt .Lmemcpy_bsrcul2loop4 + sub r2, r2, #0x0c + stmdb sp!, {r4, r5, lr} + +.Lmemcpy_bsrcul2loop16: + mov lr, r3, lsl #16 + ldmdb r1!, {r3-r5, r12} + orr lr, lr, r12, lsr #16 + mov r12, r12, lsl #16 + orr r12, r12, r5, lsr #16 + mov r5, r5, lsl #16 + orr r5, r5, r4, lsr #16 + mov r4, r4, lsl #16 + orr r4, r4, r3, lsr #16 + stmdb r0!, {r4, r5, r12, lr} + subs r2, r2, #0x10 + bge .Lmemcpy_bsrcul2loop16 + ldmia sp!, {r4, r5, lr} + adds r2, r2, #0x0c + blt .Lmemcpy_bsrcul2l4 + +.Lmemcpy_bsrcul2loop4: + mov r12, r3, lsl #16 + ldr r3, [r1, #-4]! + orr r12, r12, r3, lsr #16 + str r12, [r0, #-4]! + subs r2, r2, #4 + bge .Lmemcpy_bsrcul2loop4 + +.Lmemcpy_bsrcul2l4: + add r1, r1, #2 + b .Lmemcpy_bl4 + +.Lmemcpy_bsrcul1: + cmp r2, #0x0c + blt .Lmemcpy_bsrcul1loop4 + sub r2, r2, #0x0c + stmdb sp!, {r4, r5, lr} + +.Lmemcpy_bsrcul1loop32: + mov lr, r3, lsl #24 + ldmdb r1!, {r3-r5, r12} + orr lr, lr, r12, lsr #8 + mov r12, r12, lsl #24 + orr r12, r12, r5, lsr #8 + mov r5, r5, lsl #24 + orr r5, r5, r4, lsr #8 + mov r4, r4, lsl #24 + orr r4, r4, r3, lsr #8 + stmdb r0!, {r4, r5, r12, lr} + subs r2, r2, #0x10 + bge .Lmemcpy_bsrcul1loop32 + ldmia sp!, {r4, r5, lr} + adds r2, r2, #0x0c + blt .Lmemcpy_bsrcul1l4 + +.Lmemcpy_bsrcul1loop4: + mov r12, r3, lsl #24 + ldr r3, [r1, #-4]! + orr r12, r12, r3, lsr #8 + str r12, [r0, #-4]! + subs r2, r2, #4 + bge .Lmemcpy_bsrcul1loop4 + +.Lmemcpy_bsrcul1l4: + add r1, r1, #1 + b .Lmemcpy_bl4 diff --git a/hw/mcu/allwinner/f1c100s/lib/memset.S b/hw/mcu/allwinner/f1c100s/lib/memset.S new file mode 100644 index 000000000..3eea2db1e --- /dev/null +++ b/hw/mcu/allwinner/f1c100s/lib/memset.S @@ -0,0 +1,79 @@ +/* + * memcpy.S + */ + .text + + .global memset + .type memset, %function + .align 4 + +memset: + stmfd sp!, {r0} /* remember address for return value */ + and r1, r1, #0x000000ff /* we write bytes */ + + cmp r2, #0x00000004 /* do we have less than 4 bytes */ + blt .Lmemset_lessthanfour + + /* first we will word align the address */ + ands r3, r0, #0x00000003 /* get the bottom two bits */ + beq .Lmemset_addraligned /* the address is word aligned */ + + rsb r3, r3, #0x00000004 + sub r2, r2, r3 + cmp r3, #0x00000002 + strb r1, [r0], #0x0001 /* set 1 byte */ + strgeb r1, [r0], #0x0001 /* set another byte */ + strgtb r1, [r0], #0x0001 /* and a third */ + + cmp r2, #0x00000004 + blt .Lmemset_lessthanfour + + /* now we must be word aligned */ +.Lmemset_addraligned: + orr r3, r1, r1, lsl #8 /* repeat the byte into a word */ + orr r3, r3, r3, lsl #16 + + /* we know we have at least 4 bytes ... */ + cmp r2, #0x00000020 /* if less than 32 then use words */ + blt .Lmemset_lessthan32 + + /* we have at least 32 so lets use quad words */ + stmfd sp!, {r4-r6} /* store registers */ + mov r4, r3 /* duplicate data */ + mov r5, r3 + mov r6, r3 + +.Lmemset_loop16: + stmia r0!, {r3-r6} /* store 16 bytes */ + sub r2, r2, #0x00000010 /* adjust count */ + cmp r2, #0x00000010 /* still got at least 16 bytes ? */ + bgt .Lmemset_loop16 + + ldmfd sp!, {r4-r6} /* restore registers */ + + /* do we need to set some words as well ? */ + cmp r2, #0x00000004 + blt .Lmemset_lessthanfour + + /* have either less than 16 or less than 32 depending on route taken */ +.Lmemset_lessthan32: + + /* we have at least 4 bytes so copy as words */ +.Lmemset_loop4: + str r3, [r0], #0x0004 + sub r2, r2, #0x0004 + cmp r2, #0x00000004 + bge .Lmemset_loop4 + +.Lmemset_lessthanfour: + cmp r2, #0x00000000 + ldmeqfd sp!, {r0} + moveq pc, lr /* zero length so exit */ + + cmp r2, #0x00000002 + strb r1, [r0], #0x0001 /* set 1 byte */ + strgeb r1, [r0], #0x0001 /* set another byte */ + strgtb r1, [r0], #0x0001 /* and a third */ + + ldmfd sp!, {r0} + mov pc, lr /* exit */ diff --git a/hw/mcu/allwinner/f1c100s/lib/printf.c b/hw/mcu/allwinner/f1c100s/lib/printf.c new file mode 100644 index 000000000..366bb9c0b --- /dev/null +++ b/hw/mcu/allwinner/f1c100s/lib/printf.c @@ -0,0 +1,757 @@ + +/////////////////////////////////////////////////////////////////////////////// +// \author (c) Marco Paland (info@paland.com) +// 2014-2018, PALANDesign Hannover, Germany +// +// \license The MIT License (MIT) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// \brief Tiny printf, sprintf and (v)snprintf implementation, optimized for speed on +// embedded systems with a very limited resources. These routines are thread +// safe and reentrant! +// Use this instead of the bloated standard/newlib printf cause these use +// malloc for printf (and may not be thread safe). +// +/////////////////////////////////////////////////////////////////////////////// + +#include +#include "printf.h" + + +// ntoa conversion buffer size, this must be big enough to hold +// one converted numeric number including padded zeros (dynamically created on stack) +// 32 byte is a good default +#define PRINTF_NTOA_BUFFER_SIZE 32U + +// ftoa conversion buffer size, this must be big enough to hold +// one converted float number including padded zeros (dynamically created on stack) +// 32 byte is a good default +#define PRINTF_FTOA_BUFFER_SIZE 32U + +// define this to support floating point (%f) +#define PRINTF_SUPPORT_FLOAT + +// define this to support long long types (%llu or %p) +#define PRINTF_SUPPORT_LONG_LONG + +// define this to support the ptrdiff_t type (%t) +// ptrdiff_t is normally defined in as long or long long type +#define PRINTF_SUPPORT_PTRDIFF_T + + +/////////////////////////////////////////////////////////////////////////////// + +// internal flag definitions +#define FLAGS_ZEROPAD (1U << 0U) +#define FLAGS_LEFT (1U << 1U) +#define FLAGS_PLUS (1U << 2U) +#define FLAGS_SPACE (1U << 3U) +#define FLAGS_HASH (1U << 4U) +#define FLAGS_UPPERCASE (1U << 5U) +#define FLAGS_CHAR (1U << 6U) +#define FLAGS_SHORT (1U << 7U) +#define FLAGS_LONG (1U << 8U) +#define FLAGS_LONG_LONG (1U << 9U) +#define FLAGS_PRECISION (1U << 10U) + +typedef unsigned char bool; +#ifndef false +#define false 0 +#endif +#ifndef true +#define true (!false) +#endif +extern void sys_uart_putc(char c); +static char last_ch; +void _putchar(char character) +{ + if(character == 0x0a && last_ch != 0x0d) + { + sys_uart_putc(0x0d); + } + sys_uart_putc(character); + +} + +// output function type +typedef void (*out_fct_type)(char character, void* buffer, size_t idx, size_t maxlen); + + +// wrapper (used as buffer) for output function type +typedef struct { + void (*fct)(char character, void* arg); + void* arg; +} out_fct_wrap_type; + + +// internal buffer output +static inline void _out_buffer(char character, void* buffer, size_t idx, size_t maxlen) +{ + if (idx < maxlen) { + ((char*)buffer)[idx] = character; + } +} + + +// internal null output +static inline void _out_null(char character, void* buffer, size_t idx, size_t maxlen) +{ + (void)character; (void)buffer; (void)idx; (void)maxlen; +} + + +// internal _putchar wrapper +static inline void _out_char(char character, void* buffer, size_t idx, size_t maxlen) +{ + (void)buffer; (void)idx; (void)maxlen; + if (character) { + _putchar(character); + } +} + + +// internal output function wrapper +static inline void _out_fct(char character, void* buffer, size_t idx, size_t maxlen) +{ + (void)idx; (void)maxlen; + // buffer is the output fct pointer + ((out_fct_wrap_type*)buffer)->fct(character, ((out_fct_wrap_type*)buffer)->arg); +} + + +// internal strlen +// \return The length of the string (excluding the terminating 0) +static inline unsigned int _strlen(const char* str) +{ + const char* s; + for (s = str; *s; ++s); + return (unsigned int)(s - str); +} + + +// internal test if char is a digit (0-9) +// \return true if char is a digit +static inline bool _is_digit(char ch) +{ + return (ch >= '0') && (ch <= '9'); +} + + +// internal ASCII string to unsigned int conversion +static unsigned int _atoi(const char** str) +{ + unsigned int i = 0U; + while (_is_digit(**str)) { + i = i * 10U + (unsigned int)(*((*str)++) - '0'); + } + return i; +} + + +// internal itoa format +static size_t _ntoa_format(out_fct_type out, char* buffer, size_t idx, size_t maxlen, char* buf, size_t len, bool negative, unsigned int base, unsigned int prec, unsigned int width, unsigned int flags) +{ + const size_t start_idx = idx; + + // pad leading zeros + while (!(flags & FLAGS_LEFT) && (len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } + while (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } + + // handle hash + if (flags & FLAGS_HASH) { + if (!(flags & FLAGS_PRECISION) && len && ((len == prec) || (len == width))) { + len--; + if (len && (base == 16U)) { + len--; + } + } + if ((base == 16U) && !(flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = 'x'; + } + else if ((base == 16U) && (flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = 'X'; + } + else if ((base == 2U) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = 'b'; + } + if (len < PRINTF_NTOA_BUFFER_SIZE) { + buf[len++] = '0'; + } + } + + // handle sign + if (len && (len == width) && (negative || (flags & FLAGS_PLUS) || (flags & FLAGS_SPACE))) { + len--; + } + if (len < PRINTF_NTOA_BUFFER_SIZE) { + if (negative) { + buf[len++] = '-'; + } + else if (flags & FLAGS_PLUS) { + buf[len++] = '+'; // ignore the space if the '+' exists + } + else if (flags & FLAGS_SPACE) { + buf[len++] = ' '; + } + } + + // pad spaces up to given width + if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) { + for (size_t i = len; i < width; i++) { + out(' ', buffer, idx++, maxlen); + } + } + + // reverse string + for (size_t i = 0U; i < len; i++) { + out(buf[len - i - 1U], buffer, idx++, maxlen); + } + + // append pad spaces up to given width + if (flags & FLAGS_LEFT) { + while (idx - start_idx < width) { + out(' ', buffer, idx++, maxlen); + } + } + + return idx; +} + + +// internal itoa for 'long' type +static size_t _ntoa_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long value, bool negative, unsigned long base, unsigned int prec, unsigned int width, unsigned int flags) +{ + char buf[PRINTF_NTOA_BUFFER_SIZE]; + size_t len = 0U; + + // no hash for 0 values + if (!value) { + flags &= ~FLAGS_HASH; + } + + // write if precision != 0 and value is != 0 + if (!(flags & FLAGS_PRECISION) || value) { + do { + const char digit = (char)(value % base); + buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; + value /= base; + } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); + } + + return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); +} + + +// internal itoa for 'long long' type +#if defined(PRINTF_SUPPORT_LONG_LONG) +static size_t _ntoa_long_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long long value, bool negative, unsigned long long base, unsigned int prec, unsigned int width, unsigned int flags) +{ + char buf[PRINTF_NTOA_BUFFER_SIZE]; + size_t len = 0U; + + // no hash for 0 values + if (!value) { + flags &= ~FLAGS_HASH; + } + + // write if precision != 0 and value is != 0 + if (!(flags & FLAGS_PRECISION) || value) { + do { + const char digit = (char)(value % base); + buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; + value /= base; + } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); + } + + return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); +} +#endif // PRINTF_SUPPORT_LONG_LONG + + +#if defined(PRINTF_SUPPORT_FLOAT) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfloat-equal" + +static size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags) +{ + const size_t start_idx = idx; + + char buf[PRINTF_FTOA_BUFFER_SIZE]; + size_t len = 0U; + double diff = 0.0; + + // if input is larger than thres_max, revert to exponential + const double thres_max = (double)0x7FFFFFFF; + + // powers of 10 + static const double pow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; + + // test for negative + bool negative = false; + if (value < 0) { + negative = true; + value = 0 - value; + } + + // set default precision to 6, if not set explicitly + if (!(flags & FLAGS_PRECISION)) { + prec = 6U; + } + // limit precision to 9, cause a prec >= 10 can lead to overflow errors + while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) { + buf[len++] = '0'; + prec--; + } + + int whole = (int)value; + double tmp = (value - whole) * pow10[prec]; + unsigned long frac = (unsigned long)tmp; + diff = tmp - frac; + + if (diff > 0.5l) { + ++frac; + // handle rollover, e.g. case 0.99 with prec 1 is 1.0 + if (frac >= pow10[prec]) { + frac = 0; + ++whole; + } + } + else if ((diff == 0.5l) && ((frac == 0U) || (frac & 1U))) { + // if halfway, round up if odd, OR if last digit is 0 + ++frac; + } + + // TBD: for very large numbers switch back to native sprintf for exponentials. Anyone want to write code to replace this? + // Normal printf behavior is to print EVERY whole number digit which can be 100s of characters overflowing your buffers == bad + if (value > thres_max) { + return 0U; + } + + if (prec == 0U) { + diff = value - (double)whole; + if (diff > 0.5l) { + // greater than 0.5, round up, e.g. 1.6 -> 2 + ++whole; + } + else if ((diff == 0.5l) && (whole & 1)) { + // exactly 0.5 and ODD, then round up + // 1.5 -> 2, but 2.5 -> 2 + ++whole; + } + } + else { + unsigned int count = prec; + // now do fractional part, as an unsigned number + while (len < PRINTF_FTOA_BUFFER_SIZE) { + --count; + buf[len++] = (char)(48U + (frac % 10U)); + if (!(frac /= 10U)) { + break; + } + } + // add extra 0s + while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) { + buf[len++] = '0'; + } + if (len < PRINTF_FTOA_BUFFER_SIZE) { + // add decimal + buf[len++] = '.'; + } + } + + // do whole part, number is reversed + while (len < PRINTF_FTOA_BUFFER_SIZE) { + buf[len++] = (char)(48 + (whole % 10)); + if (!(whole /= 10)) { + break; + } + } + + // pad leading zeros + while (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } + + // handle sign + if ((len == width) && (negative || (flags & FLAGS_PLUS) || (flags & FLAGS_SPACE))) { + len--; + } + if (len < PRINTF_FTOA_BUFFER_SIZE) { + if (negative) { + buf[len++] = '-'; + } + else if (flags & FLAGS_PLUS) { + buf[len++] = '+'; // ignore the space if the '+' exists + } + else if (flags & FLAGS_SPACE) { + buf[len++] = ' '; + } + } + + // pad spaces up to given width + if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) { + for (size_t i = len; i < width; i++) { + out(' ', buffer, idx++, maxlen); + } + } + + // reverse string + for (size_t i = 0U; i < len; i++) { + out(buf[len - i - 1U], buffer, idx++, maxlen); + } + + // append pad spaces up to given width + if (flags & FLAGS_LEFT) { + while (idx - start_idx < width) { + out(' ', buffer, idx++, maxlen); + } + } + + return idx; +} +#pragma GCC diagnostic pop +#endif // PRINTF_SUPPORT_FLOAT + + +// internal vsnprintf +static int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char* format, va_list va) +{ + unsigned int flags, width, precision, n; + size_t idx = 0U; + + if (!buffer) { + // use null output function + out = _out_null; + } + + while (*format) + { + // format specifier? %[flags][width][.precision][length] + if (*format != '%') { + // no + out(*format, buffer, idx++, maxlen); + format++; + continue; + } + else { + // yes, evaluate it + format++; + } + + // evaluate flags + flags = 0U; + do { + switch (*format) { + case '0': flags |= FLAGS_ZEROPAD; format++; n = 1U; break; + case '-': flags |= FLAGS_LEFT; format++; n = 1U; break; + case '+': flags |= FLAGS_PLUS; format++; n = 1U; break; + case ' ': flags |= FLAGS_SPACE; format++; n = 1U; break; + case '#': flags |= FLAGS_HASH; format++; n = 1U; break; + default : n = 0U; break; + } + } while (n); + + // evaluate width field + width = 0U; + if (_is_digit(*format)) { + width = _atoi(&format); + } + else if (*format == '*') { + const int w = va_arg(va, int); + if (w < 0) { + flags |= FLAGS_LEFT; // reverse padding + width = (unsigned int)-w; + } + else { + width = (unsigned int)w; + } + format++; + } + + // evaluate precision field + precision = 0U; + if (*format == '.') { + flags |= FLAGS_PRECISION; + format++; + if (_is_digit(*format)) { + precision = _atoi(&format); + } + else if (*format == '*') { + const int prec = (int)va_arg(va, int); + precision = prec > 0 ? (unsigned int)prec : 0U; + format++; + } + } + + // evaluate length field + switch (*format) { + case 'l' : + flags |= FLAGS_LONG; + format++; + if (*format == 'l') { + flags |= FLAGS_LONG_LONG; + format++; + } + break; + case 'h' : + flags |= FLAGS_SHORT; + format++; + if (*format == 'h') { + flags |= FLAGS_CHAR; + format++; + } + break; +#if defined(PRINTF_SUPPORT_PTRDIFF_T) + case 't' : + flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + format++; + break; +#endif + case 'j' : + flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + format++; + break; + case 'z' : + flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + format++; + break; + default : + break; + } + + // evaluate specifier + switch (*format) { + case 'd' : + case 'i' : + case 'u' : + case 'x' : + case 'X' : + case 'o' : + case 'b' : { + // set the base + unsigned int base; + if (*format == 'x' || *format == 'X') { + base = 16U; + } + else if (*format == 'o') { + base = 8U; + } + else if (*format == 'b') { + base = 2U; + } + else { + base = 10U; + flags &= ~FLAGS_HASH; // no hash for dec format + } + // uppercase + if (*format == 'X') { + flags |= FLAGS_UPPERCASE; + } + + // no plus or space flag for u, x, X, o, b + if ((*format != 'i') && (*format != 'd')) { + flags &= ~(FLAGS_PLUS | FLAGS_SPACE); + } + + // ignore '0' flag when precision is given + if (flags & FLAGS_PRECISION) { + flags &= ~FLAGS_ZEROPAD; + } + + // convert the integer + if ((*format == 'i') || (*format == 'd')) { + // signed + if (flags & FLAGS_LONG_LONG) { +#if defined(PRINTF_SUPPORT_LONG_LONG) + const long long value = va_arg(va, long long); + idx = _ntoa_long_long(out, buffer, idx, maxlen, (unsigned long long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); +#endif + } + else if (flags & FLAGS_LONG) { + const long value = va_arg(va, long); + idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); + } + else { + const int value = (flags & FLAGS_CHAR) ? (char)va_arg(va, int) : (flags & FLAGS_SHORT) ? (short int)va_arg(va, int) : va_arg(va, int); + idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned int)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); + } + } + else { + // unsigned + if (flags & FLAGS_LONG_LONG) { +#if defined(PRINTF_SUPPORT_LONG_LONG) + idx = _ntoa_long_long(out, buffer, idx, maxlen, va_arg(va, unsigned long long), false, base, precision, width, flags); +#endif + } + else if (flags & FLAGS_LONG) { + idx = _ntoa_long(out, buffer, idx, maxlen, va_arg(va, unsigned long), false, base, precision, width, flags); + } + else { + const unsigned int value = (flags & FLAGS_CHAR) ? (unsigned char)va_arg(va, unsigned int) : (flags & FLAGS_SHORT) ? (unsigned short int)va_arg(va, unsigned int) : va_arg(va, unsigned int); + idx = _ntoa_long(out, buffer, idx, maxlen, value, false, base, precision, width, flags); + } + } + format++; + break; + } +#if defined(PRINTF_SUPPORT_FLOAT) + case 'f' : + case 'F' : + idx = _ftoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags); + format++; + break; +#endif // PRINTF_SUPPORT_FLOAT + case 'c' : { + unsigned int l = 1U; + // pre padding + if (!(flags & FLAGS_LEFT)) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + // char output + out((char)va_arg(va, int), buffer, idx++, maxlen); + // post padding + if (flags & FLAGS_LEFT) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + format++; + break; + } + + case 's' : { + char* p = va_arg(va, char*); + unsigned int l = _strlen(p); + // pre padding + if (flags & FLAGS_PRECISION) { + l = (l < precision ? l : precision); + } + if (!(flags & FLAGS_LEFT)) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + // string output + while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) { + out(*(p++), buffer, idx++, maxlen); + } + // post padding + if (flags & FLAGS_LEFT) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + format++; + break; + } + + case 'p' : { + width = sizeof(void*) * 2U; + flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE; +#if defined(PRINTF_SUPPORT_LONG_LONG) + const bool is_ll = sizeof(uintptr_t) == sizeof(long long); + if (is_ll) { + idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va_arg(va, void*), false, 16U, precision, width, flags); + } + else { +#endif + idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va_arg(va, void*)), false, 16U, precision, width, flags); +#if defined(PRINTF_SUPPORT_LONG_LONG) + } +#endif + format++; + break; + } + + case '%' : + out('%', buffer, idx++, maxlen); + format++; + break; + + default : + out(*format, buffer, idx++, maxlen); + format++; + break; + } + } + + // termination + out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen); + + // return written chars without terminating \0 + return (int)idx; +} + + +/////////////////////////////////////////////////////////////////////////////// + + +int printf(const char* format, ...) +{ + va_list va; + va_start(va, format); + char buffer[1]; + const int ret = _vsnprintf(_out_char, buffer, (size_t)-1, format, va); + va_end(va); + return ret; +} + + +int sprintf(char* buffer, const char* format, ...) +{ + va_list va; + va_start(va, format); + const int ret = _vsnprintf(_out_buffer, buffer, (size_t)-1, format, va); + va_end(va); + return ret; +} + + +int snprintf(char* buffer, size_t count, const char* format, ...) +{ + va_list va; + va_start(va, format); + const int ret = _vsnprintf(_out_buffer, buffer, count, format, va); + va_end(va); + return ret; +} + + +int vsnprintf(char* buffer, size_t count, const char* format, va_list va) +{ + return _vsnprintf(_out_buffer, buffer, count, format, va); +} + + +int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...) +{ + va_list va; + va_start(va, format); + out_fct_wrap_type out_fct_wrap = { out, arg }; + const int ret = _vsnprintf(_out_fct, (char*)&out_fct_wrap, (size_t)-1, format, va); + va_end(va); + return ret; +} diff --git a/hw/mcu/allwinner/f1c100s/machine/exception.c b/hw/mcu/allwinner/f1c100s/machine/exception.c new file mode 100644 index 000000000..ffc61bf47 --- /dev/null +++ b/hw/mcu/allwinner/f1c100s/machine/exception.c @@ -0,0 +1,76 @@ +/* + * exception.c + * + * Copyright(c) 2007-2018 Jianjun Jiang <8192542@qq.com> + * Official site: http://xboot.org + * Mobile phone: +86-18665388956 + * QQ: 8192542 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include +#include +#include + +static void show_regs(struct arm_regs_t * regs) +{ + int i; + + printf("pc : [<%08lx>] lr : [<%08lx>] cpsr: %08lx\r\n", regs->pc, regs->lr, regs->cpsr); + printf("sp : %08lx\r\n", regs->sp); + for(i = 12; i >= 0; i--) + { + printf("r%-2d: %08lx ", i, regs->r[i]); + if(i % 2 == 0) + printf("\r\n"); + } + printf("\r\n"); +} + +void arm32_do_undefined_instruction(struct arm_regs_t * regs) +{ + //gdbserver_handle_exception(regs); +} + +void arm32_do_software_interrupt(struct arm_regs_t * regs) +{ + show_regs(regs); + regs->pc += 4; +} + +void arm32_do_prefetch_abort(struct arm_regs_t * regs) +{ + show_regs(regs); + regs->pc += 4; +} + +void arm32_do_data_abort(struct arm_regs_t * regs) +{ + show_regs(regs); + regs->pc += 4; +} + +_Noreturn void __fatal_error(const char *msg) { + printf("%s\n", msg); + while (1); +} + +#ifndef NDEBUG +_Noreturn void __assert_func(const char *file, int line, const char *func, const char *expr) { + //printf("Assertion '%s' failed, at file %s:%d\n", expr, file, line); + __fatal_error("Assertion failed"); +} +#endif \ No newline at end of file diff --git a/hw/mcu/allwinner/f1c100s/machine/f1c100s-intc.c b/hw/mcu/allwinner/f1c100s/machine/f1c100s-intc.c new file mode 100644 index 000000000..2993f0b60 --- /dev/null +++ b/hw/mcu/allwinner/f1c100s/machine/f1c100s-intc.c @@ -0,0 +1,173 @@ +// Originally designed by Hong Xuyao + +#include +#include +#include +#include + +#define __irq __attribute__ ((interrupt ("IRQ"))) + +#ifndef __IO +#define __IO volatile +#endif + +typedef struct { + __IO uint32_t INTC_VECTOR_REG; // 0x00 + __IO uint32_t INTC_BASE_ADDR_REG; // 0x04 + uint32_t resv1[1]; // 0x08 + __IO uint32_t NMI_INT_CTRL_REG; // 0x0c + __IO uint32_t INTC_PEND_REG[2]; // 0x10 + uint32_t resv2[2]; // 0x18 + __IO uint32_t INTC_EN_REG[2]; // 0x20 + uint32_t resv3[2]; // 0x28 + __IO uint32_t INTC_MASK_REG[2]; // 0x30 + uint32_t resv4[2]; // 0x38 + __IO uint32_t INTC_RESP_REG[2]; // 0x40 + uint32_t resv5[2]; // 0x48 + __IO uint32_t INTC_FF_REG[2]; // 0x50 + uint32_t resv6[2]; // 0x58 + __IO uint32_t INTC_PRIO_REG[4]; // 0x60 +} INTC_TypeDef; + +#ifndef COUNTOF +#define COUNTOF(ar) (sizeof(ar)/sizeof(ar[0])) +#endif + +#define INTC ((INTC_TypeDef*)0x01C20400) + +static IRQHandleTypeDef irq_table[64] __attribute__((used, aligned(32))); + +void arm32_do_irq(struct arm_regs_t * regs) +{ + uint8_t nIRQ = f1c100s_intc_get_nirq(); + + // ForceIRQ flag must be cleared by ISR + // Otherwise ISR will be entered repeatedly + INTC->INTC_FF_REG[nIRQ / 32] &= ~(1 << nIRQ); + // Call the drivers ISR + f1c100s_intc_dispatch(nIRQ); + // Clear pending at the end of ISR + f1c100s_intc_clear_pend(nIRQ); +} + +void arm32_do_fiq(struct arm_regs_t * regs) +{ + // Call the drivers ISR + f1c100s_intc_dispatch(0); + // Clear pending at the end of ISR. + f1c100s_intc_clear_pend(0); +} + +/* +* Read active IRQ number +* @return: none +*/ +uint8_t f1c100s_intc_get_nirq(void) +{ + return ((INTC->INTC_VECTOR_REG >> 2) & 0x3F); +} + +/* +* Execute ISR corresponding to IRQ number +* @nIRQ: IRQ number +* @return: none +*/ +void f1c100s_intc_dispatch(uint8_t nIRQ) +{ + IRQHandleTypeDef handle = irq_table[nIRQ]; + if (handle) + handle(); +} + +/* +* Set handler function for specified IRQ +* @nIRQ: IRQ number +* @handle: Handle function +* @return: none +*/ +void f1c100s_intc_set_isr(uint8_t nIRQ, IRQHandleTypeDef handle) +{ + if (nIRQ < COUNTOF(irq_table)) { + irq_table[nIRQ] = handle; + } +} + +/* +* Enable IRQ +* @nIRQ: IRQ number +* @return: none +*/ +void f1c100s_intc_enable_irq(uint8_t nIRQ) +{ + INTC->INTC_EN_REG[nIRQ / 32] |= (1 << (nIRQ % 32)); +} + +/* +* Disable IRQ +* @nIRQ: IRQ number +* @return: none +*/ +void f1c100s_intc_disable_irq(uint8_t nIRQ) +{ + INTC->INTC_EN_REG[nIRQ / 32] &= ~(1 << (nIRQ % 32)); +} + +/* +* Mask IRQ +* @nIRQ: IRQ number +* @return: none +*/ +void f1c100s_intc_mask_irq(uint8_t nIRQ) +{ + INTC->INTC_MASK_REG[nIRQ / 32] |= (1 << (nIRQ % 32)); +} + +/* +* Unmask IRQ +* @nIRQ: IRQ number +* @return: none +*/ +void f1c100s_intc_unmask_irq(uint8_t nIRQ) +{ + INTC->INTC_MASK_REG[nIRQ / 32] &= ~(1 << (nIRQ % 32)); +} + +/* +* Immediately trigger IRQ +* @nIRQ: IRQ number +* @return: none +*/ +void f1c100s_intc_force_irq(uint8_t nIRQ) +{ + // This bit is to be cleared in IRQ handler + INTC->INTC_FF_REG[nIRQ / 32] = (1 << (nIRQ % 32)); +} + +/* +* Clear pending flag +* @nIRQ: IRQ number +* @return: none +*/ +void f1c100s_intc_clear_pend(uint8_t nIRQ) +{ + INTC->INTC_PEND_REG[nIRQ / 32] = (1 << (nIRQ % 32)); +} + + +/* +* Initialize IRQ module +* @return: none +*/ +void f1c100s_intc_init(void) +{ + INTC->INTC_EN_REG[0] = INTC->INTC_EN_REG[1] = 0; + INTC->INTC_MASK_REG[0] = INTC->INTC_MASK_REG[1] = 0; + INTC->INTC_FF_REG[0] = INTC->INTC_FF_REG[1] = 0; + INTC->INTC_RESP_REG[0] = INTC->INTC_RESP_REG[1] = 0; + INTC->INTC_PEND_REG[0] = INTC->INTC_PEND_REG[1] = ~0UL; + INTC->INTC_BASE_ADDR_REG = 0; + INTC->NMI_INT_CTRL_REG = 0; + for (unsigned int i = 0; i < COUNTOF(irq_table); i++) { + irq_table[i] = 0; + } +} diff --git a/hw/mcu/allwinner/f1c100s/machine/start.S b/hw/mcu/allwinner/f1c100s/machine/start.S new file mode 100644 index 000000000..1fd7cb1f9 --- /dev/null +++ b/hw/mcu/allwinner/f1c100s/machine/start.S @@ -0,0 +1,313 @@ +/* + * start.S + * + * Copyright(c) 2007-2018 Jianjun Jiang <8192542@qq.com> + * Official site: http://xboot.org + * Mobile phone: +86-18665388956 + * QQ: 8192542 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* + * Exception vector table + */ +.text + .arm + + .global _start +_start: + /* Boot head information for BROM */ + .long 0xea000016 + .byte 'e', 'G', 'O', 'N', '.', 'B', 'T', '0' + .long 0, __bootloader_size + .byte 'S', 'P', 'L', 2 + .long 0, 0 + .long 0, 0, 0, 0, 0, 0, 0, 0 + .long 0, 0, 0, 0, 0, 0, 0, 0 /* 0x40 - boot params, 0x58 - fel boot type, 0x5c - dram size */ + +_vector: + b reset + ldr pc, _undefined_instruction + ldr pc, _software_interrupt + ldr pc, _prefetch_abort + ldr pc, _data_abort + ldr pc, _not_used + ldr pc, _irq + ldr pc, _fiq + +_undefined_instruction: + .word undefined_instruction +_software_interrupt: + .word software_interrupt +_prefetch_abort: + .word prefetch_abort +_data_abort: + .word data_abort +_not_used: + .word not_used +_irq: + .word irq +_fiq: + .word fiq + +/* + * The actual reset code + */ +reset: + /* Save boot params to 0x00000040 */ + ldr r0, =0x00000040 + str sp, [r0, #0] + str lr, [r0, #4] + mrs lr, cpsr + str lr, [r0, #8] + mrc p15, 0, lr, c1, c0, 0 + str lr, [r0, #12] + mrc p15, 0, lr, c1, c0, 0 + str lr, [r0, #16] + + /* Check boot type just for fel */ + mov r0, #0x0 + ldr r1, [r0, #8] + ldr r2, =0x4c45462e + cmp r1, r2 + bne 1f + ldr r1, =0x1 + str r1, [r0, #0x58] +1: nop + + /* Enter svc mode and mask interrupts */ + mrs r0, cpsr + bic r0, r0, #0x1f + orr r0, r0, #0xd3 + msr cpsr, r0 + + /* Set vector to the low address */ + mrc p15, 0, r0, c1, c0, 0 + bic r0, #(1<<13) + mcr p15, 0, r0, c1, c0, 0 + + /* Copy vector to the correct address */ + adr r0, _vector + mrc p15, 0, r2, c1, c0, 0 + ands r2, r2, #(1 << 13) + ldreq r1, =0x00000000 + ldrne r1, =0xffff0000 + ldmia r0!, {r2-r8, r10} + stmia r1!, {r2-r8, r10} + ldmia r0!, {r2-r8, r10} + stmia r1!, {r2-r8, r10} + + /* Initial system clock, ddr add uart */ + bl sys_clock_init + bl sys_dram_init + bl sys_uart_init + + /* Boot speed up, leave slower sram */ + adr r0, _start + ldr r1, =_start + cmp r0, r1 + beq _speedup + ldr r0, =0x81f80000 + adr r1, _start + mov r2, #0x4000 + bl memcpy + ldr r0, =_speedup + ldr r1, =_start + sub r0, r0, r1 + ldr r1, =0x81f80000 + add r0, r0, r1 + mov pc, r0 +_speedup: + nop + + /* Copyself to link address */ + adr r0, _start + ldr r1, =_start + cmp r0, r1 + beq 1f + bl sys_copyself +1: nop + + /* Initialize stacks */ + mrs r0, cpsr + bic r0, r0, #0x1f + orr r1, r0, #0x1b + msr cpsr_cxsf, r1 + ldr sp, _stack_und_end + + bic r0, r0, #0x1f + orr r1, r0, #0x17 + msr cpsr_cxsf, r1 + ldr sp, _stack_abt_end + + bic r0, r0, #0x1f + orr r1, r0, #0x12 + msr cpsr_cxsf, r1 + ldr sp, _stack_irq_end + + bic r0, r0, #0x1f + orr r1, r0, #0x11 + msr cpsr_cxsf, r1 + ldr sp, _stack_fiq_end + + bic r0, r0, #0x1f + orr r1, r0, #0x13 + msr cpsr_cxsf, r1 + ldr sp, _stack_srv_end + + /* Copy data section */ + ldr r0, _data_start + ldr r1, _data_shadow_start + ldr r2, _data_shadow_end + sub r2, r2, r1 + bl memcpy + + /* Clear bss section */ + ldr r0, _bss_start + ldr r2, _bss_end + sub r2, r2, r0 + mov r1, #0 + bl memset + + /* Call _main */ + ldr r1, =_main + mov pc, r1 +_main: + bl main + b _main + + .global return_to_fel +return_to_fel: + mov r0, #0x4 + mov r1, #'e' + strb r1, [r0, #0] + mov r1, #'G' + strb r1, [r0, #1] + mov r1, #'O' + strb r1, [r0, #2] + mov r1, #'N' + strb r1, [r0, #3] + mov r1, #'.' + strb r1, [r0, #4] + mov r1, #'F' + strb r1, [r0, #5] + mov r1, #'E' + strb r1, [r0, #6] + mov r1, #'L' + strb r1, [r0, #7] + ldr r0, =0x00000040 + ldr sp, [r0, #0] + ldr lr, [r0, #4] + ldr r1, [r0, #16] + mcr p15, 0, r1, c1, c0, 0 + ldr r1, [r0, #12] + mcr p15, 0, r1, c1, c0, 0 + ldr r1, [r0, #8] + msr cpsr, r1 + bx lr + +/* + * Exception handlers + */ + .align 5 +undefined_instruction: + b . + + .align 5 +software_interrupt: + b . + + .align 5 +prefetch_abort: + b . + + .align 5 +data_abort: + b . + + .align 5 +not_used: + b . + + .align 5 +irq: + ldr sp, _stack_irq_end + sub sp, sp, #72 + stmia sp, {r0 - r12} + add r8, sp, #60 + stmdb r8, {sp, lr}^ + str lr, [r8, #0] + mrs r6, spsr + str r6, [r8, #4] + str r0, [r8, #8] + mov r0, sp + bl arm32_do_irq + ldmia sp, {r0 - lr}^ + mov r0, r0 + ldr lr, [sp, #60] + add sp, sp, #72 + subs pc, lr, #4 + + .align 5 +fiq: + ldr sp, _stack_irq_end + sub sp, sp, #72 + stmia sp, {r0 - r12} + add r8, sp, #60 + stmdb r8, {sp, lr}^ + str lr, [r8, #0] + mrs r6, spsr + str r6, [r8, #4] + str r0, [r8, #8] + mov r0, sp + bl arm32_do_fiq + ldmia sp, {r0 - lr}^ + mov r0, r0 + ldr lr, [sp, #60] + add sp, sp, #72 + subs pc, lr, #4 + +/* + * The location of section + */ + .align 4 +_image_start: + .long __image_start +_image_end: + .long __image_end +_data_shadow_start: + .long __data_shadow_start +_data_shadow_end: + .long __data_shadow_end +_data_start: + .long __data_start +_data_end: + .long __data_end +_bss_start: + .long __bss_start +_bss_end: + .long __bss_end +_stack_und_end: + .long __stack_und_end +_stack_abt_end: + .long __stack_abt_end +_stack_irq_end: + .long __stack_irq_end +_stack_fiq_end: + .long __stack_fiq_end +_stack_srv_end: + .long __stack_srv_end diff --git a/hw/mcu/allwinner/f1c100s/machine/sys-clock.c b/hw/mcu/allwinner/f1c100s/machine/sys-clock.c new file mode 100644 index 000000000..d151dd0c1 --- /dev/null +++ b/hw/mcu/allwinner/f1c100s/machine/sys-clock.c @@ -0,0 +1,124 @@ +/* + * sys-clock.c + * + * Copyright(c) 2007-2018 Jianjun Jiang <8192542@qq.com> + * Official site: http://xboot.org + * Mobile phone: +86-18665388956 + * QQ: 8192542 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +//#include +#include +#include +#include + +static inline void sdelay(int loops) +{ + __asm__ __volatile__ ("1:\n" "subs %0, %1, #1\n" + "bne 1b":"=r" (loops):"0"(loops)); +} + +static void wait_pll_stable(uint32_t base) +{ + uint32_t rval = 0; + uint32_t time = 0xfff; + + do { + rval = read32(base); + time--; + } while(time && !(rval & (1 << 28))); +} + +static void clock_set_pll_cpu(uint32_t clk) +{ + uint32_t n, k, m, p; + uint32_t rval = 0; + uint32_t div = 0; + + if(clk > 720000000) + clk = 720000000; + + if((clk % 24000000) == 0) + { + div = clk / 24000000; + n = div - 1; + k = 0; + m = 0; + p = 0; + } + else if((clk % 12000000) == 0) + { + m = 1; + div = clk / 12000000; + if((div % 3) == 0) + k = 2; + else if((div % 4) == 0) + k = 3; + else + k = 1; + n = (div / (k + 1)) - 1; + p = 0; + } + else + { + div = clk / 24000000; + n = div - 1; + k = 0; + m = 0; + p = 0; + } + + rval = read32(F1C100S_CCU_BASE + CCU_PLL_CPU_CTRL); + rval &= ~((0x3 << 16) | (0x1f << 8) | (0x3 << 4) | (0x3 << 0)); + rval |= (1U << 31) | (p << 16) | (n << 8) | (k << 4) | m; + write32(F1C100S_CCU_BASE + CCU_PLL_CPU_CTRL, rval); + wait_pll_stable(F1C100S_CCU_BASE + CCU_PLL_CPU_CTRL); +} + +void sys_clock_init(void) +{ + uint32_t val; + + write32(F1C100S_CCU_BASE + CCU_PLL_STABLE_TIME0, 0x1ff); + write32(F1C100S_CCU_BASE + CCU_PLL_STABLE_TIME1, 0x1ff); + + val = read32(F1C100S_CCU_BASE + CCU_CPU_CFG); + val &= ~(0x3 << 16); + val |= (0x1 << 16); + write32(F1C100S_CCU_BASE + CCU_CPU_CFG, val); + sdelay(100); + + write32(F1C100S_CCU_BASE + CCU_PLL_VIDEO_CTRL, 0x81004107); + sdelay(100); + write32(F1C100S_CCU_BASE + CCU_PLL_PERIPH_CTRL, 0x80041800); + sdelay(100); + write32(F1C100S_CCU_BASE + CCU_AHB_APB_CFG, 0x00003180); + sdelay(100); + + val = read32(F1C100S_CCU_BASE + CCU_DRAM_CLK_GATE); + val |= (0x1 << 26) | (0x1 << 24); + write32(F1C100S_CCU_BASE + CCU_DRAM_CLK_GATE, val); + sdelay(100); + + clock_set_pll_cpu(408000000); + val = read32(F1C100S_CCU_BASE + CCU_CPU_CFG); + val &= ~(0x3 << 16); + val |= (0x2 << 16); + write32(F1C100S_CCU_BASE + CCU_CPU_CFG, val); + sdelay(100); +} diff --git a/hw/mcu/allwinner/f1c100s/machine/sys-copyself.c b/hw/mcu/allwinner/f1c100s/machine/sys-copyself.c new file mode 100644 index 000000000..4116e1265 --- /dev/null +++ b/hw/mcu/allwinner/f1c100s/machine/sys-copyself.c @@ -0,0 +1,111 @@ +/* + * sys-copyself.c + * + * Copyright(c) 2007-2018 Jianjun Jiang <8192542@qq.com> + * Official site: http://xboot.org + * Mobile phone: +86-18665388956 + * QQ: 8192542 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include + +extern unsigned char __image_start; +extern unsigned char __image_end; +extern void return_to_fel(void); +extern void sys_mmu_init(void); +extern void sys_uart_putc(char c); +extern void sys_spi_flash_init(void); +extern void sys_spi_flash_exit(void); +extern void sys_spi_flash_read(int addr, void * buf, int count); + +enum { + BOOT_DEVICE_FEL = 0, + BOOT_DEVICE_SPI = 1, + BOOT_DEVICE_MMC = 2, +}; + +static int get_boot_device(void) +{ + uint32_t * t = (void *)0x00000058; + + if(t[0] == 0x1) + return BOOT_DEVICE_FEL; + return BOOT_DEVICE_SPI; +} + +void sys_copyself(void) +{ + int d = get_boot_device(); + void * mem; + uint32_t size; + + if(d == BOOT_DEVICE_FEL) + { + sys_uart_putc('B'); + sys_uart_putc('o'); + sys_uart_putc('o'); + sys_uart_putc('t'); + sys_uart_putc(' '); + sys_uart_putc('t'); + sys_uart_putc('o'); + sys_uart_putc(' '); + sys_uart_putc('F'); + sys_uart_putc('E'); + sys_uart_putc('L'); + sys_uart_putc(' '); + sys_uart_putc('m'); + sys_uart_putc('o'); + sys_uart_putc('d'); + sys_uart_putc('e'); + sys_uart_putc('\r'); + sys_uart_putc('\n'); + return_to_fel(); + } + else if(d == BOOT_DEVICE_SPI) + { + sys_uart_putc('B'); + sys_uart_putc('o'); + sys_uart_putc('o'); + sys_uart_putc('t'); + sys_uart_putc(' '); + sys_uart_putc('t'); + sys_uart_putc('o'); + sys_uart_putc(' '); + sys_uart_putc('S'); + sys_uart_putc('P'); + sys_uart_putc('I'); + sys_uart_putc(' '); + sys_uart_putc('m'); + sys_uart_putc('o'); + sys_uart_putc('d'); + sys_uart_putc('e'); + sys_uart_putc('\r'); + sys_uart_putc('\n'); + mem = (void *)&__image_start; + size = &__image_end - &__image_start; + sys_mmu_init(); + + sys_spi_flash_init(); + sys_spi_flash_read(0, mem, size); + sys_spi_flash_exit(); + } + else if(d == BOOT_DEVICE_MMC) + { + mem = (void *)&__image_start; + size = (&__image_end - &__image_start + 512) >> 9; + } +} diff --git a/hw/mcu/allwinner/f1c100s/machine/sys-dram.c b/hw/mcu/allwinner/f1c100s/machine/sys-dram.c new file mode 100644 index 000000000..a819520a5 --- /dev/null +++ b/hw/mcu/allwinner/f1c100s/machine/sys-dram.c @@ -0,0 +1,506 @@ +/* + * sys-dram.c + * + * Copyright(c) 2007-2018 Jianjun Jiang <8192542@qq.com> + * Official site: http://xboot.org + * Mobile phone: +86-18665388956 + * QQ: 8192542 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include +#include +#include +#include + +#define PLL_DDR_CLK (156000000) +#define SDR_T_CAS (0x2) +#define SDR_T_RAS (0x8) +#define SDR_T_RCD (0x3) +#define SDR_T_RP (0x3) +#define SDR_T_WR (0x3) +#define SDR_T_RFC (0xd) +#define SDR_T_XSR (0xf9) +#define SDR_T_RC (0xb) +#define SDR_T_INIT (0x8) +#define SDR_T_INIT_REF (0x7) +#define SDR_T_WTR (0x2) +#define SDR_T_RRD (0x2) +#define SDR_T_XP (0x0) + +enum dram_type_t +{ + DRAM_TYPE_SDR = 0, + DRAM_TYPE_DDR = 1, + DRAM_TYPE_MDDR = 2, +}; + +struct dram_para_t +{ + uint32_t base; /* dram base address */ + uint32_t size; /* dram size (unit: MByte) */ + uint32_t clk; /* dram work clock (unit: MHz) */ + uint32_t access_mode; /* 0: interleave mode 1: sequence mode */ + uint32_t cs_num; /* dram chip count 1: one chip 2: two chip */ + uint32_t ddr8_remap; /* for 8bits data width DDR 0: normal 1: 8bits */ + enum dram_type_t sdr_ddr; + uint32_t bwidth; /* dram bus width */ + uint32_t col_width; /* column address width */ + uint32_t row_width; /* row address width */ + uint32_t bank_size; /* dram bank count */ + uint32_t cas; /* dram cas */ +}; + +static inline void sdelay(int loops) +{ + __asm__ __volatile__ ("1:\n" "subs %0, %1, #1\n" + "bne 1b":"=r" (loops):"0"(loops)); +} + +static void dram_delay(int ms) +{ + sdelay(ms * 2 * 1000); +} + +static int dram_initial(void) +{ + unsigned int time = 0xffffff; + + write32(F1C100S_DRAM_BASE + DRAM_SCTLR, read32(F1C100S_DRAM_BASE + DRAM_SCTLR) | 0x1); + while((read32(F1C100S_DRAM_BASE + DRAM_SCTLR) & 0x1) && time--) + { + if(time == 0) + return 0; + } + return 1; +} + +static int dram_delay_scan(void) +{ + unsigned int time = 0xffffff; + + write32(F1C100S_DRAM_BASE + DRAM_DDLYR, read32(F1C100S_DRAM_BASE + DRAM_DDLYR) | 0x1); + while((read32(F1C100S_DRAM_BASE + DRAM_DDLYR) & 0x1) && time--) + { + if(time == 0) + return 0; + } + return 1; +} + +static void dram_set_autofresh_cycle(uint32_t clk) +{ + uint32_t val = 0; + uint32_t row = 0; + uint32_t temp = 0; + + row = read32(F1C100S_DRAM_BASE + DRAM_SCONR); + row &= 0x1e0; + row >>= 0x5; + + if(row == 0xc) + { + if(clk >= 1000000) + { + temp = clk + (clk >> 3) + (clk >> 4) + (clk >> 5); + while(temp >= (10000000 >> 6)) + { + temp -= (10000000 >> 6); + val++; + } + } + else + { + val = (clk * 499) >> 6; + } + } + else if(row == 0xb) + { + if(clk >= 1000000) + { + temp = clk + (clk >> 3) + (clk >> 4) + (clk >> 5); + while(temp >= (10000000 >> 7)) + { + temp -= (10000000 >> 7); + val++; + } + } + else + { + val = (clk * 499) >> 5; + } + } + write32(F1C100S_DRAM_BASE + DRAM_SREFR, val); +} + +static int dram_para_setup(struct dram_para_t * para) +{ + uint32_t val = 0; + + val = (para->ddr8_remap) | + (0x1 << 1) | + ((para->bank_size >> 2) << 3) | + ((para->cs_num >> 1) << 4) | + ((para->row_width - 1) << 5) | + ((para->col_width - 1) << 9) | + ((para->sdr_ddr ? (para->bwidth >> 4) : (para->bwidth >> 5)) << 13) | + (para->access_mode << 15) | + (para->sdr_ddr << 16); + + write32(F1C100S_DRAM_BASE + DRAM_SCONR, val); + write32(F1C100S_DRAM_BASE + DRAM_SCTLR, read32(F1C100S_DRAM_BASE + DRAM_SCTLR) | (0x1 << 19)); + return dram_initial(); +} + +static uint32_t dram_check_delay(uint32_t bwidth) +{ + uint32_t dsize; + uint32_t i,j; + uint32_t num = 0; + uint32_t dflag = 0; + + dsize = ((bwidth == 16) ? 4 : 2); + for(i = 0; i < dsize; i++) + { + if(i == 0) + dflag = read32(F1C100S_DRAM_BASE + DRAM_DRPTR0); + else if(i == 1) + dflag = read32(F1C100S_DRAM_BASE + DRAM_DRPTR1); + else if(i == 2) + dflag = read32(F1C100S_DRAM_BASE + DRAM_DRPTR2); + else if(i == 3) + dflag = read32(F1C100S_DRAM_BASE + DRAM_DRPTR3); + + for(j = 0; j < 32; j++) + { + if(dflag & 0x1) + num++; + dflag >>= 1; + } + } + return num; +} + +static int sdr_readpipe_scan(void) +{ + uint32_t k = 0; + + for(k = 0; k < 32; k++) + { + write32(0x80000000 + 4 * k, k); + } + for(k = 0; k < 32; k++) + { + if(read32(0x80000000 + 4 * k) != k) + return 0; + } + return 1; +} + +static uint32_t sdr_readpipe_select(void) +{ + uint32_t value = 0; + uint32_t i = 0; + for(i = 0; i < 8; i++) + { + write32(F1C100S_DRAM_BASE + DRAM_SCTLR, (read32(F1C100S_DRAM_BASE + DRAM_SCTLR) & (~(0x7 << 6))) | (i << 6)); + if(sdr_readpipe_scan()) + { + value = i; + return value; + } + } + return value; +} + +static uint32_t dram_check_type(struct dram_para_t * para) +{ + uint32_t val = 0; + uint32_t times = 0; + uint32_t i; + + for(i = 0; i < 8; i++) + { + val = read32(F1C100S_DRAM_BASE + DRAM_SCTLR); + val &= ~(0x7 << 6); + val |= (i << 6); + write32(F1C100S_DRAM_BASE + DRAM_SCTLR, val); + + dram_delay_scan(); + if(read32(F1C100S_DRAM_BASE + DRAM_DDLYR) & 0x30) + times++; + } + + if(times == 8) + { + para->sdr_ddr = DRAM_TYPE_SDR; + return 0; + } + else + { + para->sdr_ddr = DRAM_TYPE_DDR; + return 1; + } +} + +static uint32_t dram_scan_readpipe(struct dram_para_t * para) +{ + uint32_t i, rp_best = 0, rp_val = 0; + uint32_t val = 0; + uint32_t readpipe[8]; + + if(para->sdr_ddr == DRAM_TYPE_DDR) + { + for(i = 0; i < 8; i++) + { + val = read32(F1C100S_DRAM_BASE + DRAM_SCTLR); + val &= ~(0x7 << 6); + val |= (i << 6); + write32(F1C100S_DRAM_BASE + DRAM_SCTLR, val); + dram_delay_scan(); + readpipe[i] = 0; + if((((read32(F1C100S_DRAM_BASE + DRAM_DDLYR) >> 4) & 0x3) == 0x0) && + (((read32(F1C100S_DRAM_BASE + DRAM_DDLYR) >> 4) & 0x1) == 0x0)) + { + readpipe[i] = dram_check_delay(para->bwidth); + } + if(rp_val < readpipe[i]) + { + rp_val = readpipe[i]; + rp_best = i; + } + } + val = read32(F1C100S_DRAM_BASE + DRAM_SCTLR); + val &= ~(0x7 << 6); + val |= (rp_best << 6); + write32(F1C100S_DRAM_BASE + DRAM_SCTLR, val); + dram_delay_scan(); + } + else + { + val = read32(F1C100S_DRAM_BASE + DRAM_SCONR); + val &= (~(0x1 << 16)); + val &= (~(0x3 << 13)); + write32(F1C100S_DRAM_BASE + DRAM_SCONR, val); + rp_best = sdr_readpipe_select(); + val = read32(F1C100S_DRAM_BASE + DRAM_SCTLR); + val &= ~(0x7 << 6); + val |= (rp_best << 6); + write32(F1C100S_DRAM_BASE + DRAM_SCTLR, val); + } + return 0; +} + +static uint32_t dram_get_dram_size(struct dram_para_t * para) +{ + uint32_t colflag = 10, rowflag = 13; + uint32_t i = 0; + uint32_t val1 = 0; + uint32_t count = 0; + uint32_t addr1, addr2; + + para->col_width = colflag; + para->row_width = rowflag; + dram_para_setup(para); + dram_scan_readpipe(para); + for(i = 0; i < 32; i++) + { + *((uint32_t *)(0x80000200 + i)) = 0x11111111; + *((uint32_t *)(0x80000600 + i)) = 0x22222222; + } + for(i = 0; i < 32; i++) + { + val1 = *((uint32_t *)(0x80000200 + i)); + if(val1 == 0x22222222) + count++; + } + if(count == 32) + { + colflag = 9; + } + else + { + colflag = 10; + } + count = 0; + para->col_width = colflag; + para->row_width = rowflag; + dram_para_setup(para); + if(colflag == 10) + { + addr1 = 0x80400000; + addr2 = 0x80c00000; + } + else + { + addr1 = 0x80200000; + addr2 = 0x80600000; + } + for(i = 0; i < 32; i++) + { + *((uint32_t *)(addr1 + i)) = 0x33333333; + *((uint32_t *)(addr2 + i)) = 0x44444444; + } + for(i = 0; i < 32; i++) + { + val1 = *((uint32_t *)(addr1 + i)); + if(val1 == 0x44444444) + { + count++; + } + } + if(count == 32) + { + rowflag = 12; + } + else + { + rowflag = 13; + } + para->col_width = colflag; + para->row_width = rowflag; + if(para->row_width != 13) + { + para->size = 16; + } + else if(para->col_width == 10) + { + para->size = 64; + } + else + { + para->size = 32; + } + dram_set_autofresh_cycle(para->clk); + para->access_mode = 0; + dram_para_setup(para); + + return 0; +} + +static int dram_init(struct dram_para_t * para) +{ + uint32_t val = 0; + uint32_t i; + + write32(0x01c20800 + 0x24, read32(0x01c20800 + 0x24) | (0x7 << 12)); + dram_delay(5); + if(((para->cas) >> 3) & 0x1) + { + write32(0x01c20800 + 0x2c4, read32(0x01c20800 + 0x2c4) | (0x1 << 23) | (0x20 << 17)); + } + if((para->clk >= 144) && (para->clk <= 180)) + { + write32(0x01c20800 + 0x2c0, 0xaaa); + } + if(para->clk >= 180) + { + write32(0x01c20800 + 0x2c0, 0xfff); + } + if((para->clk) <= 96) + { + val = (0x1 << 0) | (0x0 << 4) | (((para->clk * 2) / 12 - 1) << 8) | (0x1u << 31); + } + else + { + val = (0x0 << 0) | (0x0 << 4) | (((para->clk * 2) / 24 - 1) << 8) | (0x1u << 31); + } + + if(para->cas & (0x1 << 4)) + { + write32(F1C100S_CCU_BASE + CCU_PLL_DDR0_PAT, 0xd1303333); + } + else if(para->cas & (0x1 << 5)) + { + write32(F1C100S_CCU_BASE + CCU_PLL_DDR0_PAT, 0xcce06666); + } + else if(para->cas & (0x1 << 6)) + { + write32(F1C100S_CCU_BASE + CCU_PLL_DDR0_PAT, 0xc8909999); + } + else if(para->cas & (0x1 << 7)) + { + write32(F1C100S_CCU_BASE + CCU_PLL_DDR0_PAT, 0xc440cccc); + } + if(para->cas & (0xf << 4)) + { + val |= 0x1 << 24; + } + write32(F1C100S_CCU_BASE + CCU_PLL_DDR_CTRL, val); + write32(F1C100S_CCU_BASE + CCU_PLL_DDR_CTRL, read32(F1C100S_CCU_BASE + CCU_PLL_DDR_CTRL) | (0x1 << 20)); + while((read32(F1C100S_CCU_BASE + CCU_PLL_DDR_CTRL) & (1 << 28)) == 0); + dram_delay(5); + write32(F1C100S_CCU_BASE + CCU_BUS_CLK_GATE0, read32(F1C100S_CCU_BASE + CCU_BUS_CLK_GATE0) | (0x1 << 14)); + write32(F1C100S_CCU_BASE + CCU_BUS_SOFT_RST0, read32(F1C100S_CCU_BASE + CCU_BUS_SOFT_RST0) & ~(0x1 << 14)); + for(i = 0; i < 10; i++) + continue; + write32(F1C100S_CCU_BASE + CCU_BUS_SOFT_RST0, read32(F1C100S_CCU_BASE + CCU_BUS_SOFT_RST0) | (0x1 << 14)); + + val = read32(0x01c20800 + 0x2c4); + (para->sdr_ddr == DRAM_TYPE_DDR) ? (val |= (0x1 << 16)) : (val &= ~(0x1 << 16)); + write32(0x01c20800 + 0x2c4, val); + + val = (SDR_T_CAS << 0) | (SDR_T_RAS << 3) | (SDR_T_RCD << 7) | (SDR_T_RP << 10) | (SDR_T_WR << 13) | (SDR_T_RFC << 15) | (SDR_T_XSR << 19) | (SDR_T_RC << 28); + write32(F1C100S_DRAM_BASE + DRAM_STMG0R, val); + val = (SDR_T_INIT << 0) | (SDR_T_INIT_REF << 16) | (SDR_T_WTR << 20) | (SDR_T_RRD << 22) | (SDR_T_XP << 25); + write32(F1C100S_DRAM_BASE + DRAM_STMG1R, val); + dram_para_setup(para); + dram_check_type(para); + + val = read32(0x01c20800 + 0x2c4); + (para->sdr_ddr == DRAM_TYPE_DDR) ? (val |= (0x1 << 16)) : (val &= ~(0x1 << 16)); + write32(0x01c20800 + 0x2c4, val); + + dram_set_autofresh_cycle(para->clk); + dram_scan_readpipe(para); + dram_get_dram_size(para); + + for(i = 0; i < 128; i++) + { + *((volatile uint32_t *)(para->base + 4 * i)) = para->base + 4 * i; + } + + for(i = 0; i < 128; i++) + { + if(*((volatile uint32_t *)(para->base + 4 * i)) != (para->base + 4 * i)) + return 0; + } + return 1; +} + +void sys_dram_init(void) +{ + struct dram_para_t para; + uint32_t * dsz = (void *)0x0000005c; + + para.base = 0x80000000; + para.size = 32; + para.clk = PLL_DDR_CLK / 1000000; + para.access_mode = 1; + para.cs_num = 1; + para.ddr8_remap = 0; + para.sdr_ddr = DRAM_TYPE_DDR; + para.bwidth = 16; + para.col_width = 10; + para.row_width = 13; + para.bank_size = 4; + para.cas = 0x3; + + if((dsz[0] >> 24) == 'X') + return; + if(dram_init(¶)) + dsz[0] = (((uint32_t)'X') << 24) | (para.size << 0); +} diff --git a/hw/mcu/allwinner/f1c100s/machine/sys-mmu.c b/hw/mcu/allwinner/f1c100s/machine/sys-mmu.c new file mode 100644 index 000000000..3c89c7255 --- /dev/null +++ b/hw/mcu/allwinner/f1c100s/machine/sys-mmu.c @@ -0,0 +1,57 @@ +/* + * sys-mmu.c + * + * Copyright(c) 2007-2018 Jianjun Jiang <8192542@qq.com> + * Official site: http://xboot.org + * Mobile phone: +86-18665388956 + * QQ: 8192542 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include + +static void map_l1_section(uint32_t * ttb, virtual_addr_t virt, physical_addr_t phys, physical_size_t size, int type) +{ + physical_size_t i; + + virt >>= 20; + phys >>= 20; + size >>= 20; + type &= 0x3; + + for(i = size; i > 0; i--, virt++, phys++) + ttb[virt] = (phys << 20) | (0x3 << 10) | (0x0 << 5) | (type << 2) | (0x2 << 0); +} + +void sys_mmu_init(void) +{ + uint32_t * ttb = (uint32_t *)(0x80000000 + SZ_1M * 31); + + map_l1_section(ttb, 0x00000000, 0x00000000, SZ_2G, 0); + map_l1_section(ttb, 0x80000000, 0x80000000, SZ_2G, 0); + map_l1_section(ttb, 0x80000000, 0x80000000, SZ_1M * 32, 3); + + arm32_ttb_set((uint32_t)(ttb)); + arm32_tlb_invalidate(); + arm32_domain_set(0x3); + arm32_mmu_enable(); + arm32_icache_enable(); + arm32_dcache_enable(); +} \ No newline at end of file diff --git a/hw/mcu/allwinner/f1c100s/machine/sys-spi-flash.c b/hw/mcu/allwinner/f1c100s/machine/sys-spi-flash.c new file mode 100644 index 000000000..5c3b0f0aa --- /dev/null +++ b/hw/mcu/allwinner/f1c100s/machine/sys-spi-flash.c @@ -0,0 +1,204 @@ +/* + * sys-spi-flash.c + * + * Copyright(c) 2007-2018 Jianjun Jiang <8192542@qq.com> + * Official site: http://xboot.org + * Mobile phone: +86-18665388956 + * QQ: 8192542 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include + +enum { + SPI_GCR = 0x04, + SPI_TCR = 0x08, + SPI_IER = 0x10, + SPI_ISR = 0x14, + SPI_FCR = 0x18, + SPI_FSR = 0x1c, + SPI_WCR = 0x20, + SPI_CCR = 0x24, + SPI_MBC = 0x30, + SPI_MTC = 0x34, + SPI_BCC = 0x38, + SPI_TXD = 0x200, + SPI_RXD = 0x300, +}; + +void sys_spi_flash_init(void) +{ + virtual_addr_t addr; + uint32_t val; + + /* Config GPIOC0, GPIOC1, GPIOC2 and GPIOC3 */ + addr = 0x01c20848 + 0x00; + val = read32(addr); + val &= ~(0xf << ((0 & 0x7) << 2)); + val |= ((0x2 & 0x7) << ((0 & 0x7) << 2)); + write32(addr, val); + + val = read32(addr); + val &= ~(0xf << ((1 & 0x7) << 2)); + val |= ((0x2 & 0x7) << ((1 & 0x7) << 2)); + write32(addr, val); + + val = read32(addr); + val &= ~(0xf << ((2 & 0x7) << 2)); + val |= ((0x2 & 0x7) << ((2 & 0x7) << 2)); + write32(addr, val); + + val = read32(addr); + val &= ~(0xf << ((3 & 0x7) << 2)); + val |= ((0x2 & 0x7) << ((3 & 0x7) << 2)); + write32(addr, val); + + /* Deassert spi0 reset */ + addr = 0x01c202c0; + val = read32(addr); + val |= (1 << 20); + write32(addr, val); + + /* Open the spi0 bus gate */ + addr = 0x01c20000 + 0x60; + val = read32(addr); + val |= (1 << 20); + write32(addr, val); + + /* Set spi clock rate control register, divided by 4 */ + addr = 0x01c05000; + write32(addr + SPI_CCR, 0x00001001); + + /* Enable spi0 and do a soft reset */ + addr = 0x01c05000; + val = read32(addr + SPI_GCR); + val |= (1 << 31) | (1 << 7) | (1 << 1) | (1 << 0); + write32(addr + SPI_GCR, val); + while(read32(addr + SPI_GCR) & (1 << 31)); + + val = read32(addr + SPI_TCR); + val &= ~(0x3 << 0); + val |= (1 << 6) | (1 << 2); + write32(addr + SPI_TCR, val); + + val = read32(addr + SPI_FCR); + val |= (1 << 31) | (1 << 15); + write32(addr + SPI_FCR, val); +} + +void sys_spi_flash_exit(void) +{ + virtual_addr_t addr = 0x01c05000; + uint32_t val; + + /* Disable the spi0 controller */ + val = read32(addr + SPI_GCR); + val &= ~((1 << 1) | (1 << 0)); + write32(addr + SPI_GCR, val); +} + +static void sys_spi_select(void) +{ + virtual_addr_t addr = 0x01c05000; + uint32_t val; + + val = read32(addr + SPI_TCR); + val &= ~((0x3 << 4) | (0x1 << 7)); + val |= ((0 & 0x3) << 4) | (0x0 << 7); + write32(addr + SPI_TCR, val); +} + +static void sys_spi_deselect(void) +{ + virtual_addr_t addr = 0x01c05000; + uint32_t val; + + val = read32(addr + SPI_TCR); + val &= ~((0x3 << 4) | (0x1 << 7)); + val |= ((0 & 0x3) << 4) | (0x1 << 7); + write32(addr + SPI_TCR, val); +} + +static void sys_spi_write_txbuf(uint8_t * buf, int len) +{ + virtual_addr_t addr = 0x01c05000; + int i; + + if(!buf) + len = 0; + + write32(addr + SPI_MTC, len & 0xffffff); + write32(addr + SPI_BCC, len & 0xffffff); + for(i = 0; i < len; ++i) + write8(addr + SPI_TXD, *buf++); +} + +static int sys_spi_transfer(void * txbuf, void * rxbuf, int len) +{ + virtual_addr_t addr = 0x01c05000; + int count = len; + uint8_t * tx = txbuf; + uint8_t * rx = rxbuf; + uint8_t val; + unsigned int n, i; + + while(count > 0) + { + n = (count <= 64) ? count : 64; + write32(addr + SPI_MBC, n); + sys_spi_write_txbuf(tx, n); + write32(addr + SPI_TCR, read32(addr + SPI_TCR) | (1 << 31)); + + while((read32(addr + SPI_FSR) & 0xff) < n); + for(i = 0; i < n; i++) + { + val = read8(addr + SPI_RXD); + if(rx) + *rx++ = val; + } + + if(tx) + tx += n; + count -= n; + } + return len; +} + +static int sys_spi_write_then_read(void * txbuf, int txlen, void * rxbuf, int rxlen) +{ + if(sys_spi_transfer(txbuf, NULL, txlen) != txlen) + return -1; + if(sys_spi_transfer(NULL, rxbuf, rxlen) != rxlen) + return -1; + return 0; +} + +void sys_spi_flash_read(int addr, void * buf, int count) +{ + uint8_t tx[4]; + + tx[0] = 0x03; + tx[1] = (uint8_t)(addr >> 16); + tx[2] = (uint8_t)(addr >> 8); + tx[3] = (uint8_t)(addr >> 0); + sys_spi_select(); + sys_spi_write_then_read(tx, 4, buf, count); + sys_spi_deselect(); +} diff --git a/hw/mcu/allwinner/f1c100s/machine/sys-uart.c b/hw/mcu/allwinner/f1c100s/machine/sys-uart.c new file mode 100644 index 000000000..0e61627b7 --- /dev/null +++ b/hw/mcu/allwinner/f1c100s/machine/sys-uart.c @@ -0,0 +1,83 @@ +/* + * sys-uart.c + * + * Copyright(c) 2007-2018 Jianjun Jiang <8192542@qq.com> + * Official site: http://xboot.org + * Mobile phone: +86-18665388956 + * QQ: 8192542 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include + +void sys_uart_init(void) +{ + virtual_addr_t addr; + uint32_t val; + + /* Config GPIOE1 and GPIOE0 to txd0 and rxd0 */ + addr = 0x01c20890 + 0x00; + val = read32(addr); + val &= ~(0xf << ((1 & 0x7) << 2)); + val |= ((0x5 & 0x7) << ((1 & 0x7) << 2)); + write32(addr, val); + + val = read32(addr); + val &= ~(0xf << ((0 & 0x7) << 2)); + val |= ((0x5 & 0x7) << ((0 & 0x7) << 2)); + write32(addr, val); + + /* Open the clock gate for uart0 */ + addr = 0x01c20068; + val = read32(addr); + val |= 1 << 20; + write32(addr, val); + + /* Deassert uart0 reset */ + addr = 0x01c202d0; + val = read32(addr); + val |= 1 << 20; + write32(addr, val); + + /* Config uart0 to 115200-8-1-0 */ + addr = 0x01c25000; + write32(addr + 0x04, 0x0); + write32(addr + 0x08, 0xf7); + write32(addr + 0x10, 0x0); + val = read32(addr + 0x0c); + val |= (1 << 7); + write32(addr + 0x0c, val); + write32(addr + 0x00, 0x36 & 0xff); + write32(addr + 0x04, (0x36 >> 8) & 0xff); + val = read32(addr + 0x0c); + val &= ~(1 << 7); + write32(addr + 0x0c, val); + val = read32(addr + 0x0c); + val &= ~0x1f; + val |= (0x3 << 0) | (0 << 2) | (0x0 << 3); + write32(addr + 0x0c, val); +} + +void sys_uart_putc(char c) +{ + virtual_addr_t addr = 0x01c25000; + + while((read32(addr + 0x7c) & (0x1 << 1)) == 0); + write32(addr + 0x00, c); +} diff --git a/src/portable/sunxi/dcd_sunxi_musb.c b/src/portable/sunxi/dcd_sunxi_musb.c index b13842de1..71d0b92b2 100644 --- a/src/portable/sunxi/dcd_sunxi_musb.c +++ b/src/portable/sunxi/dcd_sunxi_musb.c @@ -4,6 +4,7 @@ #include #include #include "musb_def.h" +#include "bsp/board.h" typedef uint32_t u32; typedef uint16_t u16; @@ -69,8 +70,8 @@ static void usb_phy_write(int addr, int data, int len) static void delay_ms(uint32_t ms) { #if CFG_TUSB_OS == OPT_OS_NONE - int cnt = ms * 1000 * 1000 / 2; - while (cnt--) asm("nop"); + int now = board_millis(); + while (board_millis() - now <= ms) asm("nop"); #else osal_task_delay(ms); #endif