Explorar o código

Add BSP support for F1C100s

Yunhao Tian %!s(int64=4) %!d(string=hai) anos
pai
achega
68ca62dfd7
Modificáronse 33 ficheiros con 5043 adicións e 2 borrados
  1. 5 0
      examples/rules.mk
  2. 17 0
      hw/bsp/f1c100s/README.md
  3. 1 0
      hw/bsp/f1c100s/board.h
  4. 45 0
      hw/bsp/f1c100s/board.mk
  5. 130 0
      hw/bsp/f1c100s/f1c100s.c
  6. 137 0
      hw/mcu/allwinner/f1c100s/f1c100s.ld
  7. 150 0
      hw/mcu/allwinner/f1c100s/include/arm32.h
  8. 66 0
      hw/mcu/allwinner/f1c100s/include/f1c100s-gpio.h
  9. 104 0
      hw/mcu/allwinner/f1c100s/include/f1c100s-irq.h
  10. 39 0
      hw/mcu/allwinner/f1c100s/include/f1c100s-reset.h
  11. 139 0
      hw/mcu/allwinner/f1c100s/include/f1c100s-util.h
  12. 55 0
      hw/mcu/allwinner/f1c100s/include/f1c100s/reg-ccu.h
  13. 39 0
      hw/mcu/allwinner/f1c100s/include/f1c100s/reg-dram.h
  14. 57 0
      hw/mcu/allwinner/f1c100s/include/io.h
  15. 104 0
      hw/mcu/allwinner/f1c100s/include/irqflags.h
  16. 35 0
      hw/mcu/allwinner/f1c100s/include/malloc.h
  17. 99 0
      hw/mcu/allwinner/f1c100s/include/printf.h
  18. 42 0
      hw/mcu/allwinner/f1c100s/include/sizes.h
  19. 55 0
      hw/mcu/allwinner/f1c100s/include/types.h
  20. 834 0
      hw/mcu/allwinner/f1c100s/lib/malloc.c
  21. 404 0
      hw/mcu/allwinner/f1c100s/lib/memcpy.S
  22. 79 0
      hw/mcu/allwinner/f1c100s/lib/memset.S
  23. 757 0
      hw/mcu/allwinner/f1c100s/lib/printf.c
  24. 76 0
      hw/mcu/allwinner/f1c100s/machine/exception.c
  25. 173 0
      hw/mcu/allwinner/f1c100s/machine/f1c100s-intc.c
  26. 313 0
      hw/mcu/allwinner/f1c100s/machine/start.S
  27. 124 0
      hw/mcu/allwinner/f1c100s/machine/sys-clock.c
  28. 111 0
      hw/mcu/allwinner/f1c100s/machine/sys-copyself.c
  29. 506 0
      hw/mcu/allwinner/f1c100s/machine/sys-dram.c
  30. 57 0
      hw/mcu/allwinner/f1c100s/machine/sys-mmu.c
  31. 204 0
      hw/mcu/allwinner/f1c100s/machine/sys-spi-flash.c
  32. 83 0
      hw/mcu/allwinner/f1c100s/machine/sys-uart.c
  33. 3 2
      src/portable/sunxi/dcd_sunxi_musb.c

+ 5 - 0
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

+ 17 - 0
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?)

+ 1 - 0
hw/bsp/f1c100s/board.h

@@ -0,0 +1 @@
+// Nothing valuable here

+ 45 - 0
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

+ 130 - 0
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

+ 137 - 0
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) }
+}

+ 150 - 0
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__ */

+ 66 - 0
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__ */

+ 104 - 0
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__ */

+ 39 - 0
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__ */

+ 139 - 0
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__ */
+

+ 55 - 0
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__ */

+ 39 - 0
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__ */

+ 57 - 0
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__ */

+ 104 - 0
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__ */

+ 35 - 0
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__ */

+ 99 - 0
hw/mcu/allwinner/f1c100s/include/printf.h

@@ -0,0 +1,99 @@
+///////////////////////////////////////////////////////////////////////////////
+// \author (c) Marco Paland (info@paland.com)
+//             2014-2018, PALANDesign Hannover, Germany
+//
+// \license The MIT License (MIT)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+// \brief Tiny printf, sprintf and snprintf implementation, optimized for speed on
+//        embedded systems with a very limited resources.
+//        Use this instead of bloated standard/newlib printf.
+//        These routines are thread safe and reentrant!
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef _PRINTF_H_
+#define _PRINTF_H_
+
+#include <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_

