Merge tag 'u-boot-atmel-fixes-2021.01-b' of https://gitlab.denx.de/u-boot/custodians...
[platform/kernel/u-boot.git] / board / sunxi / board.c
index 3d364c6..708a27e 100644 (file)
  */
 
 #include <common.h>
+#include <dm.h>
+#include <env.h>
+#include <hang.h>
+#include <image.h>
+#include <init.h>
+#include <log.h>
 #include <mmc.h>
 #include <axp_pmic.h>
+#include <generic-phy.h>
+#include <phy-sun4i-usb.h>
 #include <asm/arch/clock.h>
 #include <asm/arch/cpu.h>
 #include <asm/arch/display.h>
 #include <asm/arch/dram.h>
 #include <asm/arch/gpio.h>
 #include <asm/arch/mmc.h>
+#include <asm/arch/prcm.h>
 #include <asm/arch/spl.h>
-#include <asm/arch/usb_phy.h>
+#include <linux/delay.h>
+#include <u-boot/crc.h>
 #ifndef CONFIG_ARM64
 #include <asm/armv7.h>
 #endif
 #include <asm/gpio.h>
 #include <asm/io.h>
-#include <crc.h>
-#include <environment.h>
+#include <u-boot/crc.h>
+#include <env_internal.h>
 #include <linux/libfdt.h>
 #include <nand.h>
 #include <net.h>
@@ -92,10 +102,18 @@ void i2c_init_board(void)
        sunxi_gpio_set_cfgpin(SUNXI_GPH(14), SUN6I_GPH_TWI0);
        sunxi_gpio_set_cfgpin(SUNXI_GPH(15), SUN6I_GPH_TWI0);
        clock_twi_onoff(0, 1);
+#elif defined(CONFIG_MACH_SUN8I_V3S)
+       sunxi_gpio_set_cfgpin(SUNXI_GPB(6), SUN8I_V3S_GPB_TWI0);
+       sunxi_gpio_set_cfgpin(SUNXI_GPB(7), SUN8I_V3S_GPB_TWI0);
+       clock_twi_onoff(0, 1);
 #elif defined(CONFIG_MACH_SUN8I)
        sunxi_gpio_set_cfgpin(SUNXI_GPH(2), SUN8I_GPH_TWI0);
        sunxi_gpio_set_cfgpin(SUNXI_GPH(3), SUN8I_GPH_TWI0);
        clock_twi_onoff(0, 1);
+#elif defined(CONFIG_MACH_SUN50I)
+       sunxi_gpio_set_cfgpin(SUNXI_GPH(0), SUN50I_GPH_TWI0);
+       sunxi_gpio_set_cfgpin(SUNXI_GPH(1), SUN50I_GPH_TWI0);
+       clock_twi_onoff(0, 1);
 #endif
 #endif
 
@@ -118,6 +136,10 @@ void i2c_init_board(void)
        sunxi_gpio_set_cfgpin(SUNXI_GPH(4), SUN8I_GPH_TWI1);
        sunxi_gpio_set_cfgpin(SUNXI_GPH(5), SUN8I_GPH_TWI1);
        clock_twi_onoff(1, 1);
+#elif defined(CONFIG_MACH_SUN50I)
+       sunxi_gpio_set_cfgpin(SUNXI_GPH(2), SUN50I_GPH_TWI1);
+       sunxi_gpio_set_cfgpin(SUNXI_GPH(3), SUN50I_GPH_TWI1);
+       clock_twi_onoff(1, 1);
 #endif
 #endif
 
@@ -140,6 +162,10 @@ void i2c_init_board(void)
        sunxi_gpio_set_cfgpin(SUNXI_GPE(12), SUN8I_GPE_TWI2);
        sunxi_gpio_set_cfgpin(SUNXI_GPE(13), SUN8I_GPE_TWI2);
        clock_twi_onoff(2, 1);
+#elif defined(CONFIG_MACH_SUN50I)
+       sunxi_gpio_set_cfgpin(SUNXI_GPE(14), SUN50I_GPE_TWI2);
+       sunxi_gpio_set_cfgpin(SUNXI_GPE(15), SUN50I_GPE_TWI2);
+       clock_twi_onoff(2, 1);
 #endif
 #endif
 
@@ -166,10 +192,16 @@ void i2c_init_board(void)
 #endif
 
 #ifdef CONFIG_R_I2C_ENABLE
