]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - board/sunxi/board.c
sunxi: FEL - Add the ability to recognize and auto-import uEnv-style data
[karo-tx-uboot.git] / board / sunxi / board.c
index f27967bbf418faa32e136e4c764eb29fc7281a46..78dfda5a991983466cecb4a46997d4f23bb43962 100644 (file)
 
 #include <common.h>
 #include <mmc.h>
-#ifdef CONFIG_AXP152_POWER
-#include <axp152.h>
-#endif
-#ifdef CONFIG_AXP209_POWER
-#include <axp209.h>
-#endif
-#ifdef CONFIG_AXP221_POWER
-#include <axp221.h>
-#endif
-#ifdef CONFIG_NAND_SUNXI
-#include <nand.h>
-#endif
+#include <axp_pmic.h>
 #include <asm/arch/clock.h>
 #include <asm/arch/cpu.h>
 #include <asm/arch/display.h>
 #include <asm/arch/gpio.h>
 #include <asm/arch/mmc.h>
 #include <asm/arch/usb_phy.h>
+#ifndef CONFIG_ARM64
+#include <asm/armv7.h>
+#endif
 #include <asm/gpio.h>
 #include <asm/io.h>
-#include <linux/usb/musb.h>
+#include <nand.h>
 #include <net.h>
+#include <sy8106a.h>
 
 #if defined CONFIG_VIDEO_LCD_PANEL_I2C && !(defined CONFIG_SPL_BUILD)
 /* So that we can use pin names in Kconfig and sunxi_name_to_gpio() */
@@ -83,23 +76,52 @@ DECLARE_GLOBAL_DATA_PTR;
 /* add board specific code here */
 int board_init(void)
 {
-       int id_pfr1, ret;
+       __maybe_unused int id_pfr1, ret;
 
        gd->bd->bi_boot_params = (PHYS_SDRAM_0 + 0x100);
 
+#ifndef CONFIG_ARM64
        asm volatile("mrc p15, 0, %0, c0, c1, 1" : "=r"(id_pfr1));
        debug("id_pfr1: 0x%08x\n", id_pfr1);
        /* Generic Timer Extension available? */
-       if ((id_pfr1 >> 16) & 0xf) {
+       if ((id_pfr1 >> CPUID_ARM_GENTIMER_SHIFT) & 0xf) {
+               uint32_t freq;
+
                debug("Setting CNTFRQ\n");
-               /* CNTFRQ == 24 MHz */
-               asm volatile("mcr p15, 0, %0, c14, c0, 0" : : "r"(24000000));
+
+               /*
+                * CNTFRQ is a secure register, so we will crash if we try to
+                * write this from the non-secure world (read is OK, though).
+                * In case some bootcode has already set the correct value,
+                * we avoid the risk of writing to it.
+                */
+               asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r"(freq));
+               if (freq != CONFIG_TIMER_CLK_FREQ) {
+                       debug("arch timer frequency is %d Hz, should be %d, fixing ...\n",
+                             freq, CONFIG_TIMER_CLK_FREQ);
+#ifdef CONFIG_NON_SECURE
+                       printf("arch timer frequency is wrong, but cannot adjust it\n");
+#else
+                       asm volatile("mcr p15, 0, %0, c14, c0, 0"
+                                    : : "r"(CONFIG_TIMER_CLK_FREQ));
+#endif
+               }
        }
+#endif /* !CONFIG_ARM64 */
 
        ret = axp_gpio_init();
        if (ret)
                return ret;
 
+#ifdef CONFIG_SATAPWR
+       gpio_request(CONFIG_SATAPWR, "satapwr");
+       gpio_direction_output(CONFIG_SATAPWR, 1);
+#endif
+#ifdef CONFIG_MACPWR
+       gpio_request(CONFIG_MACPWR, "macpwr");
+       gpio_direction_output(CONFIG_MACPWR, 1);
+#endif
+
        /* Uses dm gpio code so do this here and not in i2c_init_board() */
        return soft_i2c_board_init();
 }
@@ -111,6 +133,46 @@ int dram_init(void)
        return 0;
 }
 
