cpu/allwinner: Remove support

The Allwinner code was never completed and lacks a driver to load
romstage from the bootblock.

Change-Id: If2bae9e28a6e1ed6bfe0e9cb022ca410918cc4db
Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/33133
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
Arthur Heymans 2019-05-30 22:42:42 +02:00 committed by Patrick Georgi
parent 041200fae3
commit c27f1c390a
25 changed files with 0 additions and 2647 deletions

View File

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

View File

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

View File

@ -1,18 +0,0 @@
config CPU_ALLWINNER_A10
bool
default n
if CPU_ALLWINNER_A10
config CPU_SPECIFIC_OPTIONS
def_bool y
select ARCH_BOOTBLOCK_ARMV7
select ARCH_VERSTAGE_ARMV7
select ARCH_ROMSTAGE_ARMV7
select ARCH_RAMSTAGE_ARMV7
select NO_MONOTONIC_TIMER
select HAVE_UART_SPECIAL
select UART_OVERRIDE_REFCLK
select BOOT_DEVICE_NOT_SPI_FLASH
endif # if CPU_ALLWINNER_A10

View File

@ -1,55 +0,0 @@
bootblock-y += bootblock.c
bootblock-y += bootblock_media.c
bootblock-y += clock.c
bootblock-y += gpio.c
bootblock-y += pinmux.c
bootblock-y += raminit.c
bootblock-y += timer.c
romstage-y += bootblock_media.c
romstage-y += cbmem.c
romstage-y += clock.c
romstage-y += pinmux.c
romstage-y += timer.c
romstage-y += twi.c
ramstage-y += bootblock_media.c
ramstage-y += cbmem.c
ramstage-y += clock.c
ramstage-y += cpu.c
ramstage-y += timer.c
ramstage-y += twi.c
bootblock-y += uart.c uart_console.c
romstage-y += uart.c uart_console.c
ramstage-y += uart.c uart_console.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))))))
# This tool is used to prepend a header to coreboot.rom to trick the SoC into
# loading out bootblock
#
MKSUNXIBOOT:=$(objutil)/mksunxiboot
$(MKSUNXIBOOT): $(top)/util/arm_boot_tools/mksunxiboot/mksunxiboot.c
@printf " HOSTCC $(subst $(obj)/,,$(@))\n"
$(HOSTCC) $(HOSTCFLAGS) -o $@ $<
# 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 added by the 'mxsunxiboot' tool, which is provided
# under util/arm_boot_tools/mksunxiboot. The boot ROM will load at most 24KiB of
# data to SRAM. The BOOT0 header takes 32 bytes, so bootblock is limited to
# 24KiB - 32 bytes.
# TODO: make mksunxiboot take the bootblock size as a parameter
# TODO: print an error if bootblock is too large (maybe place ROMSTAGE at the
# exact offset needed to collide with the bootblock)
# FIXME: A10 loads 24KiB. According to Oliver other chips load a little more
#
$(obj)/BOOT0: $(obj)/coreboot.rom $(MKSUNXIBOOT)
@printf " BOOT0 $(subst $(obj)/,,$(^))\n"
$(MKSUNXIBOOT) $(word 1, $^) $@

View File

@ -1,33 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2013 Google Inc.
* Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
*
* 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; 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.
*
* Allwinner A10 bootblock initialization
*
*/
#include <types.h>
#include <arch/cache.h>
#include <bootblock_common.h>
void bootblock_soc_init(void)
{
uint32_t sctlr;
/* enable dcache */
sctlr = read_sctlr();
sctlr |= SCTLR_C;
write_sctlr(sctlr);
}

View File

@ -1,26 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
*
* 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; 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.
*
* CBFS accessors for bootblock stage.
*
*/
#include <boot_device.h>
#include <console/console.h>
const struct region_device *boot_device_ro(void)
{
printk(BIOS_ERR, "Oh my! I don't know how to access CBFS yet.");
return NULL;
}

View File

@ -1,26 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
*
* 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; 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.
*
* Provides cbmem utilities for romstage and ramstage
*
*/
#include "ram_segs.h"
#include <cbmem.h>
void *cbmem_top(void)
{
return a1x_get_cbmem_top();
}

View File

@ -1,23 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
*
* 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; 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.
*
* Allwinnwer A10 devicetree config struct
*
*/
#include <types.h>
struct cpu_allwinner_a10_config {
};

View File

