blob: e2aafd0822d33d3076b81ea50b680d00faab23df [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <common.h>
#include <part.h>
#include <zircon/zircon.h>
#define PDEV_VID_GOOGLE 3
#define PDEV_PID_MADRONE 4
#define NVRAM_LENGTH (1024 * 1024)
static const zbi_cpu_config_t cpu_config = {
.cluster_count = 1,
.clusters = {
{
.cpu_count = 4,
},
},
};
static const zbi_mem_range_t mem_config[] = {
{
.type = ZBI_MEM_RANGE_RAM,
.paddr = 0x40000000,
.length = 0xc0000000, // 3GB
},
{
.type = ZBI_MEM_RANGE_PERIPHERAL,
.paddr = 0,
.length = 0x40000000,
},
};
static const dcfg_simple_t uart_driver = {
.mmio_phys = 0x30860000,
.irq = 58,
};
static const dcfg_arm_gicv3_driver_t gicv3_driver = {
.mmio_phys = 0x38800000,
.gicd_offset = 0x00000,
.gicr_offset = 0x80000,
.gicr_stride = 0x20000,
.ipi_base = 9,
// Used for Errata e11171
.mx8_gpr_phys = 0x30340000,
};
static const dcfg_arm_psci_driver_t psci_driver = {
.use_hvc = false,
};
static const dcfg_arm_generic_timer_driver_t timer_driver = {
.irq_phys = 30,
.irq_virt = 27,
.freq_override = 8333333,
};
static const zbi_platform_id_t platform_id = {
.vid = PDEV_VID_GOOGLE,
.pid = PDEV_PID_MADRONE,
.board_name = "madrone",
};
enum {
PART_ZIRCON_A,
PART_ZIRCON_B,
PART_ZIRCON_R,
PART_SYS_CONFIG,
PART_FACTORY_CONFIG,
PART_FVM,
PART_COUNT,
};
static zbi_partition_map_t partition_map = {
// .block_count filled in below
// .block_size filled in below
.guid = {},
.partition_count = PART_COUNT,
.partitions = {
{
.type_guid = GUID_ZIRCON_A_VALUE,
.uniq_guid = {},
// .first_block filled in below
// .last_block filled in below
.flags = 0,
.name = "zircon-a",
},
{
.type_guid = GUID_ZIRCON_B_VALUE,
.uniq_guid = {},
// .first_block filled in below
// .last_block filled in below
.flags = 0,
.name = "zircon-b",
},
{
.type_guid = GUID_ZIRCON_R_VALUE,
.uniq_guid = {},
// .first_block filled in below
// .last_block filled in below
.flags = 0,
.name = "zircon-r",
},
{
.type_guid = GUID_SYS_CONFIG_VALUE,
.uniq_guid = {},
// .first_block filled in below
// .last_block filled in below
.flags = 0,
.name = "sys-config",
},
{
.type_guid = GUID_FACTORY_CONFIG_VALUE,
.uniq_guid = {},
// .first_block filled in below
// .last_block filled in below
.flags = 0,
.name = "factory",
},
{
.type_guid = GUID_FVM_VALUE,
.uniq_guid = {},
// .first_block filled in below
// .last_block filled in below
.flags = 0,
.name = "fvm",
},
},
};
static void add_partition_map(zbi_header_t* zbi) {
struct blk_desc* dev_desc;
disk_partition_t boot_a_info;
disk_partition_t boot_b_info;
disk_partition_t system_a_info;
disk_partition_t misc_info;
disk_partition_t factory_info;
disk_partition_t userdata_info;
dev_desc = blk_get_dev("mmc", 0);
if (!dev_desc || dev_desc->type == DEV_TYPE_UNKNOWN) {
printf("could not find MMC device for partition map\n");
return;
}
if (part_get_info_by_name(dev_desc, "boot_a", &boot_a_info)) {
printf("could not find boot_a partition\n");
return;
}
if (part_get_info_by_name(dev_desc, "boot_b", &boot_b_info)) {
printf("could not find boot_b partition\n");
return;
}
if (part_get_info_by_name(dev_desc, "system_a", &system_a_info)) {
printf("could not find system_a partition\n");
return;
}
if (part_get_info_by_name(dev_desc, "misc", &misc_info)) {
printf("could not find misc partition\n");
return;
}
if (part_get_info_by_name(dev_desc, "factory", &factory_info)) {
printf("could not find factory partition\n");
return;
}
if (part_get_info_by_name(dev_desc, "userdata", &userdata_info)) {
printf("could not find userdata partition\n");
return;
}
// map boot_a partition to ZIRCON_A
partition_map.partitions[PART_ZIRCON_A].first_block = boot_a_info.start;
partition_map.partitions[PART_ZIRCON_A].last_block = boot_a_info.start + boot_a_info.size - 1;
// map boot_b partition to ZIRCON_B
partition_map.partitions[PART_ZIRCON_B].first_block = boot_b_info.start;
partition_map.partitions[PART_ZIRCON_B].last_block = boot_b_info.start + boot_b_info.size - 1;
// map system_a partition to ZIRCON_R
partition_map.partitions[PART_ZIRCON_R].first_block = system_a_info.start;
partition_map.partitions[PART_ZIRCON_R].last_block = system_a_info.start +
system_a_info.size - 1;
// map misc partition to SYS_CONFIG
partition_map.partitions[PART_SYS_CONFIG].first_block = misc_info.start;
partition_map.partitions[PART_SYS_CONFIG].last_block = misc_info.start + misc_info.size - 1;
// map factory partition to FACTORY_CONFIG
partition_map.partitions[PART_FACTORY_CONFIG].first_block = factory_info.start;
partition_map.partitions[PART_FACTORY_CONFIG].last_block = factory_info.start +
factory_info.size - 1;
// map userdata partition to FVM
partition_map.partitions[PART_FVM].first_block = userdata_info.start;
partition_map.partitions[PART_FVM].last_block = userdata_info.start +
userdata_info.size - 1;
partition_map.block_count = userdata_info.start + userdata_info.size;
partition_map.block_size = userdata_info.blksz;
zircon_append_boot_item(zbi, ZBI_TYPE_DRV_PARTITION_MAP, 0, &partition_map,
sizeof(zbi_partition_map_t) +
partition_map.partition_count * sizeof(zbi_partition_t));
}
#if 0
static int hex_digit(char ch) {
if (ch >= '0' && ch <= '9') {
return ch - '0';
} else if (ch >= 'a' && ch <= 'f') {
return ch - 'a' + 10;
} else if (ch >= 'A' && ch <= 'F') {
return ch - 'A' + 10;
} else {
return -1;
}
}
static void add_eth_mac_address(zbi_header_t* zbi) {
char* str = getenv("eth_mac");
uint8_t addr[6];
// this would be easier with sscanf
int i;
for (i = 0; i < 6; i++) {
unsigned left, right;
if (str[0] && str[1] && (left = hex_digit(*str++)) >= 0 &&
(right = hex_digit(*str++)) >= 0) {
addr[i] = (left << 4) | right;
} else {
goto failed;
}
if (i < 5 && *str++ != ':') {
goto failed;
}
}
zircon_append_boot_item(zbi, ZBI_TYPE_DRV_MAC_ADDRESS, 0, addr, sizeof(addr));
return;
failed:
printf("MAC address parsing failed for \"%s\"\n", getenv("eth_mac"));
}
#endif
int zircon_preboot(zbi_header_t* zbi) {
// add CPU configuration
zircon_append_boot_item(zbi, ZBI_TYPE_CPU_CONFIG, 0, &cpu_config,
sizeof(zbi_cpu_config_t) +
sizeof(zbi_cpu_cluster_t) * cpu_config.cluster_count);
// allocate crashlog save area at end of RAM
zbi_nvram_t nvram;
nvram.base = mem_config[0].length - NVRAM_LENGTH;
nvram.length = NVRAM_LENGTH;
zircon_append_boot_item(zbi, ZBI_TYPE_NVRAM, 0, &nvram, sizeof(nvram));
// add memory configuration
zircon_append_boot_item(zbi, ZBI_TYPE_MEM_CONFIG, 0, &mem_config, sizeof(mem_config));
// add kernel drivers
zircon_append_boot_item(zbi, ZBI_TYPE_KERNEL_DRIVER, KDRV_NXP_IMX_UART, &uart_driver,
sizeof(uart_driver));
zircon_append_boot_item(zbi, ZBI_TYPE_KERNEL_DRIVER, KDRV_ARM_GIC_V3, &gicv3_driver,
sizeof(gicv3_driver));
zircon_append_boot_item(zbi, ZBI_TYPE_KERNEL_DRIVER, KDRV_ARM_PSCI, &psci_driver,
sizeof(psci_driver));
zircon_append_boot_item(zbi, ZBI_TYPE_KERNEL_DRIVER, KDRV_ARM_GENERIC_TIMER, &timer_driver,
sizeof(timer_driver));
// add platform ID
zircon_append_boot_item(zbi, ZBI_TYPE_PLATFORM_ID, 0, &platform_id, sizeof(platform_id));
add_partition_map(zbi);
// add_eth_mac_address(zbi);
return 0;
}