+#ifdef CONFIG_MACH_SUN50I
+       clock_twi_onoff(5, 1);
+       sunxi_gpio_set_cfgpin(SUNXI_GPL(8), SUN50I_GPL_R_TWI);
+       sunxi_gpio_set_cfgpin(SUNXI_GPL(9), SUN50I_GPL_R_TWI);
+#else
        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
+#endif
 }
 
 #if defined(CONFIG_ENV_IS_IN_MMC) && defined(CONFIG_ENV_IS_IN_FAT)
@@ -188,6 +220,10 @@ enum env_location env_get_location(enum env_operation op, int prio)
 }
 #endif
 
+#ifdef CONFIG_DM_MMC
+static void mmc_pinmux_setup(int sdc);
+#endif
+
 /* add board specific code here */
 int board_init(void)
 {
@@ -249,13 +285,68 @@ int board_init(void)
        i2c_init_board();
 #endif
 
+#ifdef CONFIG_DM_MMC
+       /*
+        * Temporary workaround for enabling MMC clocks until a sunxi DM
+        * pinctrl driver lands.
+        */
+       mmc_pinmux_setup(CONFIG_MMC_SUNXI_SLOT);
+#if CONFIG_MMC_SUNXI_SLOT_EXTRA != -1
+       mmc_pinmux_setup(CONFIG_MMC_SUNXI_SLOT_EXTRA);
+#endif
+#endif /* CONFIG_DM_MMC */
+
        /* Uses dm gpio code so do this here and not in i2c_init_board() */
        return soft_i2c_board_init();
 }
 
+/*
+ * On older SoCs the SPL is actually at address zero, so using NULL as
+ * an error value does not work.
+ */
+#define INVALID_SPL_HEADER ((void *)~0UL)
+
+static struct boot_file_head * get_spl_header(uint8_t req_version)
+{
+       struct boot_file_head *spl = (void *)(ulong)SPL_ADDR;
+       uint8_t spl_header_version = spl->spl_signature[3];
+
+       /* Is there really the SPL header (still) there? */
+       if (memcmp(spl->spl_signature, SPL_SIGNATURE, 3) != 0)
+               return INVALID_SPL_HEADER;
+
+       if (spl_header_version < req_version) {
+               printf("sunxi SPL version mismatch: expected %u, got %u\n",
+                      req_version, spl_header_version);
+               return INVALID_SPL_HEADER;
+       }
+
+       return spl;
+}
+
+static const char *get_spl_dt_name(void)
+{
+       struct boot_file_head *spl = get_spl_header(SPL_DT_HEADER_VERSION);
+
+       /* Check if there is a DT name stored in the SPL header. */
+       if (spl != INVALID_SPL_HEADER && spl->dt_name_offset)
+               return (char *)spl + spl->dt_name_offset;
+
+       return NULL;
+}
+
 int dram_init(void)
 {
-       gd->ram_size = get_ram_size((long *)PHYS_SDRAM_0, PHYS_SDRAM_0_SIZE);
+       struct boot_file_head *spl = get_spl_header(SPL_DRAM_HEADER_VERSION);
+
+       if (spl == INVALID_SPL_HEADER)
+               gd->ram_size = get_ram_size((long *)PHYS_SDRAM_0,
+                                           PHYS_SDRAM_0_SIZE);
+       else
+               gd->ram_size = (phys_addr_t)spl->dram_size << 20;
+
+       if (gd->ram_size > CONFIG_SUNXI_DRAM_MAX_SIZE)
+               gd->ram_size = CONFIG_SUNXI_DRAM_MAX_SIZE;
 
        return 0;
 }
@@ -441,6 +532,13 @@ static void mmc_pinmux_setup(int sdc)
                        sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP);
                        sunxi_gpio_set_drv(pin, 2);
                }
+#elif defined(CONFIG_MACH_SUN50I_H6)
+               /* SDC2: PC4-PC14 */
+               for (pin = SUNXI_GPC(4); pin <= SUNXI_GPC(14); pin++) {
+                       sunxi_gpio_set_cfgpin(pin, SUNXI_GPC_SDC2);
+                       sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP);
+                       sunxi_gpio_set_drv(pin, 2);
+               }
 #elif defined(CONFIG_MACH_SUN9I)
                /* SDC2: PC6-PC16 */
                for (pin = SUNXI_GPC(6); pin <= SUNXI_GPC(16); pin++) {
@@ -491,10 +589,9 @@ static void mmc_pinmux_setup(int sdc)
        }
 }
 
