riscv: Add boot hartid to device tree
[platform/kernel/u-boot.git] / arch / riscv / lib / bootm.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2011 Andes Technology Corporation
4  * Shawn Lin, Andes Technology Corporation <nobuhiro@andestech.com>
5  * Macpaul Lin, Andes Technology Corporation <macpaul@andestech.com>
6  * Rick Chen, Andes Technology Corporation <rick@andestech.com>
7  */
8
9 #include <common.h>
10 #include <command.h>
11 #include <dm.h>
12 #include <fdt_support.h>
13 #include <hang.h>
14 #include <dm/root.h>
15 #include <image.h>
16 #include <asm/byteorder.h>
17 #include <asm/csr.h>
18 #include <asm/smp.h>
19 #include <dm/device.h>
20 #include <dm/root.h>
21 #include <u-boot/zlib.h>
22
23 DECLARE_GLOBAL_DATA_PTR;
24
25 __weak void board_quiesce_devices(void)
26 {
27 }
28
29 int arch_fixup_fdt(void *blob)
30 {
31 #ifdef CONFIG_EFI_LOADER
32         int err;
33         u32 size;
34         int chosen_offset;
35
36         size = fdt_totalsize(blob);
37         err  = fdt_open_into(blob, blob, size + 32);
38         if (err < 0) {
39                 printf("Device Tree can't be expanded to accommodate new node");
40                 return err;
41         }
42         chosen_offset = fdt_path_offset(blob, "/chosen");
43         if (chosen_offset < 0) {
44                 err = fdt_add_subnode(blob, 0, "chosen");
45                 if (err < 0) {
46                         printf("chosen node can not be added\n");
47                         return err;
48                 }
49         }
50         /* Overwrite the boot-hartid as U-Boot is the last stage BL */
51         fdt_setprop_u32(blob, chosen_offset, "boot-hartid", gd->arch.boot_hart);
52 #endif
53         return 0;
54 }
55
56 /**
57  * announce_and_cleanup() - Print message and prepare for kernel boot
58  *
59  * @fake: non-zero to do everything except actually boot
60  */
61 static void announce_and_cleanup(int fake)
62 {
63         printf("\nStarting kernel ...%s\n\n", fake ?
64                 "(fake run for tracing)" : "");
65         bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel");
66 #ifdef CONFIG_BOOTSTAGE_FDT
67         bootstage_fdt_add_report();
68 #endif
69 #ifdef CONFIG_BOOTSTAGE_REPORT
70         bootstage_report();
71 #endif
72
73 #ifdef CONFIG_USB_DEVICE
74         udc_disconnect();
75 #endif
76
77         board_quiesce_devices();
78
79         /*
80          * Call remove function of all devices with a removal flag set.
81          * This may be useful for last-stage operations, like cancelling
82          * of DMA operation or releasing device internal buffers.
83          */
84         dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL);
85
86         cleanup_before_linux();
87 }
88
89 static void boot_prep_linux(bootm_headers_t *images)
90 {
91         if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) {
92 #ifdef CONFIG_OF_LIBFDT
93                 debug("using: FDT\n");
94                 if (image_setup_linux(images)) {
95                         printf("FDT creation failed! hanging...");
96                         hang();
97                 }
98 #endif
99         } else {
100                 printf("Device tree not found or missing FDT support\n");
101                 hang();
102         }
103 }
104
105 static void boot_jump_linux(bootm_headers_t *images, int flag)
106 {
107         void (*kernel)(ulong hart, void *dtb);
108         int fake = (flag & BOOTM_STATE_OS_FAKE_GO);
109 #ifdef CONFIG_SMP
110         int ret;
111 #endif
112
113         kernel = (void (*)(ulong, void *))images->ep;
114
115         bootstage_mark(BOOTSTAGE_ID_RUN_OS);
116
117         debug("## Transferring control to kernel (at address %08lx) ...\n",
118               (ulong)kernel);
119
120         announce_and_cleanup(fake);
121
122         if (!fake) {
123                 if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) {
124 #ifdef CONFIG_SMP
125                         ret = smp_call_function(images->ep,
126                                                 (ulong)images->ft_addr, 0, 0);
127                         if (ret)
128                                 hang();
129 #endif
130                         kernel(gd->arch.boot_hart, images->ft_addr);
131                 }
132         }
133 }
134
135 int do_bootm_linux(int flag, int argc, char * const argv[],
136                    bootm_headers_t *images)
137 {
138         /* No need for those on RISC-V */
139         if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE)
140                 return -1;
141
142         if (flag & BOOTM_STATE_OS_PREP) {
143                 boot_prep_linux(images);
144                 return 0;
145         }
146
147         if (flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO)) {
148                 boot_jump_linux(images, flag);
149                 return 0;
150         }
151
152         boot_prep_linux(images);
153         boot_jump_linux(images, flag);
154         return 0;
155 }
156
157 int do_bootm_vxworks(int flag, int argc, char * const argv[],
158                      bootm_headers_t *images)
159 {
160         return do_bootm_linux(flag, argc, argv, images);
161 }