@ -1,283 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
*
* 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; 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.
*
* Helpers for clock control and gating on Allwinner CPUs
*/
#include "clock.h"
#include <device/mmio.h>
#include <console/console.h>
#include <delay.h>
#include <lib.h>
static struct a10_ccm *const ccm = (void *)A1X_CCM_BASE;
/**
* \brief Enable the clock source for the peripheral
*
* @param[in] periph peripheral and clock type to enable @see a1x_clken
*/
void a1x_periph_clock_enable(enum a1x_clken periph)
{
void *addr;
u32 reg32;
addr = (void *)A1X_CCM_BASE + (periph >> 5);
reg32 = read32(addr);
reg32 |= 1 << (periph & 0x1f);
write32(addr, reg32);
}
/**
* \brief Disable the clock source for the peripheral
*
* @param[in] periph peripheral and clock type to disable @see a1x_clken
*/
void a1x_periph_clock_disable(enum a1x_clken periph)
{
void *addr;
u32 reg32;
addr = (void *)A1X_CCM_BASE + (periph >> 5);
reg32 = read32(addr);
reg32 &= ~(1 << (periph & 0x1f));
write32(addr, reg32);
}
/**
* \brief Configure PLL5 factors
*
* This is a low-level accessor to configure the divisors and multipliers of
* PLL5. PLL5 uses two factors to multiply the 24MHz oscillator clock to
* generate a pre-clock. The pre-divided clock is then divided by one of two
* independent divisors, one for DRAM, and another for peripherals clocked from
* this PLL. If the PLL was previously disabled, this function will enable it.
* Other than that, this function only modifies these factors, and leaves the
* other settings unchanged.
*
* The output clocks are given by the following formulas:
*
* Pre-clock = (24 MHz * N * K) <- Must be between 240MHz and 2GHz
* DRAM clock = pre / M
* Other module = pre / P
*
* It is the caller's responsibility to make sure the pre-divided clock falls
* within the operational range of the PLL, and that the divisors and
* multipliers are within their ranges.
*
* @param[in] mul_n Multiplier N, between 0 and 32
* @param[in] mul_k Multiplier K, between 1 and 4
* @param[in] div_m DRAM clock divisor, between 1 and 4
* @param[in] exp_div_p Peripheral clock divisor exponent, between 0 and 3
* (P = 1/2/4/8, respectively)
*/
void a1x_pll5_configure(u8 mul_n, u8 mul_k, u8 div_m, u8 exp_div_p)
{
u32 reg32;
reg32 = read32(&ccm->pll5_cfg);
reg32 &= ~(PLL5_FACTOR_M_MASK | PLL5_FACTOR_N_MASK |
PLL5_FACTOR_K_MASK | PLL5_DIV_EXP_P_MASK);
/* The M1 factor is not documented in the datasheet, and the reference
* raminit code does not use it. Whether this is a fractional divisor,
* or an additional divisor is unknown, so don't use it for now */
reg32 &= ~PLL5_FACTOR_M1_MASK;
reg32 |= (PLL5_FACTOR_M(div_m) | PLL5_FACTOR_N(mul_n) |
PLL5_FACTOR_K(mul_k) | PLL5_DIV_EXP_P(exp_div_p));
reg32 |= PLL5_PLL_ENABLE;
write32(&ccm->pll5_cfg, reg32);
}
/**
* \brief Enable the clock output to DRAM chips
*
* This enables the DRAM clock to be sent to DRAM chips. This should normally be
* done after PLL5 is configured and locked. Note that the clock may be gated,
* and also needs to be ungated in order to reach the DDR chips.
* Also see @ref clock_ungate_dram_clk_output
*/
void a1x_pll5_enable_dram_clock_output(void)
{
setbits_le32(&ccm->pll5_cfg, PLL5_DDR_CLK_OUT_EN);
}
/**
* \brief Ungate the clock to DRAM chips
*
* Although the DRAM clock output may be enabled, it is by default gated. It
* needs to be ungated before reaching DRAM.
*/
void a1x_ungate_dram_clock_output(void)
{
setbits_le32(&ccm->dram_clk_cfg, DRAM_CTRL_DCLK_OUT);
}
/**
* \brief Gate the clock to DRAM chips
*
* Disable the clock to DRAM without altering PLL configuration, by closing the
* DRAM clock gate.
*/
void a1x_gate_dram_clock_output(void)
{
clrbits_le32(&ccm->dram_clk_cfg, DRAM_CTRL_DCLK_OUT);
}
/*
* Linker doesn't garbage collect and the function below adds about half
* kilobyte to the bootblock, and log2_ceil is not available in the bootblock.
*/
#ifndef __BOOTBLOCK__
#define PLL1_CFG(N, K, M, P_EXP) \
((1 << 31 | 0 << 30 | 8 << 26 | 0 << 25 | 16 << 20 | 2 << 13) | \
(P_EXP) << 16 | (N) << 8 | \
(K - 1) << 4 | 0 << 3 | 0 << 2 | (M -1) << 0)
static const struct {
u32 pll1_cfg;
u16 freq_mhz;
} pll1_table[] = {
/* PLL1 output = (24MHz * N * K) / (M * P) */
{ PLL1_CFG(16, 1, 1, 0), 384 },
{ PLL1_CFG(16, 2, 1, 0), 768 },
{ PLL1_CFG(20, 2, 1, 0), 960 },
{ PLL1_CFG(21, 2, 1, 0), 1008 },
{ PLL1_CFG(22, 2, 1, 0), 1056 },
{ PLL1_CFG(23, 2, 1, 0), 1104 },
{ PLL1_CFG(24, 2, 1, 0), 1152 },
{ PLL1_CFG(25, 2, 1, 0), 1200 },
{ PLL1_CFG(26, 2, 1, 0), 1248 },
{ PLL1_CFG(27, 2, 1, 0), 1296 },
{ PLL1_CFG(28, 2, 1, 0), 1344 },
{ PLL1_CFG(29, 2, 1, 0), 1392 },
{ PLL1_CFG(30, 2, 1, 0), 1440 },
{ PLL1_CFG(31, 2, 1, 0), 1488 },
{ PLL1_CFG(20, 4, 1, 0), 1944 },
};
static void cpu_clk_src_switch(u32 clksel_bits)
{
u32 reg32;
reg32 = read32(&ccm->cpu_ahb_apb0_cfg);
reg32 &= ~CPU_CLK_SRC_MASK;
reg32 |= clksel_bits & CPU_CLK_SRC_MASK;
write32(&ccm->cpu_ahb_apb0_cfg, reg32);
}
static void change_sys_divisors(u8 axi, u8 ahb_exp, u8 apb0_exp)
{
u32 reg32;
reg32 = read32(&ccm->cpu_ahb_apb0_cfg);
/* Not a typo: We want to keep only the CLK_SRC bits */
reg32 &= CPU_CLK_SRC_MASK;
reg32 |= ((axi - 1) << 0) & AXI_DIV_MASK;
reg32 |= (ahb_exp << 4) & AHB_DIV_MASK;
reg32 |= (apb0_exp << 8) & APB0_DIV_MASK;
write32(&ccm->cpu_ahb_apb0_cfg, reg32);
}
static void spin_delay(u32 loops)
{
volatile u32 x = loops;
while (x--);
}
/**
* \brief Configure the CPU clock and PLL1
*
* To run at full speed, the CPU uses PLL1 as the clock source. AXI, AHB, and
* APB0 are derived from the CPU clock, and need to be kept within certain
* limits. This function configures PLL1 as close as possible to the desired
* frequency, based on a set of known working configurations for PLL1. It then
* calculates and applies the appropriate divisors for the AXI/AHB/APB0 clocks,
* before finally switching the CPU to run from the new clock.
* No further configuration of the CPU clock or divisors is needed. after
* calling this function.
*
* @param[in] cpu_clk_mhz Desired CPU clock, in MHz
*/
void a1x_set_cpu_clock(u16 cpu_clk_mhz)
{
int i = 0;
u8 axi, ahb, ahb_exp, apb0, apb0_exp;
u32 actual_mhz;
/*
* Rated clock for PLL1 is 2000 MHz, but there is no combination of
* parameters that yields that exact frequency. 1944 MHz is the highest.
*/
if (cpu_clk_mhz > 1944) {
printk(BIOS_CRIT, "BUG! maximum PLL1 clock is 1944 MHz,"
"but asked to clock CPU at %d MHz\n",
cpu_clk_mhz);
cpu_clk_mhz = 1944;
}
/* Find target frequency */
while (pll1_table[i].freq_mhz < cpu_clk_mhz)
i++;
actual_mhz = pll1_table[i].freq_mhz;
if (cpu_clk_mhz != actual_mhz) {
printk(BIOS_WARNING, "Parameters for %d MHz not available, "
"setting CPU clock at %d MHz\n",
cpu_clk_mhz, actual_mhz);
}
/*
* Calculate system clock divisors:
* The minimum clock divisor for APB0 is 2, which guarantees that AHB0
* will always be in spec, as long as AHB is in spec, although the max
* AHB0 clock we can get is 125 MHz
*/
axi = DIV_ROUND_UP(actual_mhz, 450); /* Max 450 MHz */
ahb = DIV_ROUND_UP(actual_mhz/axi, 250); /* Max 250 MHz */
apb0 = 2; /* Max 150 MHz */
ahb_exp = log2_ceil(ahb);
ahb = 1 << ahb_exp;
apb0_exp = 1;
printk(BIOS_INFO, "CPU: %d MHz, AXI %d Mhz, AHB: %d MHz APB0: %d MHz\n",
actual_mhz,
actual_mhz / axi,
actual_mhz / (axi * ahb),
actual_mhz / (axi * ahb * apb0));
/* Keep the CPU off PLL1 while we change PLL parameters */
cpu_clk_src_switch(CPU_CLK_SRC_OSC24M);
/*
* We can't use udelay() here. udelay() relies on timer 0, but timers
* have the habit of not ticking when the CPU is clocked from the main
* oscillator.
*/
spin_delay(8);
change_sys_divisors(axi, ahb_exp, apb0_exp);
/* Configure PLL1 at the desired frequency */
write32(&ccm->pll1_cfg, pll1_table[i].pll1_cfg);
spin_delay(8);
cpu_clk_src_switch(CPU_CLK_SRC_PLL1);
/* Here, we're running from PLL, so timers will tick */
udelay(1);
}
#endif /* __BOOTBLOCK__ */

View File

@ -1,283 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2007-2011 Allwinner Technology Co., Ltd.
* Tom Cubie <tangliang@allwinnertech.com>
* Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
*
* 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; 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.
*
* Definitions for clock control and gating on Allwinner CPUs
*/
#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)
/* PLL5_CFG values */
#define PLL5_PLL_ENABLE (1 << 31)
#define PLL5_OUT_BYPASS_EN (1 << 30)
#define PLL5_DDR_CLK_OUT_EN (1 << 29)
#define PLL5_DIV_EXP_P_MASK (0x3 << 16)
#define PLL5_DIV_EXP_P(ep) ((ep << 16) & PLL5_DIV_EXP_P_MASK)
#define PLL5_DIV_P_1 (0x0 << 16)
#define PLL5_DIV_P_2 (0x1 << 16)
#define PLL5_DIV_P_4 (0x2 << 16)
#define PLL5_DIV_P_8 (0x3 << 16)
#define PLL5_FACTOR_N_MASK (0x1f << 8)
#define PLL5_FACTOR_N(n) ((n << 8) & PLL5_FACTOR_N_MASK)
#define PLL5_LDO_EN (1 << 7)
#define PLL5_FACTOR_K_MASK (0x3 << 4)
#define PLL5_FACTOR_K(k) ((((k) - 1) << 4) & PLL5_FACTOR_K_MASK)
#define PLL5_FACTOR_M1_MASK (0x3 << 2)
#define PLL5_FACTOR_M1(m1) (((m1) << 2) & PLL5_FACTOR_M1_MASK)
#define PLL5_FACTOR_M_MASK (0x3 << 0)
#define PLL5_FACTOR_M(m) ((((m) - 1) << 0) & PLL5_FACTOR_M_MASK)
/* DRAM_CLK values*/
#define DRAM_CTRL_DCLK_OUT (1 << 15)
/* SDx_CLK values */
#define SDx_CLK_GATE (1 << 31)
#define SDx_CLK_SRC_MASK (3 << 24)
#define SDx_CLK_SRC_OSC24M (0 << 24)
#define SDx_CLK_SRC_PLL6 (1 << 24)
#define SDx_CLK_SRC_PLL5 (2 << 24)
#define SDx_RAT_EXP_N_MASK (3 << 16)
#define SDx_RAT_EXP_N(n) (((n) << 16) & SDx_RAT_EXP_N_MASK)
#define SDx_RAT_M_MASK (0xf << 0)
#define SDx_RAT_M(m) ((((m) - 1) << 0) & SDx_RAT_M_MASK)
/**
* \brief Clock gating definitions
*
* The definitions are specified in the form:
* 31:5 register offset from A1X_CCM_BASE for the clock register
* 4:0 bit offset for the given peripheral
*
* The names have the form [periph_type][periph_number]
*
* These definitions are meant to be used with @ref a1x_periph_clock_enable and
* @ref a1x_periph_clock_disable
*/
enum a1x_clken {
/* AXI module clock gating */
A1X_CLKEN_DRAM_AXI = (0x5C << 5),
/* AHB0 module clock gating */
A1X_CLKEN_USB0 = (0x60 << 5),
A1X_CLKEN_EHCI0,
RSVD_0x60_2,
A1X_CLKEN_EHCI1,
RSVD_0x60_4,
A1X_CLKEN_SS,
A1X_CLKEN_DMA,
A1X_CLKEN_BIST,
A1X_CLKEN_MMC0,
A1X_CLKEN_MMC1,
A1X_CLKEN_MMC2,
A1X_CLKEN_MMC3,
A1X_CLKEN_NC,
A1X_CLKEN_NAND,
A1X_CLKEN_SDRAM,
RSVD_0x60_15,
A1X_CLKEN_ACE,
A1X_CLKEN_EMAC,
A1X_CLKEN_TS,
RSVD_0x60_19,
A1X_CLKEN_SPI0,
A1X_CLKEN_SPI1,
A1X_CLKEN_SPI2,
A1X_CLKEN_SPI3,
A1X_CLKEN_PATA,
RSVD_0x60_25,
A1X_CLKEN_GPS,
/* AHB1 module clock gating */
A1X_CLKEN_DRAM_VE = (0x64 << 5),
A1X_CLKEN_TVD,
A1X_CLKEN_TVE0,
A1X_CLKEN_TVE1,
A1X_CLKEN_LCD0,
A1X_CLKEN_LCD1,
RSVD_0x64_6,
RSVD_0x64_7,
A1X_CLKEN_CSI0,
A1X_CLKEN_CSI1,
RSVD_0x64_10,
A1X_CLKEN_HDMI,
A1X_CLKEN_DE_BE0,
A1X_CLKEN_DE_BE1,
A1X_CLKEN_DE_FE0,
A1X_CLKEN_DE_FE1,
RSVD_0x64_16,
RSVD_0x64_17,
A1X_CLKEN_MP,
RSVD_0x64_19,
A1X_CLKEN_MALI400,
/* APB0 module clock gating */
A1X_CLKEN_CODEC = (0x68 << 5),
A1X_CLKEN_NC_APB,
A1X_CLKEN_AC97,
A1X_CLKEN_IIS,
RSVD_0x68_4,
A1X_CLKEN_PIO,
A1X_CLKEN_IR0,
A1X_CLKEN_IR1,
RSVD_0x68_8,
RSVD_0x68_9,
A1X_CLKEN_KEYPAD,
/* APB1 module clock gating */
A1X_CLKEN_TWI0 = (0x6C << 5),
A1X_CLKEN_TWI1,
A1X_CLKEN_TWI2,
RSVD_0x6C_3,
A1X_CLKEN_CAN,
A1X_CLKEN_SCR,
A1X_CLKEN_PS20,
A1X_CLKEN_PS21,
RSVD_0x6C_8,
RSVD_0x6C_9,
RSVD_0x6C_10,
RSVD_0x6C_11,
RSVD_0x6C_12,
RSVD_0x6C_13,
RSVD_0x6C_14,
RSVD_0x6C_15,
A1X_CLKEN_UART0,
A1X_CLKEN_UART1,
A1X_CLKEN_UART2,
A1X_CLKEN_UART3,
A1X_CLKEN_UART4,
A1X_CLKEN_UART5,
A1X_CLKEN_UART6,
A1X_CLKEN_UART7,
};
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 */
} __packed;
void a1x_periph_clock_enable(enum a1x_clken periph);
void a1x_periph_clock_disable(enum a1x_clken periph);
void a1x_pll5_configure(u8 mul_n, u8 mul_k, u8 div_m, u8 exp_div_p);
void a1x_pll5_enable_dram_clock_output(void);
void a1x_ungate_dram_clock_output(void);
void a1x_gate_dram_clock_output(void);
/* Not available in bootblock */
void a1x_set_cpu_clock(u16 cpu_clk_mhz);
#endif /* CPU_ALLWINNER_A10_CLOCK_H */