-int board_mmc_init(bd_t *bis)
+int board_mmc_init(struct bd_info *bis)
 {
        __maybe_unused struct mmc *mmc0, *mmc1;
-       __maybe_unused char buf[512];
 
        mmc_pinmux_setup(CONFIG_MMC_SUNXI_SLOT);
        mmc0 = sunxi_mmc_init(CONFIG_MMC_SUNXI_SLOT);
@@ -513,6 +610,21 @@ int board_mmc_init(bd_t *bis)
 #endif
 
 #ifdef CONFIG_SPL_BUILD
+
+static void sunxi_spl_store_dram_size(phys_addr_t dram_size)
+{
+       struct boot_file_head *spl = get_spl_header(SPL_DT_HEADER_VERSION);
+
+       if (spl == INVALID_SPL_HEADER)
+               return;
+
+       /* Promote the header version for U-Boot proper, if needed. */
+       if (spl->spl_signature[3] < SPL_DRAM_HEADER_VERSION)
+               spl->spl_signature[3] = SPL_DRAM_HEADER_VERSION;
+
+       spl->dram_size = dram_size >> 20;
+}
+
 void sunxi_board_init(void)
 {
        int power_failed = 0;
@@ -581,6 +693,8 @@ void sunxi_board_init(void)
        if (!gd->ram_size)
                hang();
 
+       sunxi_spl_store_dram_size(gd->ram_size);
+
        /*
         * Only clock up the CPU to full speed if we are reasonably
         * assured it's being powered with suitable core voltage
@@ -595,7 +709,35 @@ void sunxi_board_init(void)
 #ifdef CONFIG_USB_GADGET
 int g_dnl_board_usb_cable_connected(void)
 {
-       return sunxi_usb_phy_vbus_detect(0);
+       struct udevice *dev;
+       struct phy phy;
+       int ret;
+
+       ret = uclass_get_device(UCLASS_USB_GADGET_GENERIC, 0, &dev);
+       if (ret) {
+               pr_err("%s: Cannot find USB device\n", __func__);
+               return ret;
+       }
+
+       ret = generic_phy_get_by_name(dev, "usb", &phy);
+       if (ret) {
+               pr_err("failed to get %s USB PHY\n", dev->name);
+               return ret;
+       }
+
+       ret = generic_phy_init(&phy);
+       if (ret) {
+               pr_debug("failed to init %s USB PHY\n", dev->name);
+               return ret;
+       }
+
+       ret = sun4i_usb_phy_vbus_detect(&phy);
+       if (ret == 1) {
+               pr_err("A charger is plugged into the OTG\n");
+               return -ENODEV;
+       }
+
+       return ret;
 }
 #endif
 
@@ -626,16 +768,11 @@ void get_board_serial(struct tag_serialnr *serialnr)
  */
 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 */
+       struct boot_file_head *spl = get_spl_header(SPL_ENV_HEADER_VERSION);
 
-       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);
+       if (spl == INVALID_SPL_HEADER)
                return;
-       }
+
        if (!spl->fel_script_address)
                return;
 
@@ -722,7 +859,7 @@ static void setup_environment(const void *fdt)
 
 int misc_init_r(void)
 {
-       __maybe_unused int ret;
+       const char *spl_dt_name;
        uint boot;
 
        env_set("fel_booted", NULL);
@@ -741,13 +878,17 @@ int misc_init_r(void)
                env_set("mmc_bootdev", "1");
        }
 
-       setup_environment(gd->fdt_blob);
+       /* Set fdtfile to match the FIT configuration chosen in SPL. */
+       spl_dt_name = get_spl_dt_name();
+       if (spl_dt_name) {
+               char *prefix = IS_ENABLED(CONFIG_ARM64) ? "allwinner/" : "";
+               char str[64];
 
-#ifndef CONFIG_MACH_SUN9I
-       ret = sunxi_usb_phy_probe();
-       if (ret)
-               return ret;
-#endif
+               snprintf(str, sizeof(str), "%s%s.dtb", prefix, spl_dt_name);
+               env_set("fdtfile", str);
+       }
+
+       setup_environment(gd->fdt_blob);
 
 #ifdef CONFIG_USB_ETHER
        usb_ether_init();
