u-boot-brain/arch/arm/mach-sunxi/board.c

317 lines
9.5 KiB
C
Raw Normal View History

/*
* (C) Copyright 2012 Henrik Nordstrom <henrik@henriknordstrom.net>
*
* (C) Copyright 2007-2011
* Allwinner Technology Co., Ltd. <www.allwinnertech.com>
* Tom Cubie <tangliang@allwinnertech.com>
*
* Some init for sunxi platform.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <mmc.h>
#include <i2c.h>
#include <serial.h>
#ifdef CONFIG_SPL_BUILD
#include <spl.h>
#endif
#include <asm/gpio.h>
#include <asm/io.h>
#include <asm/arch/clock.h>
#include <asm/arch/gpio.h>
#include <asm/arch/spl.h>
#include <asm/arch/sys_proto.h>
#include <asm/arch/timer.h>
#include <asm/arch/tzpc.h>
#include <asm/arch/mmc.h>
#include <linux/compiler.h>
struct fel_stash {
uint32_t sp;
uint32_t lr;
uint32_t cpsr;
uint32_t sctlr;
uint32_t vbar;
uint32_t cr;
};
struct fel_stash fel_stash __attribute__((section(".data")));
#ifdef CONFIG_MACH_SUN50I
#include <asm/armv8/mmu.h>
static struct mm_region sunxi_mem_map[] = {
{
/* SRAM, MMIO regions */
.base = 0x0UL,
.size = 0x40000000UL,
.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
PTE_BLOCK_NON_SHARE
}, {
/* RAM */
.base = 0x40000000UL,
.size = 0x80000000UL,
.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
PTE_BLOCK_INNER_SHARE
}, {
/* List terminator */
0,
}
};
struct mm_region *mem_map = sunxi_mem_map;
#endif
static int gpio_init(void)
{
#if CONFIG_CONS_INDEX == 1 && defined(CONFIG_UART0_PORT_F)
#if defined(CONFIG_MACH_SUN4I) || defined(CONFIG_MACH_SUN7I)
/* disable GPB22,23 as uart0 tx,rx to avoid conflict */
sunxi_gpio_set_cfgpin(SUNXI_GPB(22), SUNXI_GPIO_INPUT);
sunxi_gpio_set_cfgpin(SUNXI_GPB(23), SUNXI_GPIO_INPUT);
#endif
#if defined(CONFIG_MACH_SUN8I)
sunxi_gpio_set_cfgpin(SUNXI_GPF(2), SUN8I_GPF_UART0);
sunxi_gpio_set_cfgpin(SUNXI_GPF(4), SUN8I_GPF_UART0);
#else
sunxi_gpio_set_cfgpin(SUNXI_GPF(2), SUNXI_GPF_UART0);
sunxi_gpio_set_cfgpin(SUNXI_GPF(4), SUNXI_GPF_UART0);
#endif
sunxi_gpio_set_pull(SUNXI_GPF(4), 1);
#elif CONFIG_CONS_INDEX == 1 && (defined(CONFIG_MACH_SUN4I) || defined(CONFIG_MACH_SUN7I))
sunxi_gpio_set_cfgpin(SUNXI_GPB(22), SUN4I_GPB_UART0);
sunxi_gpio_set_cfgpin(SUNXI_GPB(23), SUN4I_GPB_UART0);
sunxi_gpio_set_pull(SUNXI_GPB(23), SUNXI_GPIO_PULL_UP);
#elif CONFIG_CONS_INDEX == 1 && defined(CONFIG_MACH_SUN5I)
sunxi_gpio_set_cfgpin(SUNXI_GPB(19), SUN5I_GPB_UART0);
sunxi_gpio_set_cfgpin(SUNXI_GPB(20), SUN5I_GPB_UART0);
sunxi_gpio_set_pull(SUNXI_GPB(20), SUNXI_GPIO_PULL_UP);
#elif CONFIG_CONS_INDEX == 1 && defined(CONFIG_MACH_SUN6I)
sunxi_gpio_set_cfgpin(SUNXI_GPH(20), SUN6I_GPH_UART0);
sunxi_gpio_set_cfgpin(SUNXI_GPH(21), SUN6I_GPH_UART0);
sunxi_gpio_set_pull(SUNXI_GPH(21), SUNXI_GPIO_PULL_UP);
#elif CONFIG_CONS_INDEX == 1 && defined(CONFIG_MACH_SUN8I_A33)
sunxi_gpio_set_cfgpin(SUNXI_GPB(0), SUN8I_A33_GPB_UART0);
sunxi_gpio_set_cfgpin(SUNXI_GPB(1), SUN8I_A33_GPB_UART0);
sunxi_gpio_set_pull(SUNXI_GPB(1), SUNXI_GPIO_PULL_UP);
#elif CONFIG_CONS_INDEX == 1 && defined(CONFIG_MACH_SUN8I_H3)
sunxi_gpio_set_cfgpin(SUNXI_GPA(4), SUN8I_H3_GPA_UART0);
sunxi_gpio_set_cfgpin(SUNXI_GPA(5), SUN8I_H3_GPA_UART0);
sunxi_gpio_set_pull(SUNXI_GPA(5), SUNXI_GPIO_PULL_UP);
#elif CONFIG_CONS_INDEX == 1 && defined(CONFIG_MACH_SUN50I)
sunxi_gpio_set_cfgpin(SUNXI_GPB(8), SUN50I_GPB_UART0);
sunxi_gpio_set_cfgpin(SUNXI_GPB(9), SUN50I_GPB_UART0);
sunxi_gpio_set_pull(SUNXI_GPB(9), SUNXI_GPIO_PULL_UP);
#elif CONFIG_CONS_INDEX == 1 && defined(CONFIG_MACH_SUN8I_A83T)
sunxi_gpio_set_cfgpin(SUNXI_GPB(9), SUN8I_A83T_GPB_UART0);
sunxi_gpio_set_cfgpin(SUNXI_GPB(10), SUN8I_A83T_GPB_UART0);
sunxi_gpio_set_pull(SUNXI_GPB(10), SUNXI_GPIO_PULL_UP);
#elif CONFIG_CONS_INDEX == 1 && defined(CONFIG_MACH_SUN9I)
sunxi_gpio_set_cfgpin(SUNXI_GPH(12), SUN9I_GPH_UART0);
sunxi_gpio_set_cfgpin(SUNXI_GPH(13), SUN9I_GPH_UART0);
sunxi_gpio_set_pull(SUNXI_GPH(13), SUNXI_GPIO_PULL_UP);
#elif CONFIG_CONS_INDEX == 2 && defined(CONFIG_MACH_SUN5I)
sunxi_gpio_set_cfgpin(SUNXI_GPG(3), SUN5I_GPG_UART1);
sunxi_gpio_set_cfgpin(SUNXI_GPG(4), SUN5I_GPG_UART1);
sunxi_gpio_set_pull(SUNXI_GPG(4), SUNXI_GPIO_PULL_UP);
#elif CONFIG_CONS_INDEX == 3 && defined(CONFIG_MACH_SUN8I)
sunxi_gpio_set_cfgpin(SUNXI_GPB(0), SUN8I_GPB_UART2);
sunxi_gpio_set_cfgpin(SUNXI_GPB(1), SUN8I_GPB_UART2);
sunxi_gpio_set_pull(SUNXI_GPB(1), SUNXI_GPIO_PULL_UP);
#elif CONFIG_CONS_INDEX == 5 && defined(CONFIG_MACH_SUN8I)
sunxi_gpio_set_cfgpin(SUNXI_GPL(2), SUN8I_GPL_R_UART);
sunxi_gpio_set_cfgpin(SUNXI_GPL(3), SUN8I_GPL_R_UART);
sunxi_gpio_set_pull(SUNXI_GPL(3), SUNXI_GPIO_PULL_UP);
#else
#error Unsupported console port number. Please fix pin mux settings in board.c
#endif
return 0;
}
int spl_board_load_image(void)
{
debug("Returning to FEL sp=%x, lr=%x\n", fel_stash.sp, fel_stash.lr);
return_to_fel(fel_stash.sp, fel_stash.lr);
return 0;
}
void s_init(void)
{
/*
* Undocumented magic taken from boot0, without this DRAM
* access gets messed up (seems cache related).
* The boot0 sources describe this as: "config ema for cache sram"
*/
#if defined CONFIG_MACH_SUN6I
setbits_le32(SUNXI_SRAMC_BASE + 0x44, 0x1800);
#elif defined CONFIG_MACH_SUN8I
__maybe_unused uint version;
/* Unlock sram version info reg, read it, relock */
setbits_le32(SUNXI_SRAMC_BASE + 0x24, (1 << 15));
version = readl(SUNXI_SRAMC_BASE + 0x24) >> 16;
clrbits_le32(SUNXI_SRAMC_BASE + 0x24, (1 << 15));
/*
* Ideally this would be a switch case, but we do not know exactly
* which versions there are and which version needs which settings,
* so reproduce the per SoC code from the BSP.
*/
#if defined CONFIG_MACH_SUN8I_A23
if (version == 0x1650)
setbits_le32(SUNXI_SRAMC_BASE + 0x44, 0x1800);
else /* 0x1661 ? */
setbits_le32(SUNXI_SRAMC_BASE + 0x44, 0xc0);
#elif defined CONFIG_MACH_SUN8I_A33
if (version != 0x1667)
setbits_le32(SUNXI_SRAMC_BASE + 0x44, 0xc0);
#endif
/* A83T BSP never modifies SUNXI_SRAMC_BASE + 0x44 */
/* No H3 BSP, boot0 seems to not modify SUNXI_SRAMC_BASE + 0x44 */
#endif
#if defined CONFIG_MACH_SUN6I || \
defined CONFIG_MACH_SUN7I || \
defined CONFIG_MACH_SUN8I
/* Enable SMP mode for CPU0, by setting bit 6 of Auxiliary Ctl reg */
asm volatile(
"mrc p15, 0, r0, c1, c0, 1\n"
"orr r0, r0, #1 << 6\n"
"mcr p15, 0, r0, c1, c0, 1\n");
#endif
#if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I_H3
/* Enable non-secure access to some peripherals */
tzpc_init();
#endif
clock_init();
timer_init();
gpio_init();
i2c_init_board();
eth_init_board();
}
#ifdef CONFIG_SPL_BUILD
DECLARE_GLOBAL_DATA_PTR;
/* The sunxi internal brom will try to loader external bootloader
* from mmc0, nand flash, mmc2.
*/
u32 spl_boot_device(void)
{
__maybe_unused struct mmc *mmc0, *mmc1;
/*
* When booting from the SD card or NAND memory, the "eGON.BT0"
* signature is expected to be found in memory at the address 0x0004
* (see the "mksunxiboot" tool, which generates this header).
*
* When booting in the FEL mode over USB, this signature is patched in
* memory and replaced with something else by the 'fel' tool. This other
* signature is selected in such a way, that it can't be present in a
* valid bootable SD card image (because the BROM would refuse to
* execute the SPL in this case).
*
* This checks for the signature and if it is not found returns to
* the FEL code in the BROM to wait and receive the main u-boot
* binary over USB. If it is found, it determines where SPL was
* read from.
*/
if (!is_boot0_magic(SPL_ADDR + 4)) /* eGON.BT0 */
return BOOT_DEVICE_BOARD;
sunxi: Support booting from SPI flash Allwinner devices support SPI flash as one of the possible bootable media type. The SPI flash chip needs to be connected to SPI0 pins (port C) to make this work. More information is available at: https://linux-sunxi.org/Bootable_SPI_flash This patch adds the initial support for booting from SPI flash. The existing SPI frameworks are not used in order to reduce the SPL code size. Right now the SPL size grows by ~370 bytes when CONFIG_SPL_SPI_SUNXI option is enabled. While there are no popular Allwinner devices with SPI flash at the moment, testing can be done using a SPI flash module (it can be bought for ~2$ on ebay) and jumper wires with the boards, which expose relevant pins on the expansion header. The SPI flash chips themselves are very cheap (some prices are even listed as low as 4 cents) and should not cost much if somebody decides to design a development board with an SPI flash chip soldered on the PCB. Another nice feature of the SPI flash is that it can be safely accessed in a device-independent way (since we know that the boot ROM is already probing these pins during the boot time). And if, for example, Olimex boards opted to use SPI flash instead of EEPROM, then they would have been able to have U-Boot installed in the SPI flash now and boot the rest of the system from the SATA hard drive. Hopefully we may see new interesting Allwinner based development boards in the future, now that the software support for the SPI flash is in a better shape :-) Testing can be done by enabling the CONFIG_SPL_SPI_SUNXI option in a board defconfig, then building U-Boot and finally flashing the resulting u-boot-sunxi-with-spl.bin binary over USB OTG with a help of the sunxi-fel tool: sunxi-fel spiflash-write 0 u-boot-sunxi-with-spl.bin The device needs to be switched into FEL (USB recovery) mode first. The most suitable boards for testing are Orange Pi PC and Pine64. Because these boards are cheap, have no built-in NAND/eMMC and expose SPI0 pins on the Raspberry Pi compatible expansion header. The A13-OLinuXino-Micro board also can be used. Signed-off-by: Siarhei Siamashka <siarhei.siamashka@gmail.com> Reviewed-by: Simon Glass <sjg@chromium.org> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
2016-06-07 20:28:34 +09:00
#ifdef CONFIG_SPL_SPI_SUNXI
if (readb(SPL_ADDR + 0x28) == SUNXI_BOOTED_FROM_SPI)
return BOOT_DEVICE_SPI;
#endif
/* The BROM will try to boot from mmc0 first, so try that first. */
#ifdef CONFIG_MMC
mmc_initialize(gd->bd);
mmc0 = find_mmc_device(0);
if (sunxi_mmc_has_egon_boot_signature(mmc0))
return BOOT_DEVICE_MMC1;
#endif
/* Fallback to booting NAND if enabled. */
if (IS_ENABLED(CONFIG_SPL_NAND_SUPPORT))
return BOOT_DEVICE_NAND;
#ifdef CONFIG_MMC
if (CONFIG_MMC_SUNXI_SLOT_EXTRA == 2) {
mmc1 = find_mmc_device(1);
if (sunxi_mmc_has_egon_boot_signature(mmc1))
return BOOT_DEVICE_MMC2;
}
#endif
panic("Could not determine boot source\n");
return -1; /* Never reached */
}
/*
* Properly announce BOOT_DEVICE_BOARD as "FEL".
* Overrides weak function from common/spl/spl.c
*/
void spl_board_announce_boot_device(void)
{
printf("FEL");
}
/* No confirmation data available in SPL yet. Hardcode bootmode */
u32 spl_boot_mode(const u32 boot_device)
{
return MMCSD_MODE_RAW;
}
void board_init_f(ulong dummy)
{
spl_init();
preloader_console_init();
#ifdef CONFIG_SPL_I2C_SUPPORT
/* Needed early by sunxi_board_init if PMU is enabled */
i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
#endif
sunxi_board_init();
}
#endif
void reset_cpu(ulong addr)
{
#ifdef CONFIG_SUNXI_GEN_SUN4I
static const struct sunxi_wdog *wdog =
&((struct sunxi_timer_reg *)SUNXI_TIMER_BASE)->wdog;
/* Set the watchdog for its shortest interval (.5s) and wait */
writel(WDT_MODE_RESET_EN | WDT_MODE_EN, &wdog->mode);
writel(WDT_CTRL_KEY | WDT_CTRL_RESTART, &wdog->ctl);
while (1) {
/* sun5i sometimes gets stuck without this */
writel(WDT_MODE_RESET_EN | WDT_MODE_EN, &wdog->mode);
}
#endif
#ifdef CONFIG_SUNXI_GEN_SUN6I
static const struct sunxi_wdog *wdog =
((struct sunxi_timer_reg *)SUNXI_TIMER_BASE)->wdog;
/* Set the watchdog for its shortest interval (.5s) and wait */
writel(WDT_CFG_RESET, &wdog->cfg);
writel(WDT_MODE_EN, &wdog->mode);
writel(WDT_CTRL_KEY | WDT_CTRL_RESTART, &wdog->ctl);
while (1) { }
#endif
}
#if !defined(CONFIG_SYS_DCACHE_OFF) && !defined(CONFIG_ARM64)
void enable_caches(void)
{
/* Enable D-cache. I-cache is already enabled in start.S */
dcache_enable();
}
#endif