View File

@ -1,53 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2014 Alexandru Gagniuc <mr.nuke.me@gmail.com>
*
* 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; 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.
*
* Ramstage initialization for Allwinner CPUs
*
*/
#include <device/device.h>
#include <symbols.h>
static void cpu_enable_resources(struct device *dev)
{
ram_resource(dev, 0, (uintptr_t)_dram/KiB,
CONFIG_DRAM_SIZE_MB << 10);
/* TODO: Declare CBFS cache as reserved? There's no guarantee we won't
* overwrite it. It seems to stay intact, being so high in RAM
*/
}
static void cpu_init(struct device *dev)
{
/* TODO: Check if anything else needs to be explicitly initialized */
}
static struct device_operations cpu_ops = {
.read_resources = DEVICE_NOOP,
.set_resources = DEVICE_NOOP,
.enable_resources = cpu_enable_resources,
.init = cpu_init,
.scan_bus = NULL,
};
static void a1x_cpu_enable_dev(struct device *dev)
{
dev->ops = &cpu_ops;
}
struct chip_operations cpu_allwinner_a10_ops = {
CHIP_NAME("CPU Allwinner A10")
.enable_dev = a1x_cpu_enable_dev,
};

View File

@ -1,187 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2007-2012 Allwinner Technology Co., Ltd.
* Berg Xing <bergxing@allwinnertech.com>
* Tom Cubie <tangliang@allwinnertech.com>
* Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
*
* 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; 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.
*
* Allwinner A10 platform dram register definition.
*
* Based on sun4i Linux kernel sources mach-sunxi/pm/standby/dram*.c
* and earlier U-Boot Allwiner A10 SPL work
*/
#ifndef CPU_ALLWINNER_A10_DRAMC_H
#define CPU_ALLWINNER_A10_DRAMC_H
#include <types.h>
#define DRAM_CCR_COMMAND_RATE_1T (0x1 << 5)
#define DRAM_CCR_DQS_GATE (0x1 << 14)
#define DRAM_CCR_DQS_DRIFT_COMP (0x1 << 17)
#define DRAM_CCR_ITM_OFF (0x1 << 28)
#define DRAM_CCR_DATA_TRAINING (0x1 << 30)
#define DRAM_CCR_INIT (0x1 << 31)
#define DRAM_MEMORY_TYPE_DDR1 1
#define DRAM_MEMORY_TYPE_DDR2 2
#define DRAM_MEMORY_TYPE_DDR3 3
#define DRAM_MEMORY_TYPE_LPDDR2 4
#define DRAM_MEMORY_TYPE_LPDDR 5
#define DRAM_DCR_TYPE (0x1 << 0)
#define DRAM_DCR_TYPE_DDR2 0x0
#define DRAM_DCR_TYPE_DDR3 0x1
#define DRAM_DCR_IO_WIDTH(n) (((n) & 0x3) << 1)
#define DRAM_DCR_IO_WIDTH_MASK DRAM_DCR_IO_WIDTH(0x3)
#define DRAM_DCR_IO_WIDTH_8BIT 0x0
#define DRAM_DCR_IO_WIDTH_16BIT 0x1
#define DRAM_DCR_CHIP_DENSITY(n) (((n) & 0x7) << 3)
#define DRAM_DCR_CHIP_DENSITY_MASK DRAM_DCR_CHIP_DENSITY(0x7)
#define DRAM_DCR_CHIP_DENSITY_256M 0x0
#define DRAM_DCR_CHIP_DENSITY_512M 0x1
#define DRAM_DCR_CHIP_DENSITY_1024M 0x2
#define DRAM_DCR_CHIP_DENSITY_2048M 0x3
#define DRAM_DCR_CHIP_DENSITY_4096M 0x4
#define DRAM_DCR_CHIP_DENSITY_8192M 0x5
#define DRAM_DCR_BUS_WIDTH(n) (((n) & 0x7) << 6)
#define DRAM_DCR_BUS_WIDTH_MASK DRAM_DCR_BUS_WIDTH(0x7)
#define DRAM_DCR_BUS_WIDTH_32BIT 0x3
#define DRAM_DCR_BUS_WIDTH_16BIT 0x1
#define DRAM_DCR_BUS_WIDTH_8BIT 0x0
#define DRAM_DCR_NR_DLLCR_32BIT 5
#define DRAM_DCR_NR_DLLCR_16BIT 3
#define DRAM_DCR_NR_DLLCR_8BIT 2
#define DRAM_DCR_RANK_SEL(n) (((n) & 0x3) << 10)
#define DRAM_DCR_RANK_SEL_MASK DRAM_DCR_CMD_RANK(0x3)
#define DRAM_DCR_CMD_RANK_ALL (0x1 << 12)
#define DRAM_DCR_MODE(n) (((n) & 0x3) << 13)
#define DRAM_DCR_MODE_MASK DRAM_DCR_MODE(0x3)
#define DRAM_DCR_MODE_SEQ 0x0
#define DRAM_DCR_MODE_INTERLEAVE 0x1
#define DRAM_CSR_FAILED (0x1 << 20)
#define DRAM_MCR_MODE_NORM(n) (((n) & 0x3) << 0)
#define DRAM_MCR_MODE_NORM_MASK DRAM_MCR_MOD_NORM(0x3)
#define DRAM_MCR_MODE_DQ_OUT(n) (((n) & 0x3) << 2)
#define DRAM_MCR_MODE_DQ_OUT_MASK DRAM_MCR_MODE_DQ_OUT(0x3)
#define DRAM_MCR_MODE_ADDR_OUT(n) (((n) & 0x3) << 4)
#define DRAM_MCR_MODE_ADDR_OUT_MASK DRAM_MCR_MODE_ADDR_OUT(0x3)
#define DRAM_MCR_MODE_DQ_IN_OUT(n) (((n) & 0x3) << 6)
#define DRAM_MCR_MODE_DQ_IN_OUT_MASK DRAM_MCR_MODE_DQ_IN_OUT(0x3)
#define DRAM_MCR_MODE_DQ_TURNON_DELAY(n) (((n) & 0x7) << 8)
#define DRAM_MCR_MODE_DQ_TURNON_DELAY_MASK DRAM_MCR_MODE_DQ_TURNON_DELAY(0x7)
#define DRAM_MCR_MODE_ADDR_IN (0x1 << 11)
#define DRAM_MCR_RESET (0x1 << 12)
#define DRAM_MCR_MODE_EN(n) (((n) & 0x3) << 13)
#define DRAM_MCR_MODE_EN_MASK DRAM_MCR_MOD_EN(0x3)
#define DRAM_MCR_DCLK_OUT (0x1 << 16)
#define DRAM_DLLCR_NRESET (0x1 << 30)
#define DRAM_DLLCR_DISABLE (0x1 << 31)
#define DRAM_ZQCR0_IMP_DIV(n) (((n) & 0xff) << 20)
#define DRAM_ZQCR0_IMP_DIV_MASK DRAM_ZQCR0_IMP_DIV(0xff)
#define DRAM_IOCR_ODT_EN(n) ((((n) & 0x3) << 30) | ((n) & 0x3) << 0)
#define DRAM_IOCR_ODT_EN_MASK DRAM_IOCR_ODT_EN(0x3)
#define DRAM_MR_BURST_LENGTH(n) (((n) & 0x7) << 0)
#define DRAM_MR_BURST_LENGTH_MASK DRAM_MR_BURST_LENGTH(0x7)
#define DRAM_MR_CAS_LAT(n) (((n) & 0x7) << 4)
#define DRAM_MR_CAS_LAT_MASK DRAM_MR_CAS_LAT(0x7)
#define DRAM_MR_WRITE_RECOVERY(n) (((n) & 0x7) << 9)
#define DRAM_MR_WRITE_RECOVERY_MASK DRAM_MR_WRITE_RECOVERY(0x7)
#define DRAM_MR_POWER_DOWN (0x1 << 12)
#define DRAM_CSEL_MAGIC 0x16237495
struct a1x_dramc {
u32 ccr; /* 0x00 controller configuration register */
u32 dcr; /* 0x04 dram configuration register */
u32 iocr; /* 0x08 i/o configuration register */
u32 csr; /* 0x0c controller status register */
u32 drr; /* 0x10 dram refresh register */
u32 tpr0; /* 0x14 dram timing parameters register 0 */
u32 tpr1; /* 0x18 dram timing parameters register 1 */
u32 tpr2; /* 0x1c dram timing parameters register 2 */
u32 gdllcr; /* 0x20 global dll control register */
u8 res0[0x28];
u32 rslr0; /* 0x4c rank system latency register */
u32 rslr1; /* 0x50 rank system latency register */
u8 res1[0x8];
u32 rdgr0; /* 0x5c rank dqs gating register */
u32 rdgr1; /* 0x60 rank dqs gating register */
u8 res2[0x34];
u32 odtcr; /* 0x98 odt configuration register */
u32 dtr0; /* 0x9c data training register 0 */
u32 dtr1; /* 0xa0 data training register 1 */
u32 dtar; /* 0xa4 data training address register */
u32 zqcr0; /* 0xa8 zq control register 0 */
u32 zqcr1; /* 0xac zq control register 1 */
u32 zqsr; /* 0xb0 zq status register */
u32 idcr; /* 0xb4 initializaton delay configure reg */
u8 res3[0x138];
u32 mr; /* 0x1f0 mode register */
u32 emr; /* 0x1f4 extended mode register */
u32 emr2; /* 0x1f8 extended mode register */
u32 emr3; /* 0x1fc extended mode register */
u32 dllctr; /* 0x200 dll control register */
u32 dllcr[5]; /* 0x204 dll control register 0(byte 0) */
/* 0x208 dll control register 1(byte 1) */
/* 0x20c dll control register 2(byte 2) */
/* 0x210 dll control register 3(byte 3) */
/* 0x214 dll control register 4(byte 4) */
u32 dqtr0; /* 0x218 dq timing register */
u32 dqtr1; /* 0x21c dq timing register */
u32 dqtr2; /* 0x220 dq timing register */
u32 dqtr3; /* 0x224 dq timing register */
u32 dqstr; /* 0x228 dqs timing register */
u32 dqsbtr; /* 0x22c dqsb timing register */
u32 mcr; /* 0x230 mode configure register */
u8 res[0x8];
u32 ppwrsctl; /* 0x23c pad power save control */
u32 apr; /* 0x240 arbiter period register */
u32 pldtr; /* 0x244 priority level data threshold reg */
u8 res5[0x8];
u32 hpcr[32]; /* 0x250 host port configure register */
u8 res6[0x10];
u32 csel; /* 0x2e0 controller select register */
};
struct dram_para {
u32 clock;
u32 type;
u32 rank_num;
u32 density;
u32 io_width;
u32 bus_width;
u32 cas;
u32 zq;
u32 odt_en;
u32 size;
u32 tpr0;
u32 tpr1;
u32 tpr2;
u32 tpr3;
u32 tpr4;
u32 tpr5;
u32 emr1;
u32 emr2;
u32 emr3;
};
unsigned long dramc_init(struct dram_para *para);
#endif /* CPU_ALLWINNER_A10_DRAMC_H */