@@ -756,7 +897,7 @@ int misc_init_r(void)
        return 0;
 }
 
-int ft_board_setup(void *blob, bd_t *bd)
+int ft_board_setup(void *blob, struct bd_info *bd)
 {
        int __maybe_unused r;
 
@@ -775,30 +916,72 @@ int ft_board_setup(void *blob, bd_t *bd)
 }
 
 #ifdef CONFIG_SPL_LOAD_FIT
+
+static void set_spl_dt_name(const char *name)
+{
+       struct boot_file_head *spl = get_spl_header(SPL_ENV_HEADER_VERSION);
+
+       if (spl == INVALID_SPL_HEADER)
+               return;
+
+       /* Promote the header version for U-Boot proper, if needed. */
+       if (spl->spl_signature[3] < SPL_DT_HEADER_VERSION)
+               spl->spl_signature[3] = SPL_DT_HEADER_VERSION;
+
+       strcpy((char *)&spl->string_pool, name);
+       spl->dt_name_offset = offsetof(struct boot_file_head, string_pool);
+}
+
 int board_fit_config_name_match(const char *name)
 {
-       struct boot_file_head *spl = (void *)(ulong)SPL_ADDR;
-       const char *cmp_str = (void *)(ulong)SPL_ADDR;
+       const char *best_dt_name = get_spl_dt_name();
+       int ret;
 
-       /* Check if there is a DT name stored in the SPL header and use that. */
-       if (spl->dt_name_offset) {
-               cmp_str += spl->dt_name_offset;
-       } else {
 #ifdef CONFIG_DEFAULT_DEVICE_TREE
-               cmp_str = CONFIG_DEFAULT_DEVICE_TREE;
-#else
-               return 0;
+       if (best_dt_name == NULL)
+               best_dt_name = CONFIG_DEFAULT_DEVICE_TREE;
 #endif
-       };
 
-/* Differentiate the two Pine64 board DTs by their DRAM size. */
-       if (strstr(name, "-pine64") && strstr(cmp_str, "-pine64")) {
-               if ((gd->ram_size > 512 * 1024 * 1024))
-                       return !strstr(name, "plus");
+       if (best_dt_name == NULL) {
+               /* No DT name was provided, so accept the first config. */
+               return 0;
+       }
+#ifdef CONFIG_PINE64_DT_SELECTION
+       if (strstr(best_dt_name, "-pine64-plus")) {
+               /* Differentiate the Pine A64 boards by their DRAM size. */
+               if ((gd->ram_size == 512 * 1024 * 1024))
+                       best_dt_name = "sun50i-a64-pine64";
+       }
+#endif
+#ifdef CONFIG_PINEPHONE_DT_SELECTION
+       if (strstr(best_dt_name, "-pinephone")) {
+               /* Differentiate the PinePhone revisions by GPIO inputs. */
+               prcm_apb0_enable(PRCM_APB0_GATE_PIO);
+               sunxi_gpio_set_pull(SUNXI_GPL(6), SUNXI_GPIO_PULL_UP);
+               sunxi_gpio_set_cfgpin(SUNXI_GPL(6), SUNXI_GPIO_INPUT);
+               udelay(100);
+
+               /* PL6 is pulled low by the modem on v1.2. */
+               if (gpio_get_value(SUNXI_GPL(6)) == 0)
+                       best_dt_name = "sun50i-a64-pinephone-1.2";
                else
-                       return !!strstr(name, "plus");
-       } else {
-               return strcmp(name, cmp_str);
+                       best_dt_name = "sun50i-a64-pinephone-1.1";
+
+               sunxi_gpio_set_cfgpin(SUNXI_GPL(6), SUNXI_GPIO_DISABLE);
+               sunxi_gpio_set_pull(SUNXI_GPL(6), SUNXI_GPIO_PULL_DISABLE);
+               prcm_apb0_disable(PRCM_APB0_GATE_PIO);
        }
+#endif
+
+       ret = strcmp(name, best_dt_name);
+
+       /*
+        * If one of the FIT configurations matches the most accurate DT name,
+        * update the SPL header to provide that DT name to U-Boot proper.
+        */
+       if (ret == 0)
+               set_spl_dt_name(best_dt_name);
+
+       return ret;
 }
 #endif