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:
parent
041200fae3
commit
c27f1c390a
|
@ -1 +0,0 @@
|
|||
source src/cpu/allwinner/a10/Kconfig
|
|
@ -1 +0,0 @@
|
|||
subdirs-$(CONFIG_CPU_ALLWINNER_A10) += a10
|
|
@ -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
|
|
@ -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, $^) $@
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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 {
|
||||
};
|
|
@ -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__ */
|
|
@ -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 */
|
|
@ -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,
|
||||
};
|
|
@ -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 */
|
|
@ -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);
|
||||
}
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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)
|
||||
{
|
||||
}
|
|
@ -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 */
|
|
@ -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
|
Loading…
Reference in New Issue