+#if defined(CONFIG_NAND_SUNXI) && defined(CONFIG_SPL_BUILD)
+static void nand_pinmux_setup(void)
+{
+       unsigned int pin;
+
+       for (pin = SUNXI_GPC(0); pin <= SUNXI_GPC(19); pin++)
+               sunxi_gpio_set_cfgpin(pin, SUNXI_GPC_NAND);
+
+#if defined CONFIG_MACH_SUN4I || defined CONFIG_MACH_SUN7I
+       for (pin = SUNXI_GPC(20); pin <= SUNXI_GPC(22); pin++)
+               sunxi_gpio_set_cfgpin(pin, SUNXI_GPC_NAND);
+#endif
+       /* sun4i / sun7i do have a PC23, but it is not used for nand,
+        * only sun7i has a PC24 */
+#ifdef CONFIG_MACH_SUN7I
+       sunxi_gpio_set_cfgpin(SUNXI_GPC(24), SUNXI_GPC_NAND);
+#endif
+}
+
+static void nand_clock_setup(void)
+{
+       struct sunxi_ccm_reg *const ccm =
+               (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+
+       setbits_le32(&ccm->ahb_gate0, (CLK_GATE_OPEN << AHB_GATE_OFFSET_NAND0));
+#ifdef CONFIG_MACH_SUN9I
+       setbits_le32(&ccm->ahb_gate1, (1 << AHB_GATE_OFFSET_DMA));
+#else
+       setbits_le32(&ccm->ahb_gate0, (1 << AHB_GATE_OFFSET_DMA));
+#endif
+       setbits_le32(&ccm->nand0_clk_cfg, CCM_NAND_CTRL_ENABLE | AHB_DIV_1);
+}
+
+void board_nand_init(void)
+{
+       nand_pinmux_setup();
+       nand_clock_setup();
+}
+#endif
+
 #ifdef CONFIG_GENERIC_MMC
 static void mmc_pinmux_setup(int sdc)
 {
@@ -225,7 +287,7 @@ static void mmc_pinmux_setup(int sdc)
                        sunxi_gpio_set_pull(SUNXI_GPC(24), SUNXI_GPIO_PULL_UP);
                        sunxi_gpio_set_drv(SUNXI_GPC(24), 2);
                }
-#elif defined(CONFIG_MACH_SUN8I)
+#elif defined(CONFIG_MACH_SUN8I) || defined(CONFIG_MACH_SUN50I)
                /* SDC2: PC5-PC6, PC8-PC16 */
                for (pin = SUNXI_GPC(5); pin <= SUNXI_GPC(6); pin++) {
                        sunxi_gpio_set_cfgpin(pin, SUNXI_GPC_SDC2);
@@ -297,42 +359,25 @@ int board_mmc_init(bd_t *bis)
                return -1;
 #endif
 
-#if CONFIG_MMC_SUNXI_SLOT == 0 && CONFIG_MMC_SUNXI_SLOT_EXTRA == 2
+#if !defined(CONFIG_SPL_BUILD) && CONFIG_MMC_SUNXI_SLOT_EXTRA == 2
        /*
-        * Both mmc0 and mmc2 are bootable, figure out where we're booting
-        * from. Try mmc0 first, just like the brom does.
+        * On systems with an emmc (mmc2), figure out if we are booting from
+        * the emmc and if we are make it "mmc dev 0" so that boot.scr, etc.
+        * are searched there first. Note we only do this for u-boot proper,
+        * not for the SPL, see spl_boot_device().
         */
-       if (mmc_getcd(mmc0) && mmc_init(mmc0) == 0 &&
-           mmc0->block_dev.block_read(0, 16, 1, buf) == 1) {
-               buf[12] = 0;
-               if (strcmp(&buf[4], "eGON.BT0") == 0)
-                       return 0;
+       if (!sunxi_mmc_has_egon_boot_signature(mmc0) &&
+           sunxi_mmc_has_egon_boot_signature(mmc1)) {
+               /* Booting from emmc / mmc2, swap */
+               mmc0->block_dev.devnum = 1;
+               mmc1->block_dev.devnum = 0;
        }
-
-       /* no bootable card in mmc0, so we must be booting from mmc2, swap */
-       mmc0->block_dev.dev = 1;
-       mmc1->block_dev.dev = 0;
 #endif
 
        return 0;
 }
 #endif
 
-#ifdef CONFIG_NAND
-void board_nand_init(void)
-{
-       unsigned int pin;
-       static u8 ports[] = CONFIG_NAND_SUNXI_GPC_PORTS;
-
-       /* Configure AHB muxes to connect output pins with NAND controller */
-       for (pin = 0; pin < 16; pin++)
-               sunxi_gpio_set_cfgpin(SUNXI_GPC(pin), SUNXI_GPC_NAND);
-
-       for (pin = 0; pin < ARRAY_SIZE(ports); pin++)
-               sunxi_gpio_set_cfgpin(SUNXI_GPC(ports[pin]), SUNXI_GPC_NAND);
-}
-#endif
-
 void i2c_init_board(void)
 {
 #ifdef CONFIG_I2C0_ENABLE
@@ -410,6 +455,12 @@ void i2c_init_board(void)
        clock_twi_onoff(4, 1);
 #endif
 #endif
+
+#ifdef CONFIG_R_I2C_ENABLE
+       clock_twi_onoff(5, 1);
+       sunxi_gpio_set_cfgpin(SUNXI_GPL(0), SUN8I_H3_GPL_R_TWI);
+       sunxi_gpio_set_cfgpin(SUNXI_GPL(1), SUN8I_H3_GPL_R_TWI);
+#endif
 }
 
 #ifdef CONFIG_SPL_BUILD
@@ -418,43 +469,67 @@ void sunxi_board_init(void)
        int power_failed = 0;
        unsigned long ramsize;
 
-#ifdef CONFIG_AXP152_POWER
-       power_failed = axp152_init();
-       power_failed |= axp152_set_dcdc2(1400);
-       power_failed |= axp152_set_dcdc3(1500);
-       power_failed |= axp152_set_dcdc4(1250);
-       power_failed |= axp152_set_ldo2(3000);
+#ifdef CONFIG_SY8106A_POWER
+       power_failed = sy8106a_set_vout1(CONFIG_SY8106A_VOUT1_VOLT);
+#endif
+
+#if defined CONFIG_AXP152_POWER || defined CONFIG_AXP209_POWER || \
+       defined CONFIG_AXP221_POWER || defined CONFIG_AXP809_POWER || \
+       defined CONFIG_AXP818_POWER
+       power_failed = axp_init();
+
+#if defined CONFIG_AXP221_POWER || defined CONFIG_AXP809_POWER || \
+       defined CONFIG_AXP818_POWER
+       power_failed |= axp_set_dcdc1(CONFIG_AXP_DCDC1_VOLT);
+#endif
+       power_failed |= axp_set_dcdc2(CONFIG_AXP_DCDC2_VOLT);
+       power_failed |= axp_set_dcdc3(CONFIG_AXP_DCDC3_VOLT);
+#if !defined(CONFIG_AXP209_POWER) && !defined(CONFIG_AXP818_POWER)
+       power_failed |= axp_set_dcdc4(CONFIG_AXP_DCDC4_VOLT);
+#endif
+#if defined CONFIG_AXP221_POWER || defined CONFIG_AXP809_POWER || \
+       defined CONFIG_AXP818_POWER
+       power_failed |= axp_set_dcdc5(CONFIG_AXP_DCDC5_VOLT);
+#endif
+
+#if defined CONFIG_AXP221_POWER || defined CONFIG_AXP809_POWER || \
+       defined CONFIG_AXP818_POWER
+       power_failed |= axp_set_aldo1(CONFIG_AXP_ALDO1_VOLT);
+#endif
+       power_failed |= axp_set_aldo2(CONFIG_AXP_ALDO2_VOLT);
+#if !defined(CONFIG_AXP152_POWER)
+       power_failed |= axp_set_aldo3(CONFIG_AXP_ALDO3_VOLT);
 #endif
 #ifdef CONFIG_AXP209_POWER
-       power_failed |= axp209_init();
-       power_failed |= axp209_set_dcdc2(1400);
-       power_failed |= axp209_set_dcdc3(1250);
-       power_failed |= axp209_set_ldo2(3000);
-       power_failed |= axp209_set_ldo3(2800);
-       power_failed |= axp209_set_ldo4(2800);
-#endif
-#ifdef CONFIG_AXP221_POWER
-       power_failed = axp221_init();
-       power_failed |= axp221_set_dcdc1(CONFIG_AXP221_DCDC1_VOLT);
-       power_failed |= axp221_set_dcdc2(1200); /* A31:VDD-GPU, A23:VDD-SYS */
-       power_failed |= axp221_set_dcdc3(1200); /* VDD-CPU */
-#ifdef CONFIG_MACH_SUN6I
-       power_failed |= axp221_set_dcdc4(1200); /* A31:VDD-SYS */
-#else
-       power_failed |= axp221_set_dcdc4(0);    /* A23:unused */
+       power_failed |= axp_set_aldo4(CONFIG_AXP_ALDO4_VOLT);
+#endif
+
+#if defined(CONFIG_AXP221_POWER) || defined(CONFIG_AXP809_POWER) || \
+       defined(CONFIG_AXP818_POWER)
+       power_failed |= axp_set_dldo(1, CONFIG_AXP_DLDO1_VOLT);
+       power_failed |= axp_set_dldo(2, CONFIG_AXP_DLDO2_VOLT);
+#if !defined CONFIG_AXP809_POWER
+       power_failed |= axp_set_dldo(3, CONFIG_AXP_DLDO3_VOLT);
+       power_failed |= axp_set_dldo(4, CONFIG_AXP_DLDO4_VOLT);
 #endif
-       power_failed |= axp221_set_dcdc5(1500); /* VCC-DRAM */
-       power_failed |= axp221_set_dldo1(CONFIG_AXP221_DLDO1_VOLT);
-       power_failed |= axp221_set_dldo4(CONFIG_AXP221_DLDO4_VOLT);
-       power_failed |= axp221_set_aldo1(CONFIG_AXP221_ALDO1_VOLT);
-       power_failed |= axp221_set_aldo2(CONFIG_AXP221_ALDO2_VOLT);
-       power_failed |= axp221_set_aldo3(CONFIG_AXP221_ALDO3_VOLT);
-       power_failed |= axp221_set_eldo(3, CONFIG_AXP221_ELDO3_VOLT);
+       power_failed |= axp_set_eldo(1, CONFIG_AXP_ELDO1_VOLT);
+       power_failed |= axp_set_eldo(2, CONFIG_AXP_ELDO2_VOLT);
+       power_failed |= axp_set_eldo(3, CONFIG_AXP_ELDO3_VOLT);
 #endif
 
+#ifdef CONFIG_AXP818_POWER
+       power_failed |= axp_set_fldo(1, CONFIG_AXP_FLDO1_VOLT);
+       power_failed |= axp_set_fldo(2, CONFIG_AXP_FLDO2_VOLT);
+       power_failed |= axp_set_fldo(3, CONFIG_AXP_FLDO3_VOLT);
+#endif
+
+#if defined CONFIG_AXP809_POWER || defined CONFIG_AXP818_POWER
+       power_failed |= axp_set_sw(IS_ENABLED(CONFIG_AXP_SW_ON));
+#endif
+#endif
        printf("DRAM:");
        ramsize = sunxi_dram_init();
-       printf(" %lu MiB\n", ramsize >> 20);
+       printf(" %d MiB\n", (int)(ramsize >> 20));
        if (!ramsize)
                hang();
 
@@ -469,28 +544,6 @@ void sunxi_board_init(void)
 }
 #endif
 
-#if defined(CONFIG_MUSB_HOST) || defined(CONFIG_MUSB_GADGET)
-extern const struct musb_platform_ops sunxi_musb_ops;
-
-static struct musb_hdrc_config musb_config = {
-       .multipoint     = 1,
-       .dyn_fifo       = 1,
-       .num_eps        = 6,
-       .ram_bits       = 11,
-};
-
-static struct musb_hdrc_platform_data musb_plat = {
-#if defined(CONFIG_MUSB_HOST)
-       .mode           = MUSB_HOST,
-#else
-       .mode           = MUSB_PERIPHERAL,
-#endif
-       .config         = &musb_config,
-       .power          = 250,
-       .platform_ops   = &sunxi_musb_ops,
-};
-#endif
-
 #ifdef CONFIG_USB_GADGET
 int g_dnl_board_usb_cable_connected(void)
 {
@@ -518,6 +571,44 @@ void get_board_serial(struct tag_serialnr *serialnr)
 }
 #endif
 
+#if !defined(CONFIG_SPL_BUILD)
+#include <asm/arch/spl.h>
+#include <environment.h>
+
+/*
+ * Check the SPL header for the "sunxi" variant. If found: parse values
+ * that might have been passed by the loader ("fel" utility), and update
+ * the environment accordingly.
+ */
+static void parse_spl_header(const uint32_t spl_addr)
+{
+       struct boot_file_head *spl = (void *)(ulong)spl_addr;
+       if (memcmp(spl->spl_signature, SPL_SIGNATURE, 3) != 0)
+               return; /* signature mismatch, no usable header */
+
+       uint8_t spl_header_version = spl->spl_signature[3];
+       if (spl_header_version != SPL_HEADER_VERSION) {
+               printf("sunxi SPL version mismatch: expected %u, got %u\n",
+                      SPL_HEADER_VERSION, spl_header_version);
+               return;
+       }
+       if (!spl->fel_script_address)
+               return;
+
+       if (spl->fel_uEnv_length != 0) {
+               /*
+                * data is expected in uEnv.txt compatible format, so "env
+                * import -t" the string(s) at fel_script_address right away.
+                */
+               himport_r(&env_htab, (char *)spl->fel_script_address,
+                         spl->fel_uEnv_length, '\n', H_NOCLEAR, 0, 0, NULL);
+               return;
+       }
+       /* otherwise assume .scr format (mkimage-type script) */
+       setenv_hex("fel_scriptaddr", spl->fel_script_address);
+}
+#endif
+
 #ifdef CONFIG_MISC_INIT_R
 int misc_init_r(void)
 {
@@ -526,6 +617,16 @@ int misc_init_r(void)
        uint8_t mac_addr[6];
        int ret;
 
+#if !defined(CONFIG_SPL_BUILD)
+       setenv("fel_booted", NULL);
+       setenv("fel_scriptaddr", NULL);
+       /* determine if we are running in FEL mode */
+       if (!is_boot0_magic(SPL_ADDR + 4)) { /* eGON.BT0 */
+               setenv("fel_booted", "1");
+               parse_spl_header(SPL_ADDR);
+       }
+#endif
+
        ret = sunxi_get_sid(sid);
        if (ret == 0 && sid[0] != 0 && sid[3] != 0) {
                if (!getenv("ethaddr")) {
@@ -553,18 +654,20 @@ int misc_init_r(void)
        if (ret)
                return ret;
 #endif
-#if defined(CONFIG_MUSB_HOST) || defined(CONFIG_MUSB_GADGET)
-       musb_register(&musb_plat, NULL, (void *)SUNXI_USB0_BASE);
-#endif
+       sunxi_musb_board_init();
+
        return 0;
 }
 #endif
 
-#ifdef CONFIG_OF_BOARD_SETUP
 int ft_board_setup(void *blob, bd_t *bd)
 {
+       int __maybe_unused r;
+
 #ifdef CONFIG_VIDEO_DT_SIMPLEFB
-       return sunxi_simplefb_setup(blob);
+       r = sunxi_simplefb_setup(blob);
+       if (r)
+               return r;
 #endif
+       return 0;
 }
-#endif /* CONFIG_OF_BOARD_SETUP */