+ 42 - 0
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__ */

+ 55 - 0
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__ */

+ 834 - 0
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
+}

+ 404 - 0
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

+ 79 - 0
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 */

+ 757 - 0
hw/mcu/allwinner/f1c100s/lib/printf.c

@@ -0,0 +1,757 @@
+
+///////////////////////////////////////////////////////////////////////////////
+// \author (c) Marco Paland (info@paland.com)
+//             2014-2018, PALANDesign Hannover, Germany
+//
+// \license The MIT License (MIT)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+// \brief Tiny printf, sprintf and (v)snprintf implementation, optimized for speed on
+//        embedded systems with a very limited resources. These routines are thread
+//        safe and reentrant!
+//        Use this instead of the bloated standard/newlib printf cause these use
+//        malloc for printf (and may not be thread safe).
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include <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;
+}

+ 76 - 0
hw/mcu/allwinner/f1c100s/machine/exception.c

@@ -0,0 +1,76 @@
+/*
+ * exception.c
+ *
+ * Copyright(c) 2007-2018 Jianjun Jiang <8192542@qq.com>
+ * Official site: http://xboot.org
+ * Mobile phone: +86-18665388956
+ * QQ: 8192542
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include <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

+ 173 - 0
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;
+  }
+}

+ 313 - 0
hw/mcu/allwinner/f1c100s/machine/start.S

@@ -0,0 +1,313 @@
+/*
+ * start.S
+ *
+ * Copyright(c) 2007-2018 Jianjun Jiang <8192542@qq.com>
+ * Official site: http://xboot.org
+ * Mobile phone: +86-18665388956
+ * QQ: 8192542
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+ * Exception vector table
+ */
+.text
+	.arm
+
+	.global	_start
+_start:
+	/* Boot head information for BROM */
+	.long 0xea000016
+	.byte 'e', 'G', 'O', 'N', '.', 'B', 'T', '0'
+	.long 0, __bootloader_size
+	.byte 'S', 'P', 'L', 2
+	.long 0, 0
+	.long 0, 0, 0, 0, 0, 0, 0, 0
+	.long 0, 0, 0, 0, 0, 0, 0, 0	/* 0x40 - boot params, 0x58 - fel boot type, 0x5c - dram size */
+
+_vector:
+	b reset
+	ldr pc, _undefined_instruction
+	ldr pc, _software_interrupt
+	ldr pc, _prefetch_abort
+	ldr pc, _data_abort
+	ldr pc, _not_used
+	ldr pc, _irq
+	ldr pc, _fiq
+
+_undefined_instruction:
+	.word undefined_instruction
+_software_interrupt:
+	.word software_interrupt
+_prefetch_abort:
+	.word prefetch_abort
+_data_abort:
+	.word data_abort
+_not_used:
+	.word not_used
+_irq:
+	.word irq
+_fiq:
+	.word fiq
+
+/*
+ * The actual reset code
+ */
+reset:
+	/* Save boot params to 0x00000040 */
+	ldr r0, =0x00000040
+	str sp, [r0, #0]
+	str lr, [r0, #4]
+	mrs lr, cpsr
+	str lr, [r0, #8]
+	mrc p15, 0, lr, c1, c0, 0
+	str lr, [r0, #12]
+	mrc p15, 0, lr, c1, c0, 0
+	str lr, [r0, #16]
+
+	/* Check boot type just for fel */
+	mov r0, #0x0
+	ldr r1, [r0, #8]
+	ldr r2, =0x4c45462e
+	cmp r1, r2
+	bne 1f
+	ldr r1, =0x1
+	str r1, [r0, #0x58]
+1:	nop
+
+	/* Enter svc mode and mask interrupts */
+	mrs r0, cpsr
+	bic r0, r0, #0x1f
+	orr r0, r0, #0xd3
+	msr cpsr, r0
+
+	/* Set vector to the low address */
+	mrc p15, 0, r0, c1, c0, 0
+	bic r0, #(1<<13)
+	mcr p15, 0, r0, c1, c0, 0
+
+	/* Copy vector to the correct address */
+	adr r0, _vector
+	mrc p15, 0, r2, c1, c0, 0
+	ands r2, r2, #(1 << 13)
+	ldreq r1, =0x00000000
+	ldrne r1, =0xffff0000
+	ldmia r0!, {r2-r8, r10}
+	stmia r1!, {r2-r8, r10}
+	ldmia r0!, {r2-r8, r10}
+	stmia r1!, {r2-r8, r10}
+
+	/* Initial system clock, ddr add uart */
+	bl sys_clock_init
+	bl sys_dram_init
+	bl sys_uart_init
+
+	/* Boot speed up, leave slower sram */
+	adr r0, _start
+	ldr r1, =_start
+	cmp r0, r1
+	beq _speedup
+	ldr r0, =0x81f80000
+	adr r1, _start
+	mov r2, #0x4000
+	bl memcpy
+	ldr r0, =_speedup
+	ldr r1, =_start
+	sub r0, r0, r1
+	ldr r1, =0x81f80000
+	add r0, r0, r1
+	mov pc, r0
+_speedup:
+	nop
+
+	/* Copyself to link address */
+	adr r0, _start
+	ldr r1, =_start
+	cmp r0, r1
+	beq 1f
+	bl sys_copyself
+1:	nop
+
+	/* Initialize stacks */
+	mrs r0, cpsr
+	bic r0, r0, #0x1f
+	orr r1, r0, #0x1b
+	msr cpsr_cxsf, r1
+	ldr sp, _stack_und_end
+
+	bic r0, r0, #0x1f
+	orr r1, r0, #0x17
+	msr cpsr_cxsf, r1
+	ldr sp, _stack_abt_end
+
+	bic r0, r0, #0x1f
+	orr r1, r0, #0x12
+	msr cpsr_cxsf, r1
+	ldr sp, _stack_irq_end
+
+	bic r0, r0, #0x1f
+	orr r1, r0, #0x11
+	msr cpsr_cxsf, r1
+	ldr sp, _stack_fiq_end
+
+	bic r0, r0, #0x1f
+	orr r1, r0, #0x13
+	msr cpsr_cxsf, r1
+	ldr sp, _stack_srv_end
+
+	/* Copy data section */
+	ldr r0, _data_start
+	ldr r1, _data_shadow_start
+	ldr r2, _data_shadow_end
+	sub r2, r2, r1
+	bl memcpy
+
+	/* Clear bss section */
+	ldr r0, _bss_start
+	ldr r2, _bss_end
+	sub r2, r2, r0
+	mov r1, #0
+	bl memset
+
+	/* Call _main */
+	ldr r1, =_main
+	mov pc, r1
+_main:
+	bl main
+	b _main
+
+	.global return_to_fel
+return_to_fel:
+	mov r0, #0x4
+	mov r1, #'e'
+	strb r1, [r0, #0]
+	mov r1, #'G'
+	strb r1, [r0, #1]
+	mov r1, #'O'
+	strb r1, [r0, #2]
+	mov r1, #'N'
+	strb r1, [r0, #3]
+	mov r1, #'.'
+	strb r1, [r0, #4]
+	mov r1, #'F'
+	strb r1, [r0, #5]
+	mov r1, #'E'
+	strb r1, [r0, #6]
+	mov r1, #'L'
+	strb r1, [r0, #7]
+	ldr r0, =0x00000040
+	ldr sp, [r0, #0]
+	ldr lr, [r0, #4]
+	ldr r1, [r0, #16]
+	mcr p15, 0, r1, c1, c0, 0
+	ldr r1, [r0, #12]
+	mcr p15, 0, r1, c1, c0, 0
+	ldr r1, [r0, #8]
+	msr cpsr, r1
+	bx lr
+
+/*
+ * Exception handlers
+ */
+	.align 5
+undefined_instruction:
+	b .
+
+	.align 5
+software_interrupt:
+	b .
+
+	.align 5
+prefetch_abort:
+	b .
+
+	.align 5
+data_abort:
+	b .
+
+	.align 5
+not_used:
+	b .
+
+	.align 5
+irq:
+	ldr sp, _stack_irq_end
+	sub sp, sp, #72
+	stmia sp, {r0 - r12}
+	add r8, sp, #60
+	stmdb r8, {sp, lr}^
+	str lr, [r8, #0]
+	mrs r6, spsr
+	str r6, [r8, #4]
+	str r0, [r8, #8]
+	mov r0, sp
+	bl arm32_do_irq
+	ldmia sp, {r0 - lr}^
+	mov r0, r0
+	ldr lr, [sp, #60]
+	add sp, sp, #72
+	subs pc, lr, #4
+
+	.align 5
+fiq:
+	ldr sp, _stack_irq_end
+	sub sp, sp, #72
+	stmia sp, {r0 - r12}
+	add r8, sp, #60
+	stmdb r8, {sp, lr}^
+	str lr, [r8, #0]
+	mrs r6, spsr
+	str r6, [r8, #4]
+	str r0, [r8, #8]
+	mov r0, sp
+	bl arm32_do_fiq
+	ldmia sp, {r0 - lr}^
+	mov r0, r0
+	ldr lr, [sp, #60]
+	add sp, sp, #72
+	subs pc, lr, #4
+
+/*
+ * The location of section
+ */
+ 	.align 4
+_image_start:
+	.long __image_start
+_image_end:
+	.long __image_end
+_data_shadow_start:
+	.long __data_shadow_start
+_data_shadow_end:
+	.long __data_shadow_end
+_data_start:
+	.long __data_start
+_data_end:
+	.long __data_end
+_bss_start:
+	.long __bss_start
+_bss_end:
+	.long __bss_end
+_stack_und_end:
+	.long __stack_und_end
+_stack_abt_end:
+	.long __stack_abt_end
+_stack_irq_end:
+	.long __stack_irq_end
+_stack_fiq_end:
+	.long __stack_fiq_end
+_stack_srv_end:
+	.long __stack_srv_end

+ 124 - 0
hw/mcu/allwinner/f1c100s/machine/sys-clock.c

@@ -0,0 +1,124 @@
+/*
+ * sys-clock.c
+ *
+ * Copyright(c) 2007-2018 Jianjun Jiang <8192542@qq.com>
+ * Official site: http://xboot.org
+ * Mobile phone: +86-18665388956
+ * QQ: 8192542
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+//#include <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);
+}

+ 111 - 0
hw/mcu/allwinner/f1c100s/machine/sys-copyself.c

@@ -0,0 +1,111 @@
+/*
+ * sys-copyself.c
+ *
+ * Copyright(c) 2007-2018 Jianjun Jiang <8192542@qq.com>
+ * Official site: http://xboot.org
+ * Mobile phone: +86-18665388956
+ * QQ: 8192542
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include <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;
+	}
+}

+ 506 - 0
hw/mcu/allwinner/f1c100s/machine/sys-dram.c

@@ -0,0 +1,506 @@
+/*
+ * sys-dram.c
+ *
+ * Copyright(c) 2007-2018 Jianjun Jiang <8192542@qq.com>
+ * Official site: http://xboot.org
+ * Mobile phone: +86-18665388956
+ * QQ: 8192542
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include <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);
+}

+ 57 - 0
hw/mcu/allwinner/f1c100s/machine/sys-mmu.c

@@ -0,0 +1,57 @@
+/*
+ * sys-mmu.c
+ *
+ * Copyright(c) 2007-2018 Jianjun Jiang <8192542@qq.com>
+ * Official site: http://xboot.org
+ * Mobile phone: +86-18665388956
+ * QQ: 8192542
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <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();
+}

+ 204 - 0
hw/mcu/allwinner/f1c100s/machine/sys-spi-flash.c

@@ -0,0 +1,204 @@
+/*
+ * sys-spi-flash.c
+ *
+ * Copyright(c) 2007-2018 Jianjun Jiang <8192542@qq.com>
+ * Official site: http://xboot.org
+ * Mobile phone: +86-18665388956
+ * QQ: 8192542
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <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();
+}

+ 83 - 0
hw/mcu/allwinner/f1c100s/machine/sys-uart.c

@@ -0,0 +1,83 @@
+/*
+ * sys-uart.c
+ *
+ * Copyright(c) 2007-2018 Jianjun Jiang <8192542@qq.com>
+ * Official site: http://xboot.org
+ * Mobile phone: +86-18665388956
+ * QQ: 8192542
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <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);
+}

+ 3 - 2
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