diff --git a/board/sunxi/board.c b/board/sunxi/board.c index 20c5dd90f94..ac99bf712c3 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -51,13 +51,12 @@ #include #include -DECLARE_GLOBAL_DATA_PTR; - #ifdef CONFIG_RADXA_UNIFIED_IMAGE -extern void radxa_set_board_type(void); -extern void radxa_set_compat_fdt(void); +#include "cubie_board.h" #endif +DECLARE_GLOBAL_DATA_PTR; + void i2c_init_board(void) { #ifdef CONFIG_I2C0_ENABLE @@ -891,8 +890,10 @@ int board_late_init(void) #endif #ifdef CONFIG_RADXA_UNIFIED_IMAGE - radxa_set_board_type(); - radxa_set_compat_fdt(); + if (!radxa_set_board_type()) { + radxa_enable_boot_led(); + radxa_set_compat_fdt(); + } #endif return 0; } diff --git a/board/sunxi/cubie_board.c b/board/sunxi/cubie_board.c index 0e321974de5..97fb94cf5f8 100644 --- a/board/sunxi/cubie_board.c +++ b/board/sunxi/cubie_board.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -13,6 +14,8 @@ static const struct hw_info_def hw_info[] = { .pcie_power_gpio = "PD20", .pcie_wake_gpio = "PD21", .pcie_reset_gpio = "PD22", + .boot_led_gpio = SUNXI_GPM(2), + .boot_led_on_value = 1, .hw_id_level = 1, .hw_id_lower_bound = 1750, .hw_id_upper_bound = 1850, //1800mv +/- 50mv @@ -23,6 +26,8 @@ static const struct hw_info_def hw_info[] = { .pcie_power_gpio = "PE11", .pcie_wake_gpio = "PE12", .pcie_reset_gpio = "PE13", + .boot_led_gpio = SUNXI_GPJ(26), + .boot_led_on_value = 0, .hw_id_level = 1, .hw_id_lower_bound = 1519, .hw_id_upper_bound = 1619, //1569mv +/- 50mv @@ -33,6 +38,8 @@ static const struct hw_info_def hw_info[] = { .pcie_power_gpio = "PD20", .pcie_wake_gpio = "PD21", .pcie_reset_gpio = "PD22", + .boot_led_gpio = SUNXI_GPM(2), + .boot_led_on_value = 1, .hw_id_level = 1, .hw_id_lower_bound = 1265, .hw_id_upper_bound = 1365, //1315mv +/- 50mv @@ -43,21 +50,25 @@ static const struct hw_info_def hw_info[] = { .pcie_power_gpio = "PD20", .pcie_wake_gpio = "PD21", .pcie_reset_gpio = "PD22", + .boot_led_gpio = -1, + .boot_led_on_value = 0, .hw_id_level = 1, .hw_id_lower_bound = 1000, .hw_id_upper_bound = 1100, //1050mv +/- 50mv } }; -void radxa_set_board_type(void) +int radxa_set_board_type(void) { - int i, vol, level; + int i, ret, vol, level; sunxi_gpio_set_cfgpin(SUNXI_GPK(24), SUNXI_GPIO_INPUT); - if (gpio_request(HW_ID_GPIO, "hw_id_level") != 0) { - debug("Failed to request GPIO %d for hardware ID detection\n", HW_ID_GPIO); - return; + ret = gpio_request(HW_ID_GPIO, "hw_id_level"); + if (ret) { + debug("Failed to request GPIO %d for hardware ID detection: %d\n", + HW_ID_GPIO, ret); + return ret; } gpio_direction_input(HW_ID_GPIO); level = gpio_get_value(HW_ID_GPIO); @@ -71,11 +82,35 @@ void radxa_set_board_type(void) vol <= hw_info[i].hw_id_upper_bound && level == hw_info[i].hw_id_level) { board_index = i; - return; + return 0; } } printf("No compatible board type found for vol=%d, level=%d\n", vol, level); - return; + return -ENODEV; +} + +void radxa_enable_boot_led(void) +{ + const struct hw_info_def *info = &hw_info[board_index]; + int ret; + + if (info->boot_led_gpio < 0) + return; + + ret = gpio_request(info->boot_led_gpio, "boot_led"); + if (ret) { + printf("Failed to request boot LED GPIO %d: %d\n", + info->boot_led_gpio, ret); + return; + } + + ret = gpio_direction_output(info->boot_led_gpio, + info->boot_led_on_value); + if (ret) + printf("Failed to enable boot LED GPIO %d: %d\n", + info->boot_led_gpio, ret); + + gpio_free(info->boot_led_gpio); } void radxa_set_compat_fdt(void) diff --git a/board/sunxi/cubie_board.h b/board/sunxi/cubie_board.h index 95ec49e1a7a..6894e219a4c 100644 --- a/board/sunxi/cubie_board.h +++ b/board/sunxi/cubie_board.h @@ -13,11 +13,14 @@ struct hw_info_def { const char* pcie_power_gpio; const char* pcie_wake_gpio; const char* pcie_reset_gpio; + int boot_led_gpio; + int boot_led_on_value; unsigned int hw_id_level; unsigned int hw_id_lower_bound; unsigned int hw_id_upper_bound; }; -void radxa_set_board_type(void); +int radxa_set_board_type(void); +void radxa_enable_boot_led(void); void radxa_set_compat_fdt(void); struct hw_info_def radxa_get_hw_info(void); diff --git a/cmd/sunxi_boot_arisc.c b/cmd/sunxi_boot_arisc.c index 0c6fbeb2e02..7b4147f6edf 100644 --- a/cmd/sunxi_boot_arisc.c +++ b/cmd/sunxi_boot_arisc.c @@ -2,11 +2,104 @@ #include #include +#include +#include +#include +#include #include #include #include #include +#ifdef CONFIG_MACH_SUN60I_A733 +/* + * Temporary bring-up interface for the A733 ddr.bin with SHA-256 + * d89804f404f2eef6ef5b03d82a310ef0906c4db8ded760be221b131f5c813a05. + * The blob keeps its 96-word trained DRAM parameter block in SRAM. Keep all + * layout checks here so a different blob fails closed instead of passing + * arbitrary data to ARISC. + */ +#define A733_LIBDRAM_GETTER_OFFSET 0x3e0 +#define A733_LIBDRAM_GETTER_CODE 0x47704800 +#define A733_LIBDRAM_PARA_PTR_OFFSET 0x3e4 +#define A733_LIBDRAM_PARA_OFFSET 0x38fe0 +#define A733_LIBDRAM_BSS_START_OFFSET 0x54 +#define A733_LIBDRAM_BSS_END_OFFSET 0x58 +#define A733_LIBDRAM_BSS_START 0x000c8bdc +#define A733_LIBDRAM_BSS_END 0x000c94a4 +#define A733_DRAM_PARA_WORDS 96 +#define A733_DRAM_FDT_EXTRA_SIZE 4096 + +static int sunxi_a733_inject_dram_para(void *fdt) +{ + uintptr_t blob = CONFIG_SUNXI_LIBDRAM_BASE; + u32 para[A733_DRAM_PARA_WORDS]; + u32 getter_code, para_addr, bss_start, bss_end; + char prop[16]; + int node, ret, i; + + getter_code = readl((void *)(blob + A733_LIBDRAM_GETTER_OFFSET)); + para_addr = readl((void *)(blob + A733_LIBDRAM_PARA_PTR_OFFSET)); + bss_start = readl((void *)(blob + A733_LIBDRAM_BSS_START_OFFSET)); + bss_end = readl((void *)(blob + A733_LIBDRAM_BSS_END_OFFSET)); + + if (getter_code != A733_LIBDRAM_GETTER_CODE || + para_addr != blob + A733_LIBDRAM_PARA_OFFSET || + bss_start != A733_LIBDRAM_BSS_START || + bss_end != A733_LIBDRAM_BSS_END || + para_addr + sizeof(para) > bss_end) { + printf("[SCP] ERROR: unsupported A733 ddr.bin layout\n"); + return -EINVAL; + } + + for (i = 0; i < A733_DRAM_PARA_WORDS; i++) + para[i] = readl((void *)(uintptr_t)(para_addr + i * sizeof(u32))); + + if (para[0] < 400 || para[0] > 4000 || + (para[1] != 8 && para[1] != 9) || + !para[6] || !para[7] || !para[30]) { + printf("[SCP] ERROR: invalid trained DRAM parameters: " + "clk=%x type=%x para1=%x para2=%x tpr13=%x\n", + para[0], para[1], para[6], para[7], para[30]); + return -EINVAL; + } + + ret = fdt_check_header(fdt); + if (ret) + return ret; + + ret = fdt_increase_size(fdt, A733_DRAM_FDT_EXTRA_SIZE); + if (ret) { + printf("[SCP] ERROR: failed to grow FDT: %s\n", + fdt_strerror(ret)); + return ret; + } + + node = fdt_path_offset(fdt, "/dram"); + if (node < 0) { + printf("[SCP] ERROR: no /dram node: %s\n", fdt_strerror(node)); + return node; + } + + for (i = 0; i < A733_DRAM_PARA_WORDS; i++) { + sprintf(prop, "dram_para%02d", i); + ret = fdt_setprop_u32(fdt, node, prop, para[i]); + if (ret) { + printf("[SCP] ERROR: failed to set %s: %s\n", + prop, fdt_strerror(ret)); + return ret; + } + } + + printf("[SCP] INFO: injected trained DRAM parameters: " + "clk=%x type=%x para1=%x para2=%x tpr13=%x\n", + para[0], para[1], para[6], para[7], para[30]); + flush_cache((ulong)fdt, fdt_totalsize(fdt)); + + return 0; +} +#endif + static u32 sunxi_smc_call_atf(ulong arg0, ulong arg1, ulong arg2, ulong arg3, ulong pResult) { struct arm_smccc_res param = { 0 }; @@ -38,6 +131,13 @@ static int do_sunxi_boot_arisc(struct cmd_tbl *cmdtp, int flag, int argc, } else { printf("[SCP] WARNING: dtb magic mismatch, expected 0xedfe0dd0 got 0x%08x, power management may malfunction\n", magic); } + +#ifdef CONFIG_MACH_SUN60I_A733 + if (sunxi_a733_inject_dram_para((void *)(uintptr_t)dtb_addr)) { + printf("[SCP] ERROR: refusing to start ARISC without trained DRAM parameters\n"); + return CMD_RET_FAILURE; + } +#endif } }