summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYunhao Tian <[email protected]>2021-12-04 18:02:07 +0800
committerYunhao Tian <[email protected]>2021-12-04 18:02:07 +0800
commit68ca62dfd7e7fe757ba436fee7721520119da92b (patch)
tree62089abe09894d0824fa22837b2a86f1b1dfb0c5
parentdff54d854ddae3ff5c8dc81bac77fd8b50564598 (diff)
Add BSP support for F1C100s
-rw-r--r--examples/rules.mk5
-rw-r--r--hw/bsp/f1c100s/README.md17
-rw-r--r--hw/bsp/f1c100s/board.h1
-rw-r--r--hw/bsp/f1c100s/board.mk45
-rw-r--r--hw/bsp/f1c100s/f1c100s.c130
-rw-r--r--hw/mcu/allwinner/f1c100s/f1c100s.ld137
-rw-r--r--hw/mcu/allwinner/f1c100s/include/arm32.h150
-rw-r--r--hw/mcu/allwinner/f1c100s/include/f1c100s-gpio.h66
-rw-r--r--hw/mcu/allwinner/f1c100s/include/f1c100s-irq.h104
-rw-r--r--hw/mcu/allwinner/f1c100s/include/f1c100s-reset.h39
-rw-r--r--hw/mcu/allwinner/f1c100s/include/f1c100s-util.h139
-rw-r--r--hw/mcu/allwinner/f1c100s/include/f1c100s/reg-ccu.h55
-rw-r--r--hw/mcu/allwinner/f1c100s/include/f1c100s/reg-dram.h39
-rw-r--r--hw/mcu/allwinner/f1c100s/include/io.h57
-rw-r--r--hw/mcu/allwinner/f1c100s/include/irqflags.h104
-rw-r--r--hw/mcu/allwinner/f1c100s/include/malloc.h35
-rw-r--r--hw/mcu/allwinner/f1c100s/include/printf.h99
-rw-r--r--hw/mcu/allwinner/f1c100s/include/sizes.h42
-rw-r--r--hw/mcu/allwinner/f1c100s/include/types.h55
-rw-r--r--hw/mcu/allwinner/f1c100s/lib/malloc.c834
-rw-r--r--hw/mcu/allwinner/f1c100s/lib/memcpy.S404
-rw-r--r--hw/mcu/allwinner/f1c100s/lib/memset.S79
-rw-r--r--hw/mcu/allwinner/f1c100s/lib/printf.c757
-rw-r--r--hw/mcu/allwinner/f1c100s/machine/exception.c76
-rw-r--r--hw/mcu/allwinner/f1c100s/machine/f1c100s-intc.c173
-rw-r--r--hw/mcu/allwinner/f1c100s/machine/start.S313
-rw-r--r--hw/mcu/allwinner/f1c100s/machine/sys-clock.c124
-rw-r--r--hw/mcu/allwinner/f1c100s/machine/sys-copyself.c111
-rw-r--r--hw/mcu/allwinner/f1c100s/machine/sys-dram.c506
-rw-r--r--hw/mcu/allwinner/f1c100s/machine/sys-mmu.c57
-rw-r--r--hw/mcu/allwinner/f1c100s/machine/sys-spi-flash.c204
-rw-r--r--hw/mcu/allwinner/f1c100s/machine/sys-uart.c83
-rw-r--r--src/portable/sunxi/dcd_sunxi_musb.c5
33 files changed, 5043 insertions, 2 deletions
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 <stdint.h>
+#include <malloc.h>
+#include <irqflags.h>
+#include <f1c100s-irq.h>
+#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 <stdint.h>
+
+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 <stdint.h>
+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 <types.h>
+
+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 <types.h>
+
+#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 <types.h>
+#include <stddef.h>
+#include <string.h>
+#include <assert.h>
+
+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 ([email protected])
+// 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 <stdarg.h>
+#include <stddef.h>
+
+
+#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 <malloc.h>
+
+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 ([email protected])
+// 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 <stdint.h>
+#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 <stddef.h> 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 <[email protected]>
+ * 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 <stdio.h>
+#include <arm32.h>
+#include <string.h>
+
+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 <stdint.h>
+#include <stdio.h>
+#include <f1c100s-irq.h>
+#include <arm32.h>
+
+#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 <[email protected]>
+ * 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 <[email protected]>
+ * 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 <xboot.h>
+#include <stdint.h>
+#include <f1c100s/reg-ccu.h>
+#include <io.h>
+
+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 <[email protected]>
+ * 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 <stdint.h>
+
+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 <[email protected]>
+ * 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 <stdint.h>
+#include <f1c100s/reg-ccu.h>
+#include <f1c100s/reg-dram.h>
+#include <io.h>
+
+#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(&para))
+ 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 <[email protected]>
+ * 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 <stdint.h>
+#include <io.h>
+#include <sizes.h>
+#include <arm32.h>
+
+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 <[email protected]>
+ * 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 <stdint.h>
+#include <types.h>
+#include <string.h>
+#include <io.h>
+
+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 <[email protected]>
+ * 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 <types.h>
+#include <stdint.h>
+#include <io.h>
+
+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 <f1c100s-irq.h>
#include <device/dcd.h>
#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