View File

@ -1,109 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
*
* 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; 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.
*
* Basic GPIO helpers for Allwinner CPUs
*/
#include "gpio.h"
#include <device/mmio.h>
static struct a10_gpio *const gpio = (void *)GPIO_BASE;
/**
* \brief Set a single output pin
*
* @param[in] port GPIO port of the pin (GPA -> GPS)
* @param[in] pin the pin number in the given port (1 -> 31)
*/
void gpio_set(u8 port, u8 pin)
{
u32 reg32;
if ((port > GPS))
return;
reg32 = gpio_read(port);
reg32 |= (1 << pin);
gpio_write(port, reg32);
}
/**
* \brief Clear a single output pin
*
* @param[in] port GPIO port of the pin (GPA -> GPS)
* @param[in] pin the pin number in the given port (1 -> 31)
*/
void gpio_clear(u8 port, u8 pin)
{
u32 reg32;
if ((port > GPS))
return;
reg32 = gpio_read(port);
reg32 &= ~(1 << pin);
gpio_write(port, reg32);
}
/**
* \brief Get the status of a single input pin
*
* @param[in] port GPIO port of the pin (GPA -> GPS)
* @param[in] pin the pin number in the given port (1 -> 31)
* @return 1 if the pin is high, or 0 if the pin is low
*/
int gpio_get(u8 port, u8 pin)
{
if ((port > GPS))
return 0;
return (gpio_read(port) & (1 << pin)) ? 1 : 0;
}
/**
* \brief Write to a GPIO port
*
* Write the state of all output pins in the GPIO port. This only affects pins
* configured as output pins.
*
* @param[in] port GPIO port of the pin (GPA -> GPS)
* @param[in] val 32-bit mask indicating which pins to set. For a set bit, the
* corresponding pin will be set. Otherwise, it will be cleared
*/
void gpio_write(u8 port, u32 val)
{
if ((port > GPS))
return;
write32(&gpio->port[port].dat, val);
}
/**
* \brief Write to a GPIO port
*
* Read the state of all input pins in the GPIO port.
*
* @param[in] port GPIO port of the pin (GPA -> GPS)
* @return 32-bit mask indicating which pins are high. For each set bit, the
* corresponding pin is high. The value of bits corresponding to pins
* which are not configured as inputs is undefined.
*/
u32 gpio_read(u8 port)
{
if ((port > GPS))
return 0;
return read32(&gpio->port[port].dat);
}

View File

@ -1,74 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
*
* 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; version 2 of the License or (at your option)
* any later version.
*
* 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.
*
* Definitions for GPIO and pin multiplexing on Allwinner CPUs
*/
#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
/* GPIO pad functions valid for all pins */
#define GPIO_PIN_FUNC_INPUT 0
#define GPIO_PIN_FUNC_OUTPUT 1
struct a10_gpio_port {
u32 cfg[4];
u32 dat;
u32 drv[2];
u32 pul[2];
} __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;
} __packed;
/* gpio.c */
void gpio_set(u8 port, u8 pin);
void gpio_clear(u8 port, u8 pin);
int gpio_get(u8 port, u8 pin);
void gpio_write(u8 port, u32 val);
u32 gpio_read(u8 port);
/* pinmux.c */
void gpio_set_pin_func(u8 port, u8 pin, u8 pad_func);
void gpio_set_multipin_func(u8 port, u32 pin_mask, u8 pad_func);
#endif /* __CPU_ALLWINNER_A10_PINMUX_H */

View File

@ -1,128 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2007-2011 Allwinner Technology Co., Ltd.
* Tom Cubie <tangliang@allwinnertech.com>
* Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
*
* 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; 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.
*
* Memory map definitions for Allwinner A10 CPUs
*/
#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

@ -1,92 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
*
* 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; 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.
*
*
* Helpers to multiplex and configure pins on Allwinner SoCs
*
*/
#include "gpio.h"
#include <device/mmio.h>
static struct a10_gpio *const gpio = (void *)GPIO_BASE;
/**
* \brief Set the pad function of a single pin
*
* @param[in] port GPIO port of the pin (GPA -> GPS)
* @param[in] pin the pin number in the given port (1 -> 31)
* @param[in] pad_func The peripheral function to which to connect this pin
*/
void gpio_set_pin_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(&gpio->port[port].cfg[reg], reg32);
}
/**
* \brief Set the pad function of a group of pins
*
* Multiplex a group of pins to the same pad function. This is useful for
* peripherals that use the same function number for several pins. This function
* allows those pins to be set with a single call.
*
* Example:
* gpio_set_multipin_func(GPB, (1 << 23) | (1 << 22), 2);
*
* @param[in] port GPIO port of the pin (GPA -> GPS)
* @param[in] pin_mask 32-bit mask indicating which pins to re-multiplex. For
* each set bit, the corresponding pin will be multiplexed.
* @param[in] pad_func The peripheral function to which to connect the pins
*/
void gpio_set_multipin_func(u8 port, u32 pin_mask, u8 pad_func)
{
int j;
u8 reg, bit;
u32 reg32, mask_offset;
if ((port > GPS))
return;
for (reg = 0; reg < 4; reg++) {
mask_offset = 8 * reg;
/* Don't run the inner loop if we're not touching any pins */
if (!(pin_mask & (0xff << mask_offset)))
continue;
reg32 = read32(&gpio->port[port].cfg[reg]);
for (j = 0; j < 8; j++) {
if (!(pin_mask & (1 << (j + mask_offset))))
continue;
bit = j * 4;
reg32 &= ~(0xf << bit);
reg32 |= (pad_func & 0xf) << bit;
}
write32(&gpio->port[port].cfg[reg], reg32);
}
}

