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>
This commit is contained in:
Alexandru Gagniuc 2013-12-13 20:44:48 -06:00
parent 34286b861a
commit f64111b486
17 changed files with 840 additions and 0 deletions

View File

@ -3,6 +3,7 @@
# (See also src/Kconfig)
if ARCH_ARMV7
source src/cpu/allwinner/Kconfig
source src/cpu/armltd/Kconfig
source src/cpu/samsung/Kconfig
source src/cpu/ti/Kconfig

View File

@ -1,6 +1,7 @@
################################################################################
## Subdirectories
################################################################################
subdirs-y += allwinner
subdirs-y += amd
subdirs-y += dmp
subdirs-y += armltd

View File

@ -0,0 +1 @@
source src/cpu/allwinner/a10/Kconfig

View File

@ -0,0 +1 @@
subdirs-$(CONFIG_CPU_ALLWINNER_A10) += a10

View File

@ -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

View File

@ -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 $@

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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;
}

View File

@ -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]);
}

View File

@ -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 */
}

View File

@ -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);
}

View File

@ -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 */

View File

@ -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