// SPDX-License-Identifier: GPL-2.0+ /* * (C) Copyright 2008 - 2013 Tensilica Inc. * (C) Copyright 2014 Cadence Design Systems Inc. */ #include #include #include #include #include #include #include #include #include #include #include DECLARE_GLOBAL_DATA_PTR; /* * Setup boot-parameters. */ static struct bp_tag *setup_first_tag(struct bp_tag *params) { params->id = BP_TAG_FIRST; params->size = sizeof(long); *(unsigned long *)¶ms->data = BP_VERSION; return bp_tag_next(params); } static struct bp_tag *setup_last_tag(struct bp_tag *params) { params->id = BP_TAG_LAST; params->size = 0; return bp_tag_next(params); } static struct bp_tag *setup_memory_tag(struct bp_tag *params) { struct meminfo *mem; params->id = BP_TAG_MEMORY; params->size = sizeof(struct meminfo); mem = (struct meminfo *)params->data; mem->type = MEMORY_TYPE_CONVENTIONAL; mem->start = PHYSADDR(gd->ram_base); mem->end = PHYSADDR(gd->ram_base + gd->ram_size); printf(" MEMORY: tag:0x%04x, type:0X%lx, start:0X%lx, end:0X%lx\n", BP_TAG_MEMORY, mem->type, mem->start, mem->end); return bp_tag_next(params); } static struct bp_tag *setup_commandline_tag(struct bp_tag *params, char *cmdline) { int len; if (!cmdline) return params; len = strlen(cmdline); params->id = BP_TAG_COMMAND_LINE; params->size = (len + 3) & -4; strcpy((char *)params->data, cmdline); printf(" COMMAND_LINE: tag:0x%04x, size:%u, data:'%s'\n", BP_TAG_COMMAND_LINE, params->size, cmdline); return bp_tag_next(params); } static struct bp_tag *setup_ramdisk_tag(struct bp_tag *params, unsigned long rd_start, unsigned long rd_end) { struct meminfo *mem; if (rd_start == rd_end) return params; /* Add a single banked memory */ params->id = BP_TAG_INITRD; params->size = sizeof(struct meminfo); mem = (struct meminfo *)params->data; mem->type = MEMORY_TYPE_CONVENTIONAL; mem->start = PHYSADDR(rd_start); mem->end = PHYSADDR(rd_end); printf(" INITRD: tag:0x%x, type:0X%04lx, start:0X%lx, end:0X%lx\n", BP_TAG_INITRD, mem->type, mem->start, mem->end); return bp_tag_next(params); } static struct bp_tag *setup_serial_tag(struct bp_tag *params) { params->id = BP_TAG_SERIAL_BAUDRATE; params->size = sizeof(unsigned long); params->data[0] = gd->baudrate; printf(" SERIAL_BAUDRATE: tag:0x%04x, size:%u, baudrate:%lu\n", BP_TAG_SERIAL_BAUDRATE, params->size, params->data[0]); return bp_tag_next(params); } #ifdef CONFIG_OF_LIBFDT static struct bp_tag *setup_fdt_tag(struct bp_tag *params, void *fdt_start) { params->id = BP_TAG_FDT; params->size = sizeof(unsigned long); params->data[0] = (unsigned long)fdt_start; printf(" FDT: tag:0x%04x, size:%u, start:0x%lx\n", BP_TAG_FDT, params->size, params->data[0]); return bp_tag_next(params); } #endif /* * Boot Linux. */ int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images) { struct bp_tag *params, *params_start; ulong initrd_start, initrd_end; char *commandline = env_get("bootargs"); if (!(flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO))) return 0; show_boot_progress(15); if (images->rd_start) { initrd_start = images->rd_start; initrd_end = images->rd_end; } else { initrd_start = 0; initrd_end = 0; } params_start = (struct bp_tag *)gd->bd->bi_boot_params; params = params_start; params = setup_first_tag(params); params = setup_memory_tag(params); params = setup_commandline_tag(params, commandline); params = setup_serial_tag(params); if (initrd_start) params = setup_ramdisk_tag(params, initrd_start, initrd_end); #ifdef CONFIG_OF_LIBFDT if (images->ft_addr) params = setup_fdt_tag(params, images->ft_addr); #endif printf("\n"); params = setup_last_tag(params); show_boot_progress(15); printf("Transferring Control to Linux @0x%08lx ...\n\n", (ulong)images->ep); flush_dcache_range((unsigned long)params_start, (unsigned long)params); if (flag & BOOTM_STATE_OS_FAKE_GO) return 0; /* * _start() in vmlinux expects boot params in register a2. * NOTE: * Disable/delete your u-boot breakpoints before stepping into linux. */ asm volatile ("mov a2, %0\n\t" "jx %1\n\t" : : "a" (params_start), "a" (images->ep) : "a2"); /* Does not return */ return 1; }