View File

@ -1,42 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2014 Alexandru Gagniuc <mr.nuke.me@gmail.com>
*
* 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; 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.
*
*
* How we use DRAM on Allwinner CPUs
*/
#include <symbols.h>
/*
* Put CBMEM at top of RAM
*/
static inline void *a1x_get_cbmem_top(void)
{
return _dram + (CONFIG_DRAM_SIZE_MB << 20);
}
/*
* By CBFS cache, we mean a cached copy, in RAM, of the entire CBFS region.
*/
static inline void *a1x_get_cbfs_cache_top(void)
{
/* Arbitrary 16 MiB gap for cbmem tables and bouncebuffer */
return a1x_get_cbmem_top() - (16 << 20);
}
static inline void *a1x_get_cbfs_cache_base(void)
{
return a1x_get_cbfs_cache_top() - CONFIG_ROM_SIZE;
}

View File

@ -1,478 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2012 Henrik Nordstrom <henrik@henriknordstrom.net>
* Copyright (C) 2013 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
* Copyright (C) 2007-2012 Allwinner Technology Co., Ltd.
* Berg Xing <bergxing@allwinnertech.com>
* Tom Cubie <tangliang@allwinnertech.com>
* Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
*
* 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; 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.
*
* Allwinner A10 DRAM controller initialization
*
* Based on sun4i Linux kernel sources mach-sunxi/pm/standby/dram*.c
* and earlier U-Boot Allwiner A10 SPL work
*/
#include "clock.h"
#include "dramc.h"
#include "memmap.h"
#include "timer.h"
#include <device/mmio.h>
#include <delay.h>
static struct a1x_dramc *const dram = (void *)A1X_DRAMC_BASE;
static void mctl_ddr3_reset(void)
{
if (a1x_get_cpu_chip_revision() != A1X_CHIP_REV_A) {
setbits_le32(&dram->mcr, DRAM_MCR_RESET);
udelay(2);
clrbits_le32(&dram->mcr, DRAM_MCR_RESET);
} else {
clrbits_le32(&dram->mcr, DRAM_MCR_RESET);
udelay(2);
setbits_le32(&dram->mcr, DRAM_MCR_RESET);
}
}
static void mctl_set_drive(void)
{
clrsetbits_le32(&dram->mcr, DRAM_MCR_MODE_NORM(0x3),
DRAM_MCR_MODE_EN(0x3) | 0xffc);
}
static void mctl_itm_disable(void)
{
clrsetbits_le32(&dram->ccr, DRAM_CCR_INIT, DRAM_CCR_ITM_OFF);
}
static void mctl_itm_enable(void)
{
clrbits_le32(&dram->ccr, DRAM_CCR_ITM_OFF);
}
static void mctl_enable_dll0(u32 phase)
{
clrsetbits_le32(&dram->dllcr[0], 0x3f << 6,
((phase >> 16) & 0x3f) << 6);
clrsetbits_le32(&dram->dllcr[0], DRAM_DLLCR_NRESET, DRAM_DLLCR_DISABLE);
udelay(2);
clrbits_le32(&dram->dllcr[0], DRAM_DLLCR_NRESET | DRAM_DLLCR_DISABLE);
udelay(22);
clrsetbits_le32(&dram->dllcr[0], DRAM_DLLCR_DISABLE, DRAM_DLLCR_NRESET);
udelay(22);
}
/*
* Note: This differs from pm/standby in that it checks the bus width
*/
static void mctl_enable_dllx(u32 phase)
{
u32 i, n, bus_width;
bus_width = read32(&dram->dcr);
if ((bus_width & DRAM_DCR_BUS_WIDTH_MASK) ==
DRAM_DCR_BUS_WIDTH(DRAM_DCR_BUS_WIDTH_32BIT))
n = DRAM_DCR_NR_DLLCR_32BIT;
else
n = DRAM_DCR_NR_DLLCR_16BIT;
for (i = 1; i < n; i++) {
clrsetbits_le32(&dram->dllcr[i], 0x4 << 14,
(phase & 0xf) << 14);
clrsetbits_le32(&dram->dllcr[i], DRAM_DLLCR_NRESET,
DRAM_DLLCR_DISABLE);
phase >>= 4;
}
udelay(2);
for (i = 1; i < n; i++)
clrbits_le32(&dram->dllcr[i], DRAM_DLLCR_NRESET |
DRAM_DLLCR_DISABLE);
udelay(22);
for (i = 1; i < n; i++)
clrsetbits_le32(&dram->dllcr[i], DRAM_DLLCR_DISABLE,
DRAM_DLLCR_NRESET);
udelay(22);
}
static u32 hpcr_value[32] = {
0x0301, 0x0301, 0x0301, 0x0301,
0x0301, 0x0301, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0x1031, 0x1031, 0x0735, 0x1035,
0x1035, 0x0731, 0x1031, 0x0735,
0x1035, 0x1031, 0x0731, 0x1035,
0x1031, 0x0301, 0x0301, 0x0731
};
static void mctl_configure_hostport(void)
{
u32 i;
for (i = 0; i < 32; i++)
write32(&dram->hpcr[i], hpcr_value[i]);
}
static void mctl_setup_dram_clock(u32 clk)
{
/* setup DRAM PLL */
a1x_pll5_configure(clk / 24, 2, 2, 1);
/* FIXME: This bit is not documented for A10, and altering it doesn't
* seem to change anything.
*
* #define CCM_PLL5_CTRL_VCO_GAIN (0x1 << 19)
* reg_val = read32(&ccm->pll5_cfg);
* reg_val &= ~CCM_PLL5_CTRL_VCO_GAIN; // PLL VCO Gain off
* write32(reg_val, &ccm->pll5_cfg);
*/
udelay(5500);
a1x_pll5_enable_dram_clock_output();
/* reset GPS */
/* FIXME: These bits are also undocumented, and seem to have no effect
* on A10.
*
* #define CCM_GPS_CTRL_RESET (0x1 << 0)
* #define CCM_GPS_CTRL_GATE (0x1 << 1)
* clrbits_le32(&ccm->gps_clk_cfg, CCM_GPS_CTRL_RESET | CCM_GPS_CTRL_GATE);
*/
a1x_periph_clock_enable(A1X_CLKEN_GPS);
udelay(1);
a1x_periph_clock_disable(A1X_CLKEN_GPS);
/* setup MBUS clock */
/* FIXME: The MBUS does not seem to be present or do anything on A10. It
* is documented in the A13 user manual, but changing settings on A10
* has no effect.
*
* #define CCM_MBUS_CTRL_M(n) (((n) & 0xf) << 0)
* #define CCM_MBUS_CTRL_M_MASK CCM_MBUS_CTRL_M(0xf)
* #define CCM_MBUS_CTRL_M_X(n) ((n) - 1)
* #define CCM_MBUS_CTRL_N(n) (((n) & 0xf) << 16)
* #define CCM_MBUS_CTRL_N_MASK CCM_MBUS_CTRL_N(0xf)
* #define CCM_MBUS_CTRL_N_X(n) (((n) >> 3) ? 3 : (((n) >> 2) ? 2 : (((n) >> 1) ? 1 : 0)))
* #define CCM_MBUS_CTRL_CLK_SRC(n) (((n) & 0x3) << 24)
* #define CCM_MBUS_CTRL_CLK_SRC_MASK CCM_MBUS_CTRL_CLK_SRC(0x3)
* #define CCM_MBUS_CTRL_CLK_SRC_HOSC 0x0
* #define CCM_MBUS_CTRL_CLK_SRC_PLL6 0x1
* #define CCM_MBUS_CTRL_CLK_SRC_PLL5 0x2
* #define CCM_MBUS_CTRL_GATE (0x1 << 31)
* reg_val = CCM_MBUS_CTRL_GATE |
* CCM_MBUS_CTRL_CLK_SRC(CCM_MBUS_CTRL_CLK_SRC_PLL5) |
* CCM_MBUS_CTRL_N(CCM_MBUS_CTRL_N_X(1)) |
* CCM_MBUS_CTRL_M(CCM_MBUS_CTRL_M_X(2));
* write32(reg_val, &ccm->mbus_clk_cfg);
*/
/*
* open DRAMC AHB & DLL register clock
* close it first
*/
a1x_periph_clock_disable(A1X_CLKEN_SDRAM);
udelay(22);
/* then open it */
a1x_periph_clock_enable(A1X_CLKEN_SDRAM);
udelay(22);
}
static int dramc_scan_readpipe(void)
{
u32 reg32;
/* data training trigger */
setbits_le32(&dram->ccr, DRAM_CCR_DATA_TRAINING);
/* check whether data training process has completed */
while (read32(&dram->ccr) & DRAM_CCR_DATA_TRAINING);
/* check data training result */
reg32 = read32(&dram->csr);
if (reg32 & DRAM_CSR_FAILED)
return -1;
return 0;
}
static int dramc_scan_dll_para(void)
{
const u32 dqs_dly[7] = { 0x3, 0x2, 0x1, 0x0, 0xe, 0xd, 0xc };
const u32 clk_dly[15] = { 0x07, 0x06, 0x05, 0x04, 0x03,
0x02, 0x01, 0x00, 0x08, 0x10,
0x18, 0x20, 0x28, 0x30, 0x38
};
u32 clk_dqs_count[15];
u32 dqs_i, clk_i, cr_i;
u32 max_val, min_val;
u32 dqs_index, clk_index;
/* Find DQS_DLY Pass Count for every CLK_DLY */
for (clk_i = 0; clk_i < 15; clk_i++) {
clk_dqs_count[clk_i] = 0;
clrsetbits_le32(&dram->dllcr[0], 0x3f << 6,
(clk_dly[clk_i] & 0x3f) << 6);
for (dqs_i = 0; dqs_i < 7; dqs_i++) {
for (cr_i = 1; cr_i < 5; cr_i++) {
clrsetbits_le32(&dram->dllcr[cr_i],
0x4f << 14,
(dqs_dly[dqs_i] & 0x4f) << 14);
}
udelay(2);
if (dramc_scan_readpipe() == 0)
clk_dqs_count[clk_i]++;
}
}
/* Test DQS_DLY Pass Count for every CLK_DLY from up to down */
for (dqs_i = 15; dqs_i > 0; dqs_i--) {
max_val = 15;
min_val = 15;
for (clk_i = 0; clk_i < 15; clk_i++) {
if (clk_dqs_count[clk_i] == dqs_i) {
max_val = clk_i;
if (min_val == 15)
min_val = clk_i;
}
}
if (max_val < 15)
break;
}
/* Check if Find a CLK_DLY failed */
if (!dqs_i)
goto fail;
/* Find the middle index of CLK_DLY */
clk_index = (max_val + min_val) >> 1;
if ((max_val == (15 - 1)) && (min_val > 0))
/* if CLK_DLY[MCTL_CLK_DLY_COUNT] is very good, then the middle
* value can be more close to the max_val
*/
clk_index = (15 + clk_index) >> 1;
else if ((max_val < (15 - 1)) && (min_val == 0))
/* if CLK_DLY[0] is very good, then the middle value can be more
* close to the min_val
*/
clk_index >>= 1;
if (clk_dqs_count[clk_index] < dqs_i)
clk_index = min_val;
/* Find the middle index of DQS_DLY for the CLK_DLY got above, and Scan
* read pipe again
*/
clrsetbits_le32(&dram->dllcr[0], 0x3f << 6,
(clk_dly[clk_index] & 0x3f) << 6);
max_val = 7;
min_val = 7;
for (dqs_i = 0; dqs_i < 7; dqs_i++) {
clk_dqs_count[dqs_i] = 0;
for (cr_i = 1; cr_i < 5; cr_i++) {
clrsetbits_le32(&dram->dllcr[cr_i],
0x4f << 14,
(dqs_dly[dqs_i] & 0x4f) << 14);
}
udelay(2);
if (dramc_scan_readpipe() == 0) {
clk_dqs_count[dqs_i] = 1;
max_val = dqs_i;
if (min_val == 7)
min_val = dqs_i;
}
}
if (max_val < 7) {
dqs_index = (max_val + min_val) >> 1;
if ((max_val == (7 - 1)) && (min_val > 0))
dqs_index = (7 + dqs_index) >> 1;
else if ((max_val < (7 - 1)) && (min_val == 0))
dqs_index >>= 1;
if (!clk_dqs_count[dqs_index])
dqs_index = min_val;
for (cr_i = 1; cr_i < 5; cr_i++) {
clrsetbits_le32(&dram->dllcr[cr_i],
0x4f << 14,
(dqs_dly[dqs_index] & 0x4f) << 14);
}
udelay(2);
return dramc_scan_readpipe();
}
fail:
clrbits_le32(&dram->dllcr[0], 0x3f << 6);
for (cr_i = 1; cr_i < 5; cr_i++)
clrbits_le32(&dram->dllcr[cr_i], 0x4f << 14);
udelay(2);
return dramc_scan_readpipe();
}
static void dramc_set_autorefresh_cycle(u32 clk)
{
u32 reg32;
u32 tmp_val;
u32 reg_dcr;
if (clk < 600) {
reg_dcr = read32(&dram->dcr);
if ((reg_dcr & DRAM_DCR_CHIP_DENSITY_MASK) <=
DRAM_DCR_CHIP_DENSITY(DRAM_DCR_CHIP_DENSITY_1024M))
reg32 = (131 * clk) >> 10;
else
reg32 = (336 * clk) >> 10;
tmp_val = (7987 * clk) >> 10;
tmp_val = tmp_val * 9 - 200;
reg32 |= tmp_val << 8;
reg32 |= 0x8 << 24;
write32(&dram->drr, reg32);
} else {
write32(&dram->drr, 0x0);
}
}
unsigned long dramc_init(struct dram_para *para)
{
u32 reg32;
int ret_val;
/* check input dram parameter structure */
if (!para)
return 0;
/* setup DRAM relative clock */
mctl_setup_dram_clock(para->clock);
/* reset external DRAM */
mctl_ddr3_reset();
mctl_set_drive();
/* dram clock off */
a1x_gate_dram_clock_output();
/* select dram controller 1 */
write32(&dram->csel, DRAM_CSEL_MAGIC);
mctl_itm_disable();
mctl_enable_dll0(para->tpr3);
/* configure external DRAM */
reg32 = 0x0;
if (para->type == DRAM_MEMORY_TYPE_DDR3)
reg32 |= DRAM_DCR_TYPE_DDR3;
reg32 |= DRAM_DCR_IO_WIDTH(para->io_width >> 3);
if (para->density == 256)
reg32 |= DRAM_DCR_CHIP_DENSITY(DRAM_DCR_CHIP_DENSITY_256M);
else if (para->density == 512)
reg32 |= DRAM_DCR_CHIP_DENSITY(DRAM_DCR_CHIP_DENSITY_512M);
else if (para->density == 1024)
reg32 |= DRAM_DCR_CHIP_DENSITY(DRAM_DCR_CHIP_DENSITY_1024M);
else if (para->density == 2048)
reg32 |= DRAM_DCR_CHIP_DENSITY(DRAM_DCR_CHIP_DENSITY_2048M);
else if (para->density == 4096)
reg32 |= DRAM_DCR_CHIP_DENSITY(DRAM_DCR_CHIP_DENSITY_4096M);
else if (para->density == 8192)
reg32 |= DRAM_DCR_CHIP_DENSITY(DRAM_DCR_CHIP_DENSITY_8192M);
else
reg32 |= DRAM_DCR_CHIP_DENSITY(DRAM_DCR_CHIP_DENSITY_256M);
reg32 |= DRAM_DCR_BUS_WIDTH((para->bus_width >> 3) - 1);
reg32 |= DRAM_DCR_RANK_SEL(para->rank_num - 1);
reg32 |= DRAM_DCR_CMD_RANK_ALL;
reg32 |= DRAM_DCR_MODE(DRAM_DCR_MODE_INTERLEAVE);
write32(&dram->dcr, reg32);
/* dram clock on */
a1x_ungate_dram_clock_output();
udelay(1);
while (read32(&dram->ccr) & DRAM_CCR_INIT);
mctl_enable_dllx(para->tpr3);
/* set odt impendance divide ratio */
reg32 = ((para->zq) >> 8) & 0xfffff;
reg32 |= ((para->zq) & 0xff) << 20;
reg32 |= (para->zq) & 0xf0000000;
write32(&dram->zqcr0, reg32);
/* set I/O configure register */
reg32 = 0x00cc0000;
reg32 |= (para->odt_en) & 0x3;
reg32 |= ((para->odt_en) & 0x3) << 30;
write32(&dram->iocr, reg32);
/* set refresh period */
dramc_set_autorefresh_cycle(para->clock);
/* set timing parameters */
write32(&dram->tpr0, para->tpr0);
write32(&dram->tpr1, para->tpr1);
write32(&dram->tpr2, para->tpr2);
if (para->type == DRAM_MEMORY_TYPE_DDR3) {
reg32 = DRAM_MR_BURST_LENGTH(0x0);
reg32 |= DRAM_MR_CAS_LAT(para->cas - 4);
reg32 |= DRAM_MR_WRITE_RECOVERY(0x5);
} else if (para->type == DRAM_MEMORY_TYPE_DDR2) {
reg32 = DRAM_MR_BURST_LENGTH(0x2);
reg32 |= DRAM_MR_CAS_LAT(para->cas);
reg32 |= DRAM_MR_WRITE_RECOVERY(0x5);
}
write32(&dram->mr, reg32);
write32(&dram->emr, para->emr1);
write32(&dram->emr2, para->emr2);
write32(&dram->emr3, para->emr3);
/* set DQS window mode */
clrsetbits_le32(&dram->ccr, DRAM_CCR_DQS_DRIFT_COMP, DRAM_CCR_DQS_GATE);
/* reset external DRAM */
setbits_le32(&dram->ccr, DRAM_CCR_INIT);
while (read32(&dram->ccr) & DRAM_CCR_INIT);
/* scan read pipe value */
mctl_itm_enable();
if (para->tpr3 & (0x1 << 31)) {
ret_val = dramc_scan_dll_para();
if (ret_val == 0)
para->tpr3 =
(((read32(&dram->dllcr[0]) >> 6) & 0x3f) << 16) |
(((read32(&dram->dllcr[1]) >> 14) & 0xf) << 0) |
(((read32(&dram->dllcr[2]) >> 14) & 0xf) << 4) |
(((read32(&dram->dllcr[3]) >> 14) & 0xf) << 8) |
(((read32(&dram->dllcr[4]) >> 14) & 0xf) << 12);
} else {
ret_val = dramc_scan_readpipe();
}
if (ret_val < 0)
return 0;
/* configure all host port */
mctl_configure_hostport();
return para->size;
}

