diff options
Diffstat (limited to 'drivers/misc/fsl_debug_server.c')
-rw-r--r-- | drivers/misc/fsl_debug_server.c | 246 |
1 files changed, 246 insertions, 0 deletions
diff --git a/drivers/misc/fsl_debug_server.c b/drivers/misc/fsl_debug_server.c new file mode 100644 index 0000000000..e080fe6132 --- /dev/null +++ b/drivers/misc/fsl_debug_server.c @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2014 Freescale Semiconductor + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <errno.h> +#include <asm/io.h> +#include <asm/system.h> +#include <asm/arch-fsl-lsch3/immap_lsch3.h> + +#include <fsl_debug_server.h> + +DECLARE_GLOBAL_DATA_PTR; +static int debug_server_ver_info_maj, debug_server_ver_info_min; + +/** + * Copying Debug Server firmware to DDR + */ +static int debug_server_copy_image(const char *title, u64 image_addr, + u32 image_size, u64 debug_server_ram_addr) +{ + debug("%s copied to address %p\n", title, + (void *)debug_server_ram_addr); + memcpy((void *)debug_server_ram_addr, (void *)image_addr, image_size); + + return 0; +} + +/** + * Debug Server FIT image parser checks if the image is in FIT + * format, verifies integrity of the image and calculates + * raw image address and size values. + * + * Returns 0 if success and -1 if any of the above mentioned + * task fail. + **/ +int debug_server_parse_firmware_fit_image(const void **raw_image_addr, + size_t *raw_image_size) +{ + int format; + void *fit_hdr; + int node_offset; + const void *data; + size_t size; + const char *uname = "firmware"; + char *desc; + char *debug_server_ver_info; + char *debug_server_ver_info_major, *debug_server_ver_info_minor; + + /* Check if the image is in NOR flash */ +#ifdef CONFIG_SYS_DEBUG_SERVER_FW_IN_NOR + fit_hdr = (void *)CONFIG_SYS_DEBUG_SERVER_FW_ADDR; +#else +#error "CONFIG_SYS_DEBUG_SERVER_FW_IN_NOR not defined" +#endif + + /* Check if Image is in FIT format */ + format = genimg_get_format(fit_hdr); + if (format != IMAGE_FORMAT_FIT) { + printf("Error! Not a FIT image\n"); + goto out_error; + } + + if (!fit_check_format(fit_hdr)) { + printf("Error! Bad FIT image format\n"); + goto out_error; + } + + node_offset = fit_image_get_node(fit_hdr, uname); + if (node_offset < 0) { + printf("Error! Can not find %s subimage\n", uname); + goto out_error; + } + + /* Verify Debug Server firmware image */ + if (!fit_image_verify(fit_hdr, node_offset)) { + printf("Error! Bad Debug Server firmware hash"); + goto out_error; + } + + if (fit_get_desc(fit_hdr, node_offset, &desc) < 0) { + printf("Error! Failed to get Debug Server fw description"); + goto out_error; + } + + debug_server_ver_info = strstr(desc, "Version"); + debug_server_ver_info_major = strtok(debug_server_ver_info, "."); + debug_server_ver_info_minor = strtok(NULL, "."); + + debug_server_ver_info_maj = + simple_strtoul(debug_server_ver_info_major, NULL, 10); + debug_server_ver_info_min = + simple_strtoul(debug_server_ver_info_minor, NULL, 10); + + /* Debug server version checking */ + if ((debug_server_ver_info_maj < DEBUG_SERVER_VER_MAJOR) || + (debug_server_ver_info_min < DEBUG_SERVER_VER_MINOR)) { + printf("Debug server FW mismatches the min version required\n"); + printf("Expected:%d.%d, Got %d.%d\n", + DEBUG_SERVER_VER_MAJOR, DEBUG_SERVER_VER_MINOR, + debug_server_ver_info_maj, + debug_server_ver_info_min); + goto out_error; + } + + /* Get address and size of raw image */ + fit_image_get_data(fit_hdr, node_offset, &data, &size); + + *raw_image_addr = data; + *raw_image_size = size; + + return 0; + +out_error: + return -1; +} + +/** + * Return the actual size of the Debug Server private DRAM block. + * + * NOTE: For now this function always returns the minimum required size, + * However, in the future, the actual size may be obtained from an environment + * variable. + */ +unsigned long debug_server_get_dram_block_size(void) +{ + return CONFIG_SYS_DEBUG_SERVER_DRAM_BLOCK_MIN_SIZE; +} + +int debug_server_init(void) +{ + struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR); + int error, timeout = CONFIG_SYS_DEBUG_SERVER_TIMEOUT; + int debug_server_boot_status; + u64 debug_server_ram_addr, debug_server_ram_size; + const void *raw_image_addr; + size_t raw_image_size = 0; + + debug("debug_server_init called\n"); + /* + * The Debug Server private DRAM block was already carved at the end of + * DRAM by board_init_f() using CONFIG_SYS_MEM_TOP_HIDE: + */ + debug_server_ram_size = debug_server_get_dram_block_size(); + if (gd->bd->bi_dram[1].start) + debug_server_ram_addr = + gd->bd->bi_dram[1].start + gd->bd->bi_dram[1].size; + else + debug_server_ram_addr = + gd->bd->bi_dram[0].start + gd->bd->bi_dram[0].size; + + error = debug_server_parse_firmware_fit_image(&raw_image_addr, + &raw_image_size); + if (error != 0) + goto out; + + debug("debug server (ram addr = 0x%llx, ram size = 0x%llx)\n", + debug_server_ram_addr, debug_server_ram_size); + /* + * Load the Debug Server FW at the beginning of the Debug Server + * private DRAM block: + */ + debug_server_copy_image("Debug Server Firmware", + (u64)raw_image_addr, raw_image_size, + debug_server_ram_addr); + + /* flush dcache */ + flush_dcache_range((unsigned long)debug_server_ram_addr, + (unsigned long)debug_server_ram_addr + + (unsigned long)debug_server_ram_size); + + /* + * Tell SP that the Debug Server FW is about to be launched. Before that + * populate the following: + * 1. Write the size allocated to SP Memory region into Bits {31:16} of + * SCRATCHRW5. + * 2. Write the start address of the SP memory regions into + * SCRATCHRW5 (Bits {15:0}, contain most significant bits, Bits + * {47:32} of the SP Memory Region physical start address + * (SoC address)) and SCRATCHRW6 (Bits {31:0}). + * 3. To know the Debug Server FW boot status, set bit 0 of SCRATCHRW11 + * to 1. The Debug Server sets this to 0 to indicate a + * successul boot. + * 4. Wakeup SP by writing 0x1F to VSG GIC reg VIGR2. + */ + + /* 512 MB */ + out_le32(&gur->scratchrw[5 - 1], + (u32)((u64)debug_server_ram_addr >> 32) | (0x000D << 16)); + out_le32(&gur->scratchrw[6 - 1], + ((u32)debug_server_ram_addr) & 0xFFFFFFFF); + + out_le32(&gur->scratchrw[11 - 1], DEBUG_SERVER_INIT_STATUS); + /* Allow the changes to reflect in GUR block */ + mb(); + + /* + * Program VGIC to raise an interrupt to SP + */ + out_le32(CONFIG_SYS_FSL_SP_VSG_GIC_VIGR2, 0x1F); + /* Allow the changes to reflect in VIGR2 */ + mb(); + + dmb(); + debug("Polling for Debug server to launch ...\n"); + + while (1) { + debug_server_boot_status = in_le32(&gur->scratchrw[11 - 1]); + if (!(debug_server_boot_status & DEBUG_SERVER_INIT_STATUS_MASK)) + break; + + udelay(1); /* throttle polling */ + if (timeout-- <= 0) + break; + } + + if (timeout <= 0) { + printf("Debug Server FW timed out (boot status: 0x%x)\n", + debug_server_boot_status); + error = -ETIMEDOUT; + goto out; + } + + if (debug_server_boot_status & DEBUG_SERVER_INIT_STATUS_MASK) { + printf("Debug server FW error'ed out (boot status: 0x%x)\n", + debug_server_boot_status); + error = -ENODEV; + goto out; + } + + printf("Debug server booted\n"); + printf("Detected firmware %d.%d, (boot status: 0x0%x)\n", + debug_server_ver_info_maj, debug_server_ver_info_min, + debug_server_boot_status); + +out: + if (error != 0) + debug_server_boot_status = -error; + else + debug_server_boot_status = 0; + + return debug_server_boot_status; +} + |