diff options
author | Alexandru Gagniuc <mr.nuke.me@gmail.com> | 2013-12-13 20:44:48 -0600 |
---|---|---|
committer | Alexandru Gagniuc <mr.nuke.me@gmail.com> | 2014-01-08 22:54:08 +0100 |
commit | f64111b4865d611821950b25dc1ea235d8d9ca79 (patch) | |
tree | d61eef4c9476ada907f0d91e93c2707aed44df96 /src/cpu/allwinner/a10 | |
parent | 34286b861a9427520f3f3afb8bf64bfa7de37c24 (diff) | |
download | coreboot-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/Kconfig | 115 | ||||
-rw-r--r-- | src/cpu/allwinner/a10/Makefile.inc | 35 | ||||
-rw-r--r-- | src/cpu/allwinner/a10/bootblock.c | 21 | ||||
-rw-r--r-- | src/cpu/allwinner/a10/bootblock_media.c | 14 | ||||
-rw-r--r-- | src/cpu/allwinner/a10/clock.h | 137 | ||||
-rw-r--r-- | src/cpu/allwinner/a10/gpio.h | 51 | ||||
-rw-r--r-- | src/cpu/allwinner/a10/memmap.h | 117 | ||||
-rw-r--r-- | src/cpu/allwinner/a10/monotonic_timer.c | 13 | ||||
-rw-r--r-- | src/cpu/allwinner/a10/pinmux.c | 30 | ||||
-rw-r--r-- | src/cpu/allwinner/a10/timer.c | 19 | ||||
-rw-r--r-- | src/cpu/allwinner/a10/uart.c | 98 | ||||
-rw-r--r-- | src/cpu/allwinner/a10/uart.h | 77 | ||||
-rw-r--r-- | src/cpu/allwinner/a10/uart_console.c | 109 |
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 |