View File

@ -1,77 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
*
* 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; 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.
*
* Timer control and delays for Allwinner CPUs
*
*/
#include <device/mmio.h>
#include <delay.h>
#include "timer.h"
struct a1x_timer_module *const timer_module = (void *)A1X_TIMER_BASE;
struct a1x_timer *const tmr0 =
&((struct a1x_timer_module *)A1X_TIMER_BASE)->timer[0];
static inline u32 read_timer(void)
{
return read32(&tmr0->val);
}
void init_timer(void)
{
u32 reg32;
/* Load the timer rollover value */
write32(&tmr0->interval, 0xffffffff);
/* Configure the timer to run from 24MHz oscillator, no prescaler */
reg32 = TIMER_CTRL_PRESC_DIV_EXP(0);
reg32 |= TIMER_CTRL_CLK_SRC_OSC24M;
reg32 |= TIMER_CTRL_RELOAD;
reg32 |= TIMER_CTRL_TMR_EN;
write32(&tmr0->ctrl, reg32);
}
void udelay(unsigned usec)
{
u32 curr_tick, last_tick;
s32 ticks_left;
last_tick = read_timer();
/* 24 timer ticks per microsecond (24 MHz, divided by 1) */
ticks_left = usec * 24;
/* FIXME: Should we consider timer rollover?
* From when we start the timer, we have almost three minutes before it
* rolls over, so we should be long into having booted our payload.
*/
while (ticks_left > 0) {
curr_tick = read_timer();
/* Timer value decreases with each tick */
ticks_left -= last_tick - curr_tick;
last_tick = curr_tick;
}
}
/*
* This function has nothing to do with timers; however, the chip revision
* register is in the timer module, so keep this function here.
*/
u8 a1x_get_cpu_chip_revision(void)
{
write32(&timer_module->cpu_cfg, 0);
return (read32(&timer_module->cpu_cfg) >> 6) & 0x3;
}

