Merge tag 'u-boot-atmel-fixes-2020.07-a' of https://gitlab.denx.de/u-boot/custodians...
[oweals/u-boot.git] / arch / arm / mach-imx / imx_bootaux.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2016 Freescale Semiconductor, Inc.
4  */
5
6 #include <common.h>
7 #include <log.h>
8 #include <asm/io.h>
9 #include <asm/mach-imx/sys_proto.h>
10 #include <command.h>
11 #include <elf.h>
12 #include <imx_sip.h>
13 #include <linux/compiler.h>
14 #include <cpu_func.h>
15
16 int arch_auxiliary_core_up(u32 core_id, ulong addr)
17 {
18         ulong stack, pc;
19
20         if (!addr)
21                 return -EINVAL;
22
23 #ifdef CONFIG_IMX8M
24         stack = *(u32 *)addr;
25         pc = *(u32 *)(addr + 4);
26 #else
27         /*
28          * handling ELF64 binaries
29          * isn't supported yet.
30          */
31         if (valid_elf_image(addr)) {
32                 stack = 0x0;
33                 pc = load_elf_image_phdr(addr);
34                 if (!pc)
35                         return CMD_RET_FAILURE;
36
37         } else {
38                 /*
39                  * Assume binary file with vector table at the beginning.
40                  * Cortex-M4 vector tables start with the stack pointer (SP)
41                  * and reset vector (initial PC).
42                  */
43                 stack = *(u32 *)addr;
44                 pc = *(u32 *)(addr + 4);
45         }
46 #endif
47         printf("## Starting auxiliary core stack = 0x%08lX, pc = 0x%08lX...\n",
48                stack, pc);
49
50         /* Set the stack and pc to M4 bootROM */
51         writel(stack, M4_BOOTROM_BASE_ADDR);
52         writel(pc, M4_BOOTROM_BASE_ADDR + 4);
53
54         flush_dcache_all();
55
56         /* Enable M4 */
57 #ifdef CONFIG_IMX8M
58         call_imx_sip(IMX_SIP_SRC, IMX_SIP_SRC_M4_START, 0, 0, 0);
59 #else
60         clrsetbits_le32(SRC_BASE_ADDR + SRC_M4_REG_OFFSET,
61                         SRC_M4C_NON_SCLR_RST_MASK, SRC_M4_ENABLE_MASK);
62 #endif
63
64         return 0;
65 }
66
67 int arch_auxiliary_core_check_up(u32 core_id)
68 {
69 #ifdef CONFIG_IMX8M
70         return call_imx_sip(IMX_SIP_SRC, IMX_SIP_SRC_M4_STARTED, 0, 0, 0);
71 #else
72         unsigned int val;
73
74         val = readl(SRC_BASE_ADDR + SRC_M4_REG_OFFSET);
75
76         if (val & SRC_M4C_NON_SCLR_RST_MASK)
77                 return 0;  /* assert in reset */
78
79         return 1;
80 #endif
81 }
82
83 /*
84  * To i.MX6SX and i.MX7D, the image supported by bootaux needs
85  * the reset vector at the head for the image, with SP and PC
86  * as the first two words.
87  *
88  * Per the cortex-M reference manual, the reset vector of M4 needs
89  * to exist at 0x0 (TCMUL). The PC and SP are the first two addresses
90  * of that vector.  So to boot M4, the A core must build the M4's reset
91  * vector with getting the PC and SP from image and filling them to
92  * TCMUL. When M4 is kicked, it will load the PC and SP by itself.
93  * The TCMUL is mapped to (M4_BOOTROM_BASE_ADDR) at A core side for
94  * accessing the M4 TCMUL.
95  */
96 static int do_bootaux(struct cmd_tbl *cmdtp, int flag, int argc,
97                       char *const argv[])
98 {
99         ulong addr;
100         int ret, up;
101
102         if (argc < 2)
103                 return CMD_RET_USAGE;
104
105         up = arch_auxiliary_core_check_up(0);
106         if (up) {
107                 printf("## Auxiliary core is already up\n");
108                 return CMD_RET_SUCCESS;
109         }
110
111         addr = simple_strtoul(argv[1], NULL, 16);
112
113         if (!addr)
114                 return CMD_RET_FAILURE;
115
116         ret = arch_auxiliary_core_up(0, addr);
117         if (ret)
118                 return CMD_RET_FAILURE;
119
120         return CMD_RET_SUCCESS;
121 }
122
123 U_BOOT_CMD(
124         bootaux, CONFIG_SYS_MAXARGS, 1, do_bootaux,
125         "Start auxiliary core",
126         ""
127 );