summaryrefslogtreecommitdiff
path: root/src/cpu/allwinner/a10
diff options
context:
space:
mode:
authorAlexandru Gagniuc <mr.nuke.me@gmail.com>2013-12-13 20:44:48 -0600
committerAlexandru Gagniuc <mr.nuke.me@gmail.com>2014-01-08 22:54:08 +0100
commitf64111b4865d611821950b25dc1ea235d8d9ca79 (patch)
treed61eef4c9476ada907f0d91e93c2707aed44df96 /src/cpu/allwinner/a10
parent34286b861a9427520f3f3afb8bf64bfa7de37c24 (diff)
downloadcoreboot-f64111b4865d611821950b25dc1ea235d8d9ca79.tar.xz
cpu: Add initial support for Allwinner A10 SoC
Add minimal support needed to get a bootblock capable of initialising a serial console. Change-Id: I50dd85544549baf9c5ea0aa3b4296972136c02a4 Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com> Reviewed-on: http://review.coreboot.org/4549 Tested-by: build bot (Jenkins) Reviewed-by: David Hendricks <dhendrix@chromium.org> Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Diffstat (limited to 'src/cpu/allwinner/a10')
-rw-r--r--src/cpu/allwinner/a10/Kconfig115
-rw-r--r--src/cpu/allwinner/a10/Makefile.inc35
-rw-r--r--src/cpu/allwinner/a10/bootblock.c21
-rw-r--r--src/cpu/allwinner/a10/bootblock_media.c14
-rw-r--r--src/cpu/allwinner/a10/clock.h137
-rw-r--r--src/cpu/allwinner/a10/gpio.h51
-rw-r--r--src/cpu/allwinner/a10/memmap.h117
-rw-r--r--src/cpu/allwinner/a10/monotonic_timer.c13
-rw-r--r--src/cpu/allwinner/a10/pinmux.c30
-rw-r--r--src/cpu/allwinner/a10/timer.c19
-rw-r--r--src/cpu/allwinner/a10/uart.c98
-rw-r--r--src/cpu/allwinner/a10/uart.h77
-rw-r--r--src/cpu/allwinner/a10/uart_console.c109
13 files changed, 836 insertions, 0 deletions
diff --git a/src/cpu/allwinner/a10/Kconfig b/src/cpu/allwinner/a10/Kconfig
new file mode 100644
index 0000000000..639108a5ba
--- /dev/null
+++ b/src/cpu/allwinner/a10/Kconfig
@@ -0,0 +1,115 @@
+config CPU_ALLWINNER_A10
+ bool
+ default n
+
+if CPU_ALLWINNER_A10
+
+config CPU_SPECIFIC_OPTIONS
+ def_bool y
+ select HAVE_MONOTONIC_TIMER
+ select HAVE_UART_SPECIAL
+ select HAVE_UART_MEMORY_MAPPED
+ select BOOTBLOCK_CONSOLE
+ select EARLY_CONSOLE
+
+config BOOTBLOCK_CPU_INIT
+ string
+ default "cpu/allwinner/a10/bootblock.c"
+ help
+ CPU/SoC-specific bootblock code. This is useful if the
+ bootblock must load microcode or copy data from ROM before
+ searching for the bootblock.
+
+# The "eGON.BT0" header takes 32 bytes
+config BOOTBLOCK_BASE
+ hex
+ default 0x20
+
+config BOOTBLOCK_ROM_OFFSET
+ hex
+ default 0x00
+
+config CBFS_HEADER_ROM_OFFSET
+ hex
+ default 0x10
+
+config CBFS_ROM_OFFSET
+ # Calculated by BL1 + max bootblock size.
+ default 0x4c00
+
+# FIXME: untested
+config ROMSTAGE_BASE
+ hex
+ default SYS_SDRAM_BASE
+
+# Keep the stack in SRAM
+config STACK_TOP
+ hex
+ default 0x00008000
+
+config STACK_BOTTOM
+ hex
+ default 0x00004000
+
+config STACK_SIZE
+ hex
+ default 0x00004000
+
+## TODO Change this to some better address not overlapping bootblock when
+## cbfstool supports creating header in arbitrary location.
+config CBFS_HEADER_ROM_OFFSET
+ hex "offset of master CBFS header in ROM"
+ default 0x40
+
+config SYS_SDRAM_BASE
+ hex
+ default 0x40000000
+
+choice CONSOLE_SERIAL_UART_CHOICES
+ prompt "Serial Console UART"
+ default CONSOLE_SERIAL_UART0
+ depends on CONSOLE_SERIAL_UART
+
+config CONSOLE_SERIAL_UART0
+ bool "UART0"
+ help
+ Serial console on UART0
+
+config CONSOLE_SERIAL_UART1
+ bool "UART1"
+ help
+ Serial console on UART1
+
+config CONSOLE_SERIAL_UART2
+ bool "UART2"
+ help
+ Serial console on UART2
+
+config CONSOLE_SERIAL_UART3
+ bool "UART3"
+ help
+ Serial console on UART3
+
+config CONSOLE_SERIAL_UART4
+ bool "UART4"
+ help
+ Serial console on UART4
+
+config CONSOLE_SERIAL_UART5
+ bool "UART5"
+ help
+ Serial console on UART5
+
+config CONSOLE_SERIAL_UART6
+ bool "UART6"
+ help
+ Serial console on UART6
+
+config CONSOLE_SERIAL_UART7
+ bool "UART7"
+ help
+ Serial console on UART7
+
+endchoice
+
+endif # if CPU_ALLWINNER_A10
diff --git a/src/cpu/allwinner/a10/Makefile.inc b/src/cpu/allwinner/a10/Makefile.inc
new file mode 100644
index 0000000000..48f3110605
--- /dev/null
+++ b/src/cpu/allwinner/a10/Makefile.inc
@@ -0,0 +1,35 @@
+bootblock-y += pinmux.c
+bootblock-y += bootblock_media.c
+bootblock-$(CONFIG_BOOTBLOCK_CONSOLE) += uart.c
+bootblock-$(CONFIG_BOOTBLOCK_CONSOLE) += uart_console.c
+
+romstage-y += uart.c
+romstage-y += uart_console.c
+romstage-y += bootblock_media.c
+
+ramstage-y += uart.c
+ramstage-y += uart_console.c
+ramstage-y += timer.c
+ramstage-y += monotonic_timer.c
+ramstage-y += bootblock_media.c
+
+
+real-target: $(obj)/BOOT0
+
+get_bootblock_size= \
+ $(eval bb_s=$(shell $(CBFSTOOL) $(1) print | grep bootblocksize | \
+ sed 's/[^0-9 ]//g')) \
+ $(shell echo $$(($(word 2, $(strip $(bb_s))))))
+
+# The boot ROM in the SoC will start loading code if a special boot0 header is
+# found (at an offset of 8KiB in either NAND or SD), and the checksum is
+# correct. this header is normally added by the 'mxsunxiboot' tool. The file
+# passed to mksunxiboot should only include the bootblock due to size
+# limitations.
+# FIXME: Figure out how to safely integrate in coreboot.rom. For now, only copy
+# the first 15 KiB of coreboot.rom (This will not collide with stack)
+$(obj)/BOOT0: $(obj)/coreboot.rom
+ @printf " BOOT0 $(subst $(obj)/,,$(^))\n"
+ touch $@
+ dd if=$^ of=$^.tmp bs=1024 count=15
+ -mksunxiboot $^.tmp $@
diff --git a/src/cpu/allwinner/a10/bootblock.c b/src/cpu/allwinner/a10/bootblock.c
new file mode 100644
index 0000000000..38fe95308f
--- /dev/null
+++ b/src/cpu/allwinner/a10/bootblock.c
@@ -0,0 +1,21 @@
+/*
+ * Allwinner A10 bootblock initialization
+ *
+ * Copyright (C) 2013 Google Inc.
+ * Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
+ * Subject to the GNU GPL v2, or (at your option) any later version.
+ */
+
+#include <types.h>
+#include <arch/cache.h>
+
+void bootblock_cpu_init(void);
+void bootblock_cpu_init(void)
+{
+ uint32_t sctlr;
+
+ /* enable dcache */
+ sctlr = read_sctlr();
+ sctlr |= SCTLR_C;
+ write_sctlr(sctlr);
+}
diff --git a/src/cpu/allwinner/a10/bootblock_media.c b/src/cpu/allwinner/a10/bootblock_media.c
new file mode 100644
index 0000000000..a5863b6faf
--- /dev/null
+++ b/src/cpu/allwinner/a10/bootblock_media.c
@@ -0,0 +1,14 @@
+/*
+ * CBFS accessors for bootblock stage.
+ *
+ * Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
+ * Subject to the GNU GPL v2, or (at your option) any later version.
+ */
+#include <cbfs.h>
+#include <console/console.h>
+
+int init_default_cbfs_media(struct cbfs_media *media)
+{
+ printk(BIOS_ERR, "Oh my! I don't know how to access CBFS yet.");
+ return 0;
+}
diff --git a/src/cpu/allwinner/a10/clock.h b/src/cpu/allwinner/a10/clock.h
new file mode 100644
index 0000000000..e028d131c9
--- /dev/null
+++ b/src/cpu/allwinner/a10/clock.h
@@ -0,0 +1,137 @@
+/*
+ * Definitions for clock control and gating on Allwinner CPUs
+ *
+ * Copyright (C) 2007-2011 Allwinner Technology Co., Ltd.
+ * Tom Cubie <tangliang@allwinnertech.com>
+ * Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
+ * Subject to the GNU GPL v2, or (at your option) any later version.
+ */
+
+#ifndef CPU_ALLWINNER_A10_CLOCK_H
+#define CPU_ALLWINNER_A10_CLOCK_H
+
+#include "memmap.h"
+#include <types.h>
+
+/* CPU_AHB_APB0 config values */
+#define CPU_CLK_SRC_MASK (3 << 16)
+#define CPU_CLK_SRC_OSC24M (1 << 16)
+#define CPU_CLK_SRC_PLL1 (2 << 16)
+#define APB0_DIV_MASK (3 << 8)
+#define APB0_DIV_1 (0 << 8)
+#define APB0_DIV_2 (1 << 8)
+#define APB0_DIV_4 (2 << 8)
+#define APB0_DIV_8 (3 << 8)
+#define AHB_DIV_MASK (3 << 4)
+#define AHB_DIV_1 (0 << 4)
+#define AHB_DIV_2 (1 << 4)
+#define AHB_DIV_4 (2 << 4)
+#define AHB_DIV_8 (3 << 4)
+#define AXI_DIV_MASK (3 << 0)
+#define AXI_DIV_1 (0 << 0)
+#define AXI_DIV_2 (1 << 0)
+#define AXI_DIV_3 (2 << 0)
+#define AXI_DIV_4 (3 << 0)
+
+/* APB1_CLK_DIV values */
+#define APB1_CLK_SRC_MASK (3 << 24)
+#define APB1_CLK_SRC_OSC24M (0 << 24)
+#define APB1_CLK_SRC_PLL6 (1 << 24)
+#define APB1_CLK_SRC_32K (2 << 24)
+#define APB1_RAT_N_MASK (3 << 16)
+#define APB1_RAT_N(m) (((m) & 0x3) << 16)
+#define APB1_RAT_M_MASK 0x1f << 0)
+#define APB1_RAT_M(n) (((n) & 0x1f) << 0)
+
+/* APB0_GATING values */
+#define APB0_GATE_KEYPAD (1 << 10)
+#define APB0_GATE_IR(x) (((1 << (x)) & 0x3) << 6)
+#define APB0_GATE_PIO (1 << 5)
+#define APB0_GATE_IIS (1 << 3)
+#define APB0_GATE_AC97 (1 << 2)
+#define APB0_GATE_CODEC (1 << 0)
+
+/* APB1_GATING values */
+#define APB1_GATE_UART(x) (((1 << (x)) & 0xff) << 16)
+#define APB1_GATE_PS2(x) (((1 << (x)) & 0x3) << 6)
+#define APB1_GATE_CAN (1 << 4)
+#define APB1_GATE_TWI(x) (((1 << (x)) & 0x7) << 0)
+
+struct a10_ccm {
+ u32 pll1_cfg; /* 0x00 pll1 control */
+ u32 pll1_tun; /* 0x04 pll1 tuning */
+ u32 pll2_cfg; /* 0x08 pll2 control */
+ u32 pll2_tun; /* 0x0c pll2 tuning */
+ u32 pll3_cfg; /* 0x10 pll3 control */
+ u8 res0[0x4];
+ u32 pll4_cfg; /* 0x18 pll4 control */
+ u8 res1[0x4];
+ u32 pll5_cfg; /* 0x20 pll5 control */
+ u32 pll5_tun; /* 0x24 pll5 tuning */
+ u32 pll6_cfg; /* 0x28 pll6 control */
+ u32 pll6_tun; /* 0x2c pll6 tuning */
+ u32 pll7_cfg; /* 0x30 pll7 control */
+ u32 pll1_tun2; /* 0x34 pll5 tuning2 */
+ u8 res2[0x4];
+ u32 pll5_tun2; /* 0x3c pll5 tuning2 */
+ u8 res3[0xc];
+ u32 pll_lock_dbg; /* 0x4c pll lock time debug */
+ u32 osc24m_cfg; /* 0x50 osc24m control */
+ u32 cpu_ahb_apb0_cfg; /* 0x54 cpu,ahb and apb0 divide ratio */
+ u32 apb1_clk_div_cfg; /* 0x58 apb1 clock dividor */
+ u32 axi_gate; /* 0x5c axi module clock gating */
+ u32 ahb_gate0; /* 0x60 ahb module clock gating 0 */
+ u32 ahb_gate1; /* 0x64 ahb module clock gating 1 */
+ u32 apb0_gate; /* 0x68 apb0 module clock gating */
+ u32 apb1_gate; /* 0x6c apb1 module clock gating */
+ u8 res4[0x10];
+ u32 nand_sclk_cfg; /* 0x80 nand sub clock control */
+ u32 ms_sclk_cfg; /* 0x84 memory stick sub clock control */
+ u32 sd0_clk_cfg; /* 0x88 sd0 clock control */
+ u32 sd1_clk_cfg; /* 0x8c sd1 clock control */
+ u32 sd2_clk_cfg; /* 0x90 sd2 clock control */
+ u32 sd3_clk_cfg; /* 0x94 sd3 clock control */
+ u32 ts_clk_cfg; /* 0x98 transport stream clock control */
+ u32 ss_clk_cfg; /* 0x9c */
+ u32 spi0_clk_cfg; /* 0xa0 */
+ u32 spi1_clk_cfg; /* 0xa4 */
+ u32 spi2_clk_cfg; /* 0xa8 */
+ u32 pata_clk_cfg; /* 0xac */
+ u32 ir0_clk_cfg; /* 0xb0 */
+ u32 ir1_clk_cfg; /* 0xb4 */
+ u32 iis_clk_cfg; /* 0xb8 */
+ u32 ac97_clk_cfg; /* 0xbc */
+ u32 spdif_clk_cfg; /* 0xc0 */
+ u32 keypad_clk_cfg; /* 0xc4 */
+ u32 sata_clk_cfg; /* 0xc8 */
+ u32 usb_clk_cfg; /* 0xcc */
+ u32 gps_clk_cfg; /* 0xd0 */
+ u32 spi3_clk_cfg; /* 0xd4 */
+ u8 res5[0x28];
+ u32 dram_clk_cfg; /* 0x100 */
+ u32 be0_clk_cfg; /* 0x104 */
+ u32 be1_clk_cfg; /* 0x108 */
+ u32 fe0_clk_cfg; /* 0x10c */
+ u32 fe1_clk_cfg; /* 0x110 */
+ u32 mp_clk_cfg; /* 0x114 */
+ u32 lcd0_ch0_clk_cfg; /* 0x118 */
+ u32 lcd1_ch0_clk_cfg; /* 0x11c */
+ u32 csi_isp_clk_cfg; /* 0x120 */
+ u8 res6[0x4];
+ u32 tvd_clk_reg; /* 0x128 */
+ u32 lcd0_ch1_clk_cfg; /* 0x12c */
+ u32 lcd1_ch1_clk_cfg; /* 0x130 */
+ u32 csi0_clk_cfg; /* 0x134 */
+ u32 csi1_clk_cfg; /* 0x138 */
+ u32 ve_clk_cfg; /* 0x13c */
+ u32 audio_codec_clk_cfg; /* 0x140 */
+ u32 avs_clk_cfg; /* 0x144 */
+ u32 ace_clk_cfg; /* 0x148 */
+ u32 lvds_clk_cfg; /* 0x14c */
+ u32 hdmi_clk_cfg; /* 0x150 */
+ u32 mali_clk_cfg; /* 0x154 */
+ u8 res7[0x4];
+ u32 mbus_clk_cfg; /* 0x15c */
+} __attribute__ ((packed));
+
+#endif /* CPU_ALLWINNER_A10_CLOCK_H */
diff --git a/src/cpu/allwinner/a10/gpio.h b/src/cpu/allwinner/a10/gpio.h
new file mode 100644
index 0000000000..f285451b17
--- /dev/null
+++ b/src/cpu/allwinner/a10/gpio.h
@@ -0,0 +1,51 @@
+/*
+ * Definitions for GPIO and pin multiplexing on Allwinner CPUs
+ *
+ * Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
+ * Subject to the GNU GPL v2, or (at your option) any later version.
+ */
+
+#ifndef __CPU_ALLWINNER_A10_PINMUX_H
+#define __CPU_ALLWINNER_A10_PINMUX_H
+
+#include <types.h>
+
+#define GPIO_BASE 0x01C20800
+
+#define GPA 0
+#define GPB 1
+#define GPC 2
+#define GPD 3
+#define GPE 4
+#define GPF 5
+#define GPG 6
+#define GPH 7
+#define GPI 8
+#define GPS 9
+
+struct a10_gpio_port {
+ u32 cfg[4];
+ u32 dat;
+ u32 drv[2];
+ u32 pul[2];
+} __attribute__ ((packed));
+
+struct a10_gpio {
+ struct a10_gpio_port port[10];
+ u8 reserved_0x168[0x98];
+
+ /* Offset 0x200 */
+ u32 int_cfg[4];
+
+ u32 int_ctl;
+ u32 int_sta;
+ u8 reserved_0x21C[4];
+ u32 int_deb;
+
+ u32 sdr_pad_drv;
+ u32 sdr_pad_pul;
+} __attribute__ ((packed));
+
+void gpio_set_func(u8 port, u8 pin, u8 pad_func);
+
+#endif /* __CPU_ALLWINNER_A10_PINMUX_H */
diff --git a/src/cpu/allwinner/a10/memmap.h b/src/cpu/allwinner/a10/memmap.h
new file mode 100644
index 0000000000..78d81dc62d
--- /dev/null
+++ b/src/cpu/allwinner/a10/memmap.h
@@ -0,0 +1,117 @@
+/*
+ * Memory map definitions for Allwinner A10 CPUs
+ *
+ * Copyright (C) 2007-2011 Allwinner Technology Co., Ltd.
+ * Tom Cubie <tangliang@allwinnertech.com>
+ * Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
+ * Subject to the GNU GPL v2, or (at your option) any later version.
+ */
+
+#ifndef CPU_ALLWINNER_A10_MEMMAP_H
+#define CPU_ALLWINNER_A10_MEMMAP_H
+
+#define A1X_SRAM_A1_BASE 0x00000000
+#define A1X_SRAM_A1_SIZE (16 * 1024) /* 16 kiB */
+
+#define A1X_SRAM_A2_BASE 0x00004000 /* 16 kiB */
+#define A1X_SRAM_A3_BASE 0x00008000 /* 13 kiB */
+#define A1X_SRAM_A4_BASE 0x0000b400 /* 3 kiB */
+#define A1X_SRAM_D_BASE 0x01c00000
+#define A1X_SRAM_B_BASE 0x01c00000 /* 64 kiB (secure) */
+
+#define A1X_SRAMC_BASE 0x01c00000
+#define A1X_DRAMC_BASE 0x01c01000
+#define A1X_DMA_BASE 0x01c02000
+#define A1X_NFC_BASE 0x01c03000
+#define A1X_TS_BASE 0x01c04000
+#define A1X_SPI0_BASE 0x01c05000
+#define A1X_SPI1_BASE 0x01c06000
+#define A1X_MS_BASE 0x01c07000
+#define A1X_TVD_BASE 0x01c08000
+#define A1X_CSI0_BASE 0x01c09000
+#define A1X_TVE0_BASE 0x01c0a000
+#define A1X_EMAC_BASE 0x01c0b000
+#define A1X_LCD0_BASE 0x01c0C000
+#define A1X_LCD1_BASE 0x01c0d000
+#define A1X_VE_BASE 0x01c0e000
+#define A1X_MMC0_BASE 0x01c0f000
+#define A1X_MMC1_BASE 0x01c10000
+#define A1X_MMC2_BASE 0x01c11000
+#define A1X_MMC3_BASE 0x01c12000
+#define A1X_USB0_BASE 0x01c13000
+#define A1X_USB1_BASE 0x01c14000
+#define A1X_SS_BASE 0x01c15000
+#define A1X_HDMI_BASE 0x01c16000
+#define A1X_SPI2_BASE 0x01c17000
+#define A1X_SATA_BASE 0x01c18000
+#define A1X_PATA_BASE 0x01c19000
+#define A1X_ACE_BASE 0x01c1a000
+#define A1X_TVE1_BASE 0x01c1b000
+#define A1X_USB2_BASE 0x01c1c000
+#define A1X_CSI1_BASE 0x01c1d000
+#define A1X_TZASC_BASE 0x01c1e000
+#define A1X_SPI3_BASE 0x01c1f000
+
+#define A1X_CCM_BASE 0x01c20000
+#define A1X_INTC_BASE 0x01c20400
+#define A1X_PIO_BASE 0x01c20800
+#define A1X_TIMER_BASE 0x01c20c00
+#define A1X_SPDIF_BASE 0x01c21000
+#define A1X_AC97_BASE 0x01c21400
+#define A1X_IR0_BASE 0x01c21800
+#define A1X_IR1_BASE 0x01c21c00
+
+#define A1X_IIS_BASE 0x01c22400
+#define A1X_LRADC_BASE 0x01c22800
+#define A1X_AD_DA_BASE 0x01c22c00
+#define A1X_KEYPAD_BASE 0x01c23000
+#define A1X_TZPC_BASE 0x01c23400
+#define A1X_SID_BASE 0x01c23800
+#define A1X_SJTAG_BASE 0x01c23c00
+
+#define A1X_TP_BASE 0x01c25000
+#define A1X_PMU_BASE 0x01c25400
+#define A1X_CPUCFG_BASE 0x01c25c00 /* sun7i only ? */
+
+#define A1X_UART0_BASE 0x01c28000
+#define A1X_UART1_BASE 0x01c28400
+#define A1X_UART2_BASE 0x01c28800
+#define A1X_UART3_BASE 0x01c28c00
+#define A1X_UART4_BASE 0x01c29000
+#define A1X_UART5_BASE 0x01c29400
+#define A1X_UART6_BASE 0x01c29800
+#define A1X_UART7_BASE 0x01c29c00
+#define A1X_PS2_0_BASE 0x01c2a000
+#define A1X_PS2_1_BASE 0x01c2a400
+
+#define A1X_TWI0_BASE 0x01c2ac00
+#define A1X_TWI1_BASE 0x01c2b000
+#define A1X_TWI2_BASE 0x01c2b400
+
+#define A1X_CAN_BASE 0x01c2bc00
+
+#define A1X_SCR_BASE 0x01c2c400
+
+#define A1X_GPS_BASE 0x01c30000
+#define A1X_MALI400_BASE 0x01c40000
+
+/* module sram */
+#define A1X_SRAM_C_BASE 0x01d00000
+
+#define A1X_DE_FE0_BASE 0x01e00000
+#define A1X_DE_FE1_BASE 0x01e20000
+#define A1X_DE_BE0_BASE 0x01e60000
+#define A1X_DE_BE1_BASE 0x01e40000
+#define A1X_MP_BASE 0x01e80000
+#define A1X_AVG_BASE 0x01ea0000
+
+/* CoreSight Debug Module */
+#define A1X_CSDM_BASE 0x3f500000
+
+#define A1X_DRAM_BASE 0x40000000 /* 2 GiB */
+
+#define A1X_BROM_BASE 0xffff0000 /* 32 kiB */
+
+#define A1X_CPU_CFG (A1X_TIMER_BASE + 0x13c)
+
+#endif /* CPU_ALLWINNER_A10_MEMMAP_H */
diff --git a/src/cpu/allwinner/a10/monotonic_timer.c b/src/cpu/allwinner/a10/monotonic_timer.c
new file mode 100644
index 0000000000..16d478a250
--- /dev/null
+++ b/src/cpu/allwinner/a10/monotonic_timer.c
@@ -0,0 +1,13 @@
+/*
+ * Placeholder for code to come (needed to complete build)
+ *
+ * Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
+ * Subject to the GNU GPL v2, or (at your option) any later version.
+ */
+
+#include <timer.h>
+
+void timer_monotonic_get(struct mono_time *mt)
+{
+ (void)mt;
+}
diff --git a/src/cpu/allwinner/a10/pinmux.c b/src/cpu/allwinner/a10/pinmux.c
new file mode 100644
index 0000000000..2525de58af
--- /dev/null
+++ b/src/cpu/allwinner/a10/pinmux.c
@@ -0,0 +1,30 @@
+/*
+ * Helpers to multiplex and configure pins on Allwinner SoCs
+ *
+ * Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
+ * Subject to the GNU GPL v2, or (at your option) any later version.
+ */
+
+#include "gpio.h"
+
+#include <arch/io.h>
+
+static struct a10_gpio *const gpio = (void *)GPIO_BASE;
+
+void gpio_set_func(u8 port, u8 pin, u8 pad_func)
+{
+ u8 reg, bit;
+ u32 reg32;
+
+ if ((port > GPS))
+ return;
+
+ pin &= 0x1f;
+ reg = pin / 8;
+ bit = (pin % 8) * 4;
+
+ reg32 = read32(&gpio->port[port].cfg[reg]);
+ reg32 &= ~(0xf << bit);
+ reg32 |= (pad_func & 0xf) << bit;
+ write32(reg32, &gpio->port[port].cfg[reg]);
+}
diff --git a/src/cpu/allwinner/a10/timer.c b/src/cpu/allwinner/a10/timer.c
new file mode 100644
index 0000000000..e156398be3
--- /dev/null
+++ b/src/cpu/allwinner/a10/timer.c
@@ -0,0 +1,19 @@
+/*
+ * Placeholder for code to come(needed to complete build)
+ *
+ * Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
+ * Subject to the GNU GPL v2, or (at your option) any later version.
+ */
+
+#include <delay.h>
+#include <timer.h>
+
+void init_timer(void)
+{
+ /* Stub */
+}
+
+void udelay(unsigned usec)
+{
+ /* Stub */
+}
diff --git a/src/cpu/allwinner/a10/uart.c b/src/cpu/allwinner/a10/uart.c
new file mode 100644
index 0000000000..dc98bffbdf
--- /dev/null
+++ b/src/cpu/allwinner/a10/uart.c
@@ -0,0 +1,98 @@
+/*
+ * Uart setup helpers for Allwinner SoCs
+ *
+ * Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
+ * Subject to the GNU GPL v2, or (at your option) any later version.
+ */
+
+#include "uart.h"
+#include <arch/io.h>
+
+/* Give me my 8250 UART definitions!!!! */
+/* TODO: Clean this up when uart8250mem works on ARM */
+#undef CONFIG_CONSOLE_SERIAL8250MEM
+#define CONFIG_CONSOLE_SERIAL8250MEM 1
+#include <uart8250.h>
+
+/**
+ * \brief Configure line control settings for UART
+ */
+void a10_uart_configure(void *uart_base, u32 baud_rate, u8 data_bits,
+ enum uart_parity parity, u8 stop_bits)
+{
+ u32 reg32;
+ u16 div;
+ struct a10_uart *uart = uart_base;
+
+ /* Enable access to Divisor Latch register */
+ write32(UART_LCR_DLAB, &uart->lcr);
+ /* Set baudrate */
+ /* FIXME: We assume clock is 24MHz, which may not be the case */
+ div = 24000000 / 16 / baud_rate;
+ write32((div >> 8) & 0xff, &uart->dlh);
+ write32(div & 0xff, &uart->dll);
+ /* Set line control */
+ reg32 = (data_bits - 5) & UART_LCR_WLS_MSK;
+ switch (parity) {
+ case UART_PARITY_ODD:
+ reg32 |= UART_LCR_PEN;
+ break;
+ case UART_PARITY_EVEN:
+ reg32 |= UART_LCR_PEN;
+ reg32 |= UART_LCR_EPS;
+ break;
+ case UART_PARITY_NONE: /* Fall through */
+ default:
+ break;
+ }
+ write32(reg32, &uart->lcr);
+}
+
+void a10_uart_enable_fifos(void *uart_base)
+{
+ struct a10_uart *uart = uart_base;
+
+ write32(UART_FCR_FIFO_EN, &uart->fcr);
+}
+
+static int tx_fifo_full(struct a10_uart *uart)
+{
+ /* This may be a misnomer, or a typo in the datasheet. THRE indicates
+ * that the TX register is empty, not that the FIFO is not full, but
+ * this may be due to a datasheet typo. Keep the current name to signal
+ * intent. */
+ return !(read32(&uart->lsr) & UART_LSR_THRE);
+}
+
+static int rx_fifo_empty(struct a10_uart *uart)
+{
+ return !(read32(&uart->lsr) & UART_LSR_DR);
+}
+
+/**
+ * \brief Read a single byte from the UART.
+ *
+ * Blocks until at least a byte is available.
+ */
+u8 a10_uart_rx_blocking(void *uart_base)
+{
+ struct a10_uart *uart = uart_base;
+
+ while (rx_fifo_empty(uart)) ;
+
+ return read32(&uart->rbr);
+}
+
+/**
+ * \brief Write a single byte to the UART.
+ *
+ * Blocks until there is space in the FIFO.
+ */
+void a10_uart_tx_blocking(void *uart_base, u8 data)
+{
+ struct a10_uart *uart = uart_base;
+
+ while (tx_fifo_full(uart)) ;
+
+ return write32(data, &uart->thr);
+}
diff --git a/src/cpu/allwinner/a10/uart.h b/src/cpu/allwinner/a10/uart.h
new file mode 100644
index 0000000000..86ab487e38
--- /dev/null
+++ b/src/cpu/allwinner/a10/uart.h
@@ -0,0 +1,77 @@
+/*
+ * Definitions for UART on Allwinner CPUs
+ *
+ * The UART on the A10 seems to be 8250-compatible, however, this has not been
+ * verified. Our 8250mem code is specific to x86, and does not yet work, so we
+ * have to re-implement it ARM-style for the time being. The register
+ * definitions are present in <uart7250.h>, and are not redefined here.
+ *
+ * Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
+ * Subject to the GNU GPL v2, or (at your option) any later version.
+ */
+
+#ifndef CPU_ALLWINNER_A10_UART_H
+#define CPU_ALLWINNER_A10_UART_H
+
+#include "memmap.h"
+#include <types.h>
+
+struct a10_uart {
+ union {
+ /* operational mode */
+ u32 rbr; /* receiver buffer (read) */
+ u32 thr; /* transmit holding (write) */
+ /* config mode (DLAB set) */
+ u32 dll; /* divisor latches low */
+ };
+
+ union {
+ /* operational mode */
+ u32 ier; /* interrupt enable */
+ /* config mode (DLAB set) */
+ u32 dlh; /* divisor latches high */
+ };
+
+ union {
+ u32 iir; /* interrupt ID (read) */
+ u32 fcr; /* FIFO control (write) */
+ };
+
+ u32 lcr; /* line control */
+
+ /* 0x10 */
+ u32 mcr; /* modem control */
+ u32 lsr; /* line status, read-only */
+ u32 msr; /* modem status */
+ u32 sch; /* scratch register */
+
+ u8 reserved_0x20[0x50];
+
+ /* 0x70 */
+ u8 reserved_0x70[0xc];
+ u32 usr; /* UART status register */
+
+ /* 0x80 */
+ u32 tfl; /* Transmit FIFO level */
+ u32 rfl; /* Receive FIFO level */
+ u8 reserved_0x88[0x18];
+
+ /* 0xa0 */
+ u8 reserved_0xa0[4];
+ u32 halt; /* Halt register */
+
+} __attribute__ ((packed));
+
+enum uart_parity {
+ UART_PARITY_NONE,
+ UART_PARITY_EVEN,
+ UART_PARITY_ODD,
+};
+
+void a10_uart_configure(void *uart_base, u32 baud_rate, u8 data_bits,
+ enum uart_parity parity, u8 stop_bits);
+void a10_uart_enable_fifos(void *uart_base);
+u8 a10_uart_rx_blocking(void *uart_base);
+void a10_uart_tx_blocking(void *uart_base, u8 data);
+
+#endif /* CPU_ALLWINNER_A10_UART_H */
diff --git a/src/cpu/allwinner/a10/uart_console.c b/src/cpu/allwinner/a10/uart_console.c
new file mode 100644
index 0000000000..58930ddd66
--- /dev/null
+++ b/src/cpu/allwinner/a10/uart_console.c
@@ -0,0 +1,109 @@
+/*
+ * Glue to UART code to enable serial console
+ *
+ * Copyright 2013 Google Inc.
+ * Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
+ * Subject to the GNU GPL v2, or (at your option) any later version.
+ */
+
+#include <config.h>
+#include <types.h>
+#include <uart.h>
+#include <arch/io.h>
+
+#include <console/console.h>
+#include <cpu/allwinner/a10/uart.h>
+
+static void *get_console_uart_base_addr(void)
+{
+ /* This big block gets compiled to a constant, not a function call */
+ if (CONFIG_CONSOLE_SERIAL_UART0)
+ return (void *)A1X_UART0_BASE;
+ else if (CONFIG_CONSOLE_SERIAL_UART1)
+ return (void *)A1X_UART1_BASE;
+ else if (CONFIG_CONSOLE_SERIAL_UART2)
+ return (void *)A1X_UART2_BASE;
+ else if (CONFIG_CONSOLE_SERIAL_UART3)
+ return (void *)A1X_UART3_BASE;
+ else if (CONFIG_CONSOLE_SERIAL_UART4)
+ return (void *)A1X_UART4_BASE;
+ else if (CONFIG_CONSOLE_SERIAL_UART5)
+ return (void *)A1X_UART5_BASE;
+ else if (CONFIG_CONSOLE_SERIAL_UART6)
+ return (void *)A1X_UART6_BASE;
+ else if (CONFIG_CONSOLE_SERIAL_UART7)
+ return (void *)A1X_UART7_BASE;
+
+ /* If selection is invalid, default to UART0 */
+ return (void *)A1X_UART0_BASE;
+}
+
+static u32 get_console_uart_baud(void)
+{
+ if (CONFIG_CONSOLE_SERIAL_115200)
+ return 115200;
+ else if (CONFIG_CONSOLE_SERIAL_57600)
+ return 57600;
+ else if (CONFIG_CONSOLE_SERIAL_38400)
+ return 34800;
+ else if (CONFIG_CONSOLE_SERIAL_19200)
+ return 19200;
+ else if (CONFIG_CONSOLE_SERIAL_9600)
+ return 9600;
+
+ /* Default to 115200 if selection is invalid */
+ return 115200;
+}
+
+static void a10_uart_init_dev(void)
+{
+ void *uart_base = get_console_uart_base_addr();
+ /* Use default 8N1 encoding */
+ a10_uart_configure(uart_base, get_console_uart_baud(),
+ 8, UART_PARITY_NONE, 1);
+ a10_uart_enable_fifos(uart_base);
+}
+
+static unsigned char a10_uart_rx_byte(void)
+{
+ return a10_uart_rx_blocking(get_console_uart_base_addr());
+}
+
+static void a10_uart_tx_byte(unsigned char data)
+{
+ a10_uart_tx_blocking(get_console_uart_base_addr(), data);
+}
+
+uint32_t uartmem_getbaseaddr(void)
+{
+ return (uint32_t) get_console_uart_base_addr();
+}
+
+#if !defined(__PRE_RAM__)
+static const struct console_driver a10_uart_console __console = {
+ .init = a10_uart_init_dev,
+ .tx_byte = a10_uart_tx_byte,
+ .rx_byte = a10_uart_rx_byte,
+};
+#else
+
+void uart_init(void)
+{
+ a10_uart_init_dev();
+}
+
+unsigned char uart_rx_byte(void)
+{
+ return a10_uart_rx_byte();
+}
+
+void uart_tx_byte(unsigned char data)
+{
+ a10_uart_tx_byte(data);
+}
+
+void uart_tx_flush(void)
+{
+}
+
+#endif