Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions board/sunxi/board.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,12 @@
#include <sy8106a.h>
#include <asm/setup.h>

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
Expand Down Expand Up @@ -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;
}
Expand Down
49 changes: 42 additions & 7 deletions board/sunxi/cubie_board.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <env.h>
#include <errno.h>
#include <sunxi_gpio.h>
#include <asm-generic/gpio.h>
#include <sunxi_gpadc.h>
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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);
Expand All @@ -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)
Expand Down
5 changes: 4 additions & 1 deletion board/sunxi/cubie_board.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
100 changes: 100 additions & 0 deletions cmd/sunxi_boot_arisc.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,104 @@

#include <command.h>
#include <cpu_func.h>
#include <fdt_support.h>
#include <asm/io.h>
#include <linux/errno.h>
#include <linux/libfdt.h>
#include <linux/string.h>
#include <linux/arm-smccc.h>
#include <linux/types.h>
#include <env.h>

#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 };
Expand Down Expand Up @@ -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
}
}

Expand Down