View File

@ -1,110 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2007-2011 Allwinner Technology Co., Ltd.
* Tom Cubie <tangliang@allwinnertech.com>
* Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
*
* 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; 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.
*
* Definitions for timer control on Allwinner CPUs
*/
#ifndef CPU_ALLWINNER_A10_TIMER_H
#define CPU_ALLWINNER_A10_TIMER_H
#include "memmap.h"
#include <types.h>
/* TMRx_CTRL values */
#define TIMER_CTRL_MODE_SINGLE (1 << 7)
#define TIMER_CTRL_PRESC_MASK (0x7 << 4)
#define TIMER_CTRL_PRESC_DIV_EXP(ep) ((ep << 4) & TIMER_CTRL_PRESC_MASK)
#define TIMER_CTRL_CLK_SRC_MASK (0x3 << 2)
#define TIMER_CTRL_CLK_SRC_LOSC (0x0 << 2)
#define TIMER_CTRL_CLK_SRC_OSC24M (0x1 << 2)
#define TIMER_CTRL_CLK_SRC_PLL6 (0x2 << 2)
#define TIMER_CTRL_RELOAD (1 << 1)
#define TIMER_CTRL_TMR_EN (1 << 0)
/* Chip revision definitions (found in CPU_CFG register) */
#define A1X_CHIP_REV_A 0x0
#define A1X_CHIP_REV_C1 0x1
#define A1X_CHIP_REV_C2 0x2
#define A1X_CHIP_REV_B 0x3
/* General purpose timer */
struct a1x_timer {
u32 ctrl;
u32 interval;
u32 val;
u8 res[4];
} __packed;
/* Audio video sync*/
struct a1x_avs {
u32 ctrl; /* 0x80 */
u32 cnt0; /* 0x84 */
u32 cnt1; /* 0x88 */
u32 div; /* 0x8c */
} __packed;
/* Watchdog */
struct a1x_wdog {
u32 ctrl; /* 0x90 */
u32 mode; /* 0x94 */
} __packed;
/* 64 bit counter */
struct a1x_64cnt {
u32 ctrl; /* 0xa0 */
u32 lo; /* 0xa4 */
u32 hi; /* 0xa8 */
} __packed;
/* Rtc */
struct a1x_rtc {
u32 ctrl; /* 0x100 */
u32 yymmdd; /* 0x104 */
u32 hhmmss; /* 0x108 */
} __packed;
/* Alarm */
struct a1x_alarm {
u32 ddhhmmss; /* 0x10c */
u32 hhmmss; /* 0x110 */
u32 en; /* 0x114 */
u32 irq_en; /* 0x118 */
u32 irq_sta; /* 0x11c */
} __packed;
struct a1x_timer_module {
u32 irq_en; /* 0x00 */
u32 irq_sta; /* 0x04 */
u8 res1[8];
struct a1x_timer timer[6]; /* We have 6 timers */
u8 res2[16];
struct a1x_avs avs;
struct a1x_wdog wdog;
u8 res3[8];
struct a1x_64cnt cnt64;
u8 res4[0x58];
struct a1x_rtc rtc;
struct a1x_alarm alarm;
u32 gp_data[4];
u8 res5[8];
u32 cpu_cfg;
} __packed;
u8 a1x_get_cpu_chip_revision(void);
#endif /* CPU_ALLWINNER_A10_TIMER_H */

View File

@ -1,217 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2012 Henrik Nordstrom <henrik@henriknordstrom.net>
* Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
*
* 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; 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.
*
* Setup helpers for Two Wire Interface (TWI) (I2C) Allwinner CPUs
*
* Only functionality for I2C master is provided.
* Largely based on the uboot-sunxi code.
*/
#include <device/mmio.h>
#include <delay.h>
#include <device/i2c_simple.h>
#include <types.h>
#include "memmap.h"
#include "twi.h"
#define TWI_BASE(n) (A1X_TWI0_BASE + 0x400 * (n))
#define TWI_TIMEOUT (50 * 1000)
static u8 is_busy(struct a1x_twi *twi)
{
return (read32(&twi->stat) != TWI_STAT_IDLE);
}
static enum cb_err wait_until_idle(struct a1x_twi *twi)
{
u32 i = TWI_TIMEOUT;
while (i-- && is_busy((twi)))
udelay(1);
return i ? CB_SUCCESS : CB_ERR;
}
/* FIXME: This function is basic, and unintelligent */
static void configure_clock(struct a1x_twi *twi, u32 speed_hz)
{
/* FIXME: We assume clock is 24MHz, which may not be the case */
u32 apb_clk = 24000000, m, n;
/* Pre-divide the clock by 8 */
n = 3;
m = (apb_clk >> n) / speed_hz;
write32(&twi->clk, TWI_CLK_M(m) | TWI_CLK_N(n));
}
void a1x_twi_init(u8 bus, u32 speed_hz)
{
u32 i = TWI_TIMEOUT;
struct a1x_twi *twi = (void *)TWI_BASE(bus);
configure_clock(twi, speed_hz);
/* Enable the I2C bus */
write32(&twi->ctl, TWI_CTL_BUS_EN);
/* Issue soft reset */
write32(&twi->reset, 1);
while (i-- && read32(&twi->reset))
udelay(1);
}
static void clear_interrupt_flag(struct a1x_twi *twi)
{
write32(&twi->ctl, read32(&twi->ctl) & ~TWI_CTL_INT_FLAG);
}
static void i2c_send_data(struct a1x_twi *twi, u8 data)
{
write32(&twi->data, data);
clear_interrupt_flag(twi);
}
static enum twi_status wait_for_status(struct a1x_twi *twi)
{
u32 i = TWI_TIMEOUT;
/* Wait until interrupt is asserted again */
while (i-- && !(read32(&twi->ctl) & TWI_CTL_INT_FLAG))
udelay(1);
/* A timeout here most likely indicates a bus error */
return i ? read32(&twi->stat) : TWI_STAT_BUS_ERROR;
}
static void i2c_send_start(struct a1x_twi *twi)
{
u32 reg32, i;
/* Send START condition */
reg32 = read32(&twi->ctl);
reg32 &= ~TWI_CTL_INT_FLAG;
reg32 |= TWI_CTL_M_START;
write32(&twi->ctl, reg32);
/* M_START is automatically cleared after condition is transmitted */
i = TWI_TIMEOUT;
while (i-- && (read32(&twi->ctl) & TWI_CTL_M_START))
udelay(1);
}
static void i2c_send_stop(struct a1x_twi *twi)
{
u32 reg32;
/* Send STOP condition */
reg32 = read32(&twi->ctl);
reg32 &= ~TWI_CTL_INT_FLAG;
reg32 |= TWI_CTL_M_STOP;
write32(&twi->ctl, reg32);
}
static int i2c_read(struct a1x_twi *twi, uint8_t chip,
uint8_t *buf, size_t len)
{
unsigned count = len;
enum twi_status expected_status;
/* Send restart for read */
i2c_send_start(twi);
if (wait_for_status(twi) != TWI_STAT_TX_RSTART)
return CB_ERR;
/* Send chip address */
i2c_send_data(twi, chip << 1 | 1);
if (wait_for_status(twi) != TWI_STAT_TX_AR_ACK)
return CB_ERR;
/* Start ACK-ing received data */
setbits_le32(&twi->ctl, TWI_CTL_A_ACK);
expected_status = TWI_STAT_RXD_ACK;
/* Read data */
while (count > 0) {
if (count == 1) {
/* Do not ACK the last byte */
clrbits_le32(&twi->ctl, TWI_CTL_A_ACK);
expected_status = TWI_STAT_RXD_NAK;
}
clear_interrupt_flag(twi);
if (wait_for_status(twi) != expected_status)
return CB_ERR;
*buf++ = read32(&twi->data);
count--;
}
return len;
}
static int i2c_write(struct a1x_twi *twi, uint8_t chip,
const uint8_t *buf, size_t len)
{
size_t count = len;
i2c_send_start(twi);
if (wait_for_status(twi) != TWI_STAT_TX_START)
return CB_ERR;
/* Send chip address */
i2c_send_data(twi, chip << 1);
if (wait_for_status(twi) != TWI_STAT_TX_AW_ACK)
return CB_ERR;
/* Send data */
while (count > 0) {
i2c_send_data(twi, *buf++);
if (wait_for_status(twi) != TWI_STAT_TXD_ACK)
return CB_ERR;
count--;
}
return len;
}
int platform_i2c_transfer(unsigned bus, struct i2c_msg *segments, int count)
{
int i, ret = CB_SUCCESS;
struct i2c_msg *seg = segments;
struct a1x_twi *twi = (void *)TWI_BASE(bus);
if (wait_until_idle(twi) != CB_SUCCESS)
return CB_ERR;
for (i = 0; i < count; i++) {
seg = segments + i;
if (seg->flags & I2C_M_RD) {
ret = i2c_read(twi, seg->slave, seg->buf, seg->len);
if (ret < 0)
break;
} else {
ret = i2c_write(twi, seg->slave, seg->buf, seg->len);
if (ret < 0)
break;
}
}
/* Don't worry about the status. STOP is on a best-effort basis */
i2c_send_stop(twi);
return ret;
}

