// SPDX-License-Identifier: GPL-2.0+ /* * (C) Copyright 2012-2013 Henrik Nordstrom * (C) Copyright 2013 Luke Kenneth Casson Leighton * * (C) Copyright 2007-2011 * Allwinner Technology Co., Ltd. * Tom Cubie * * Some board init for the Allwinner A10-evb board. */ #include #include #include #include #include #include #include #include #include #include #include #include #include //#include #ifdef CONFIG_ARM #include #ifndef CONFIG_ARM64 #include #endif #endif #include #include #include #include #include #include #include #include #include #include #include #include #ifdef CONFIG_SUNXI_POWER #include #include #endif #ifdef CONFIG_TCS4838_POWER #include #endif #ifdef CONFIG_SUNXI_DMA #include #endif #include #include int __attribute__((weak)) sunxi_set_sramc_mode(void) { return 0; } int __attribute__((weak)) clock_set_corepll(int frequency) { return 0; } void __attribute__((weak)) rtc_set_vccio_det_spare(void) { return ; } int __attribute__((weak)) rtc_set_dcxo_off(void) { return 0; } DECLARE_GLOBAL_DATA_PTR; #ifdef CONFIG_SUNXI_OVERLAY __weak int sunxi_overlay_apply_merged(void *dtb_base, void *dtbo_base) { return fdt_check_header(dtbo_base); } #endif void i2c_init_board(void) { __maybe_unused char fdt_node_str[8] = {0}; #ifdef CONFIG_I2C0_ENABLE #if defined(CONFIG_MACH_SUN8IW18) #if 0 /*twi0 & uart0 use the same pin*/ sunxi_gpio_set_cfgpin(SUNXI_GPH(0), SUN8I_GPH_TWI0); sunxi_gpio_set_cfgpin(SUNXI_GPH(1), SUN8I_GPH_TWI0); clock_twi_onoff(0,1); #endif #else sprintf(fdt_node_str, "twi0"); fdt_set_all_pin(fdt_node_str, "pinctrl-0"); #endif #endif #ifdef CONFIG_I2C1_ENABLE #if defined(CONFIG_MACH_SUN8IW18) sunxi_gpio_set_cfgpin(SUNXI_GPH(2), SUN8I_GPH_TWI1); sunxi_gpio_set_cfgpin(SUNXI_GPH(3), SUN8I_GPH_TWI1); /*clock_twi_onoff(1, 1);*/ #else sprintf(fdt_node_str, "twi1"); fdt_set_all_pin(fdt_node_str, "pinctrl-0"); #endif #endif #ifdef CONFIG_I2C2_ENABLE sprintf(fdt_node_str, "twi2"); fdt_set_all_pin(fdt_node_str, "pinctrl-0"); #endif #ifdef CONFIG_I2C3_ENABLE sprintf(fdt_node_str, "twi3"); fdt_set_all_pin(fdt_node_str, "pinctrl-0"); #endif #ifdef CONFIG_I2C4_ENABLE sprintf(fdt_node_str, "twi4"); fdt_set_all_pin(fdt_node_str, "pinctrl-0"); #endif #ifdef CONFIG_I2C5_ENABLE sprintf(fdt_node_str, "twi5"); fdt_set_all_pin(fdt_node_str, "pinctrl-0"); #endif #ifdef CONFIG_R_I2C0_ENABLE #if defined(CONFIG_MACH_SUN50IW11) sunxi_gpio_set_cfgpin(SUNXI_GPL(5), SUN8I_H3_GPL_R_TWI); sunxi_gpio_set_cfgpin(SUNXI_GPL(6), SUN8I_H3_GPL_R_TWI); #else #if defined(CONFIG_MACH_SUN50IW9) sprintf(fdt_node_str, "twi5"); #elif defined(CONFIG_MACH_SUN50IW10) || defined(CONFIG_MACH_SUN55IW3) sprintf(fdt_node_str, "twi6"); #else sprintf(fdt_node_str, "twi4"); #endif fdt_set_all_pin(fdt_node_str, "pinctrl-0"); #endif #ifdef CONFIG_R_I2C1_ENABLE sprintf(fdt_node_str, "twi7"); fdt_set_all_pin(fdt_node_str, "pinctrl-0"); #endif #endif } #ifdef CONFIG_ARM void enable_smp(void) { /* SMP status is controlled by bit 6 of the CP15 Aux Ctrl Reg:ACTLR */ asm volatile("MRC p15, 0, r0, c1, c0, 1"); asm volatile("ORR r0, r0, #0x040"); asm volatile("MCR p15, 0, r0, c1, c0, 1"); } #else void __attribute__((weak)) enable_smp(void) { return ; } #endif void smp_init(void) { int cpu_status = 0; #if defined(CONFIG_SUNXI_NCAT) || defined(CONFIG_SUNXI_NCAT_V2) cpu_status = readl(IOMEM_ADDR(SUNXI_CPUXCFG_BASE + 0x80)); cpu_status &= (0xf<<24); #else /*old platform enable smp unconditionally*/ cpu_status = 1; #endif /* note: sbrom will enable smp bit when jmp to non-secure fel. but normal brom not do this operation. so should enable smp when run uboot by normal fel mode. */ if(!cpu_status) enable_smp(); } int sunxi_plat_init(void) { sunxi_probe_securemode(); #ifdef CONFIG_SUNXI_DMA sunxi_dma_init(); #endif #ifdef CONFIG_ARM extern int secure_os_memory_init(void); if (sunxi_probe_secure_os()) { smc_tee_inform_fdt((uint64_t)(unsigned long)working_fdt, gd->fdt_size); secure_os_memory_init(); } #endif return 0; } /* add board specific code here */ int board_init(void) { __maybe_unused int id_pfr1, ret, satapwr_pin, macpwr_pin; gd->bd->bi_boot_params = (PHYS_SDRAM_0 + 0x100); sunxi_plat_init(); int work_mode = get_boot_work_mode(); ret = axp_gpio_init(); if (ret) return ret; #ifdef CONFIG_SUNXI_POWER if (!axp_probe()) { axp_set_dcdc_mode(); axp_set_power_supply_output(); #if defined CONFIG_SUNXI_BMU && !defined CONFIG_AXP_LATE_INFO gd->pmu_saved_status = bmu_get_poweron_source(); gd->pmu_runtime_chgcur = axp_get_battery_status(); if (work_mode != WORK_MODE_BOOT) { ret = axp_reset_capacity(); if (!ret) { pr_msg("axp reset capacity fail!\n"); } } #else gd->pmu_saved_status = -1; #endif } #endif #ifdef CONFIG_SUNXI_PMU_EXT if (!pmu_ext_probe()) { pmu_ext_set_dcdc_mode(); } #endif rtc_set_dcxo_off(); if ((work_mode == WORK_MODE_BOOT) || (work_mode == WORK_MODE_CARD_PRODUCT) || (work_mode == WORK_MODE_CARD_UPDATE)) sunxi_set_sramc_mode(); int boot_clock; script_parser_fetch(FDT_PATH_TARGET, "boot_clock", &boot_clock, uboot_spare_head.boot_data.run_clock); clock_set_corepll(boot_clock); /*fix reset circuit detection threshold*/ rtc_set_vccio_det_spare(); tick_printf("CPU=%d MHz,PLL6=%d Mhz,AHB=%d Mhz, APB1=%dMhz MBus=%dMhz\n", clock_get_corepll(), clock_get_pll6(), clock_get_ahb(), clock_get_apb1(),clock_get_mbus()); #ifdef CONFIG_SUNXI_OVERLAY if (get_boot_work_mode() != WORK_MODE_BOOT) { return 0; } if (!sunxi_overlay_apply_merged(working_fdt, gd->new_dtbo)) { pr_err("sunxi overlay merged %sqv\n", (fdt_overlay_apply_verbose(working_fdt, gd->new_dtbo) ? "fail":"ok")); } else { pr_msg("not need merged sunxi overlay\n"); } #endif return 0; } int dram_init(void) { uint dram_size = 0; dram_size = uboot_spare_head.boot_data.dram_scan_size; dram_size = dram_size > 2048 ? 2048 : dram_size; if(dram_size) gd->ram_size = dram_size * 1024 * 1024; else gd->ram_size = get_ram_size((long *)PHYS_SDRAM_0, PHYS_SDRAM_0_SIZE); #ifdef CONFIG_ARM ulong drm_base = 0, drm_size = 0; if (sunxi_probe_secure_os()) { if (!smc_tee_probe_drm_configure(&drm_base, &drm_size)) { pr_msg("drm_base=0x%lx\n", drm_base); pr_msg("drm_size=0x%lx\n", drm_size); pr_msg("dram_base=0x%lx\n", CONFIG_SYS_SDRAM_BASE); pr_msg("dram_size=0x%lx\n", gd->ram_size); if (drm_base + drm_size == CONFIG_SYS_SDRAM_BASE + gd->ram_size) { //drm region resides in end of memory //do not relocate to that area gd->ram_size -= drm_size; } } } #endif return 0; } #ifdef CONFIG_MMC static void mmc_pinmux_setup(int sdc) { #if 0 unsigned int pin; __maybe_unused int pins; switch (sdc) { case 0: /* SDC0: PF0-PF5 */ for (pin = SUNXI_GPF(0); pin <= SUNXI_GPF(5); pin++) { sunxi_gpio_set_cfgpin(pin, SUNXI_GPF_SDC0); sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP); sunxi_gpio_set_drv(pin, 2); } break; case 2: pins = sunxi_name_to_gpio_bank(CONFIG_MMC2_PINS); #if defined(CONFIG_MACH_SUN50IW6) /* 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); } #endif break; default: printf("sunxi: invalid MMC slot %d for pinmux setup\n", sdc); break; } #endif } /* int board_mmc_init(bd_t *bis) { sunxi_mmc_init(bis->bi_card_num); return 0; } */ void board_mmc_pre_init(int card_num) { bd_t *bd; bd = gd->bd; //gd->bd->bi_card_num = card_num; mmc_initialize(bd); } int board_mmc_get_num(void) { return gd->boot_card_num; } void board_mmc_set_num(int num) { gd->boot_card_num = num; } int board_mmc_init(bd_t *bis) { __maybe_unused struct mmc *mmc0, *mmc1; __maybe_unused char buf[512]; mmc_pinmux_setup(board_mmc_get_num()); mmc0 = sunxi_mmc_init(board_mmc_get_num()); if (!mmc0) return -1; #if 0 #if CONFIG_MMC_SUNXI_SLOT_EXTRA != -1 mmc_pinmux_setup(CONFIG_MMC_SUNXI_SLOT_EXTRA); mmc1 = sunxi_mmc_init(CONFIG_MMC_SUNXI_SLOT_EXTRA); if (!mmc1) return -1; #endif #endif return 0; } #endif #ifdef CONFIG_USB_GADGET int g_dnl_board_usb_cable_connected(void) { struct udevice *dev; struct phy phy; int ret; ret = uclass_get_device(UCLASS_USB_DEV_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_err("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 /* * Note this function gets called multiple times. * It must not make any changes to env variables which already exist. */ static void setup_environment(const void *fdt) { #ifdef CONFIG_USB __maybe_unused unsigned int sid[4]; __maybe_unused uint8_t mac_addr[6]; __maybe_unused char ethaddr[16]; __maybe_unused int ret; ret = sunxi_get_sid(sid); if (ret == 0 && sid[0] != 0) { /* * The single words 1 - 3 of the SID have quite a few bits * which are the same on many models, so we take a crc32 * of all 3 words, to get a more unique value. * * Note we only do this on newer SoCs as we cannot change * the algorithm on older SoCs since those have been using * fixed mac-addresses based on only using word 3 for a * long time and changing a fixed mac-address with an * u-boot update is not good. */ sid[3] = crc32(0, (unsigned char *)&sid[1], 12); /* Ensure the NIC specific bytes of the mac are not all 0 */ if ((sid[3] & 0xffffff) == 0) sid[3] |= 0x800000; strcpy(ethaddr, "ethaddr"); /* Non OUI / registered MAC address */ mac_addr[0] = (0 << 4) | 0x02; mac_addr[1] = (sid[0] >> 0) & 0xff; mac_addr[2] = (sid[3] >> 24) & 0xff; mac_addr[3] = (sid[3] >> 16) & 0xff; mac_addr[4] = (sid[3] >> 8) & 0xff; mac_addr[5] = (sid[3] >> 0) & 0xff; eth_env_set_enetaddr(ethaddr, mac_addr); } #endif } int misc_init_r(void) { __maybe_unused int ret; setup_environment(gd->fdt_blob); #if 0 ret = sunxi_usb_phy_probe(); if (ret) return ret; #endif #ifdef CONFIG_USB_ETHER usb_ether_init(); #endif return 0; } int ft_board_setup(void *blob, bd_t *bd) { int __maybe_unused r; /* * Call setup_environment again in case the boot fdt has * ethernet aliases the u-boot copy does not have. */ setup_environment(blob); #ifdef CONFIG_VIDEO_DT_SIMPLEFB r = sunxi_simplefb_setup(blob); if (r) return r; #endif return 0; } static int reserve_bootlogo(void) { #ifndef FPGA_PLATFORM uint32_t *compressed_logo_size = (uint32_t *)(CONFIG_SYS_TEXT_BASE + (3 * 1024 * 1024)); uint32_t *compressed_logo_buf = (uint32_t *)(CONFIG_SYS_TEXT_BASE + (3 * 1024 * 1024) + 16); gd->boot_logo_addr = 0; if (get_boot_work_mode() != WORK_MODE_BOOT) { debug("no boot mode, dont read bootlogo\n"); return 0; } if (((uboot_spare_head.boot_data.func_mask & UBOOT_FUNC_MASK_BIT_BOOTLOGO) != UBOOT_FUNC_MASK_BIT_BOOTLOGO) || (*compressed_logo_size == 0)) { debug("no bootlogo from boot_package\n"); return 0; } gd->start_addr_sp -= ALIGN(*compressed_logo_size, 16); gd->boot_logo_addr = (ulong)map_sysmem(gd->start_addr_sp, *compressed_logo_size); /* reserve logo_buf size addr */ gd->start_addr_sp -= 16; *(uint *)(gd->boot_logo_addr - 16) = *compressed_logo_size; memcpy((void *)gd->boot_logo_addr, compressed_logo_buf, *compressed_logo_size); debug("reserve: 0x%lx from 0x%x: for boot logo in boot package\n", gd->boot_logo_addr, *compressed_logo_size); #endif return 0; } int reserve_arch(void) { reserve_bootlogo(); return 0; }