View File

@ -1,69 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
*
* 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; 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.
*
* Definitions Two Wire Interface (TWI) (I2C) Allwinner CPUs
*/
#ifndef CPU_ALLWINNER_A10_TWI_H
#define CPU_ALLWINNER_A10_TWI_H
#include <types.h>
/* TWI_CTL values */
#define TWI_CTL_INT_EN (1 << 7)
#define TWI_CTL_BUS_EN (1 << 6)
#define TWI_CTL_M_START (1 << 5)
#define TWI_CTL_M_STOP (1 << 4)
#define TWI_CTL_INT_FLAG (1 << 3)
#define TWI_CTL_A_ACK (1 << 2)
/* TWI_STAT values */
enum twi_status {
TWI_STAT_BUS_ERROR = 0x00, /**< Bus error */
TWI_STAT_TX_START = 0x08, /**< START sent */
TWI_STAT_TX_RSTART = 0x10, /**< Repeated START sent */
TWI_STAT_TX_AW_ACK = 0x18, /**< Sent address+read, ACK */
TWI_STAT_TX_AW_NAK = 0x20, /**< Sent address+read, NAK */
TWI_STAT_TXD_ACK = 0x28, /**< Sent data, got ACK */
TWI_STAT_TXD_NAK = 0x30, /**< Sent data, no ACK */
TWI_STAT_LOST_ARB = 0x38, /**< Lost arbitration */
TWI_STAT_TX_AR_ACK = 0x40, /**< Sent address+write, ACK */
TWI_STAT_TX_AR_NAK = 0x48, /**< Sent address+write, NAK */
TWI_STAT_RXD_ACK = 0x50, /**< Got data, sent ACK */
TWI_STAT_RXD_NAK = 0x58, /**< Got data, no ACK */
TWI_STAT_IDLE = 0xf8, /**< Bus idle*/
};
/* TWI_CLK values */
#define TWI_CLK_M_MASK (0xf << 3)
#define TWI_CLK_M(m) (((m - 1) << 3) & TWI_CLK_M_MASK)
#define TWI_CLK_N_MASK (0x7 << 0)
#define TWI_CLK_N(n) ((n) & TWI_CLK_N_MASK)
struct a1x_twi {
u32 addr; /**< 0x00: Slave address */
u32 xaddr; /**< 0x04: Extended slave address */
u32 data; /**< 0x08: Data byte */
u32 ctl; /**< 0x0C: Control register */
u32 stat; /**< 0x10: Status register */
u32 clk; /**< 0x14: Clock control register */
u32 reset; /**< 0x18: Software reset */
u32 efr; /**< 0x1C: Enhanced Feature register */
u32 lcr; /**< 0x20: Line control register */
};
void a1x_twi_init(u8 bus, u32 speed_hz);
#endif /* CPU_ALLWINNER_A10_TWI_H */

View File

@ -1,125 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
*
* 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; version 2 of the License (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.
*
* Uart setup helpers for Allwinner SoCs
*
*
*/
#include "uart.h"
#include <device/mmio.h>
#include <console/uart.h>
#include <drivers/uart/uart8250reg.h>
/**
* \brief Configure line control settings for UART
*/
static void a10_uart_configure(struct a10_uart *uart, u32 baud_rate, u8 data_bits,
enum uart_parity parity, u8 stop_bits)
{
u32 reg32;
u16 div;
div = (u16) uart_baudrate_divisor(baud_rate,
uart_platform_refclk(), 16);
/* Enable access to Divisor Latch register */
write32(&uart->lcr, UART8250_LCR_DLAB);
/* Set baudrate */
write32(&uart->dlh, (div >> 8) & 0xff);
write32(&uart->dll, div & 0xff);
/* Set line control */
reg32 = (data_bits - 5) & UART8250_LCR_WLS_MSK;
switch (parity) {
case UART_PARITY_ODD:
reg32 |= UART8250_LCR_PEN;
break;
case UART_PARITY_EVEN:
reg32 |= UART8250_LCR_PEN;
reg32 |= UART8250_LCR_EPS;
break;
case UART_PARITY_NONE: /* Fall through */
default:
break;
}
write32(&uart->lcr, reg32);
}
static void a10_uart_enable_fifos(struct a10_uart *uart)
{
write32(&uart->fcr, UART8250_FCR_FIFO_EN);
}
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) & UART8250_LSR_THRE);
}
static int rx_fifo_empty(struct a10_uart *uart)
{
return !(read32(&uart->lsr) & UART8250_LSR_DR);
}
/**
* \brief Read a single byte from the UART.
*
* Blocks until at least a byte is available.
*/
static u8 a10_uart_rx_blocking(struct a10_uart *uart)
{
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.
*/
static void a10_uart_tx_blocking(struct a10_uart *uart, u8 data)
{
while (tx_fifo_full(uart));
return write32(&uart->thr, data);
}
void uart_init(int idx)
{
struct a10_uart *uart_base = uart_platform_baseptr(idx);
/* Use default 8N1 encoding */
a10_uart_configure(uart_base, get_uart_baudrate(),
8, UART_PARITY_NONE, 1);
a10_uart_enable_fifos(uart_base);
}
unsigned char uart_rx_byte(int idx)
{
return a10_uart_rx_blocking(uart_platform_baseptr(idx));
}
void uart_tx_byte(int idx, unsigned char data)
{
a10_uart_tx_blocking(uart_platform_baseptr(idx), data);
}
void uart_tx_flush(int idx)
{
}

View File

@ -1,82 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
*
* 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; 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.
*
* 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.
*
*/
#ifndef CPU_ALLWINNER_A10_UART_H
#define CPU_ALLWINNER_A10_UART_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 */
} __packed;
enum uart_parity {
UART_PARITY_NONE,
UART_PARITY_EVEN,
UART_PARITY_ODD,
};
#endif /* CPU_ALLWINNER_A10_UART_H */

View File

@ -1,55 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright 2013 Google Inc.
* Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
*
* 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; 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.
*
* Glue to UART code to enable serial console
*/
#include <types.h>
#include <console/uart.h>
#include <boot/coreboot_tables.h>
#include "memmap.h"
uintptr_t uart_platform_base(int idx)
{
/* UART blocks are mapped 0x400 bytes apart */
if (idx < 8)
return A1X_UART0_BASE + 0x400 * idx;
else
return 0;
}
/* FIXME: We assume clock is 24MHz, which may not be the case. */
unsigned int uart_platform_refclk(void)
{
return 24000000;
}
#ifndef __PRE_RAM__
void uart_fill_lb(void *data)
{
struct lb_serial serial;
serial.type = LB_SERIAL_TYPE_MEMORY_MAPPED;
serial.baseaddr = uart_platform_base(CONFIG_UART_FOR_CONSOLE);
serial.baud = get_uart_baudrate();
serial.regwidth = 1;
serial.input_hertz = uart_platform_refclk();
serial.uart_pci_addr = 0;
lb_add_serial(&serial, data);
lb_add_console(LB_TAG_CONSOLE_SERIAL8250MEM, data);
}
#endif