]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/arm/cpu/armv8/fsl-lsch3/mp.c
Merge branch 'u-boot-marvell/master' into 'u-boot-arm/master'
[karo-tx-uboot.git] / arch / arm / cpu / armv8 / fsl-lsch3 / mp.c
1 /*
2  * Copyright 2014 Freescale Semiconductor, Inc.
3  *
4  * SPDX-License-Identifier:     GPL-2.0+
5  */
6
7 #include <common.h>
8 #include <asm/io.h>
9 #include <asm/system.h>
10 #include <asm/io.h>
11 #include <asm/arch-fsl-lsch3/immap_lsch3.h>
12 #include "mp.h"
13
14 DECLARE_GLOBAL_DATA_PTR;
15
16 void *get_spin_tbl_addr(void)
17 {
18         return &__spin_table;
19 }
20
21 phys_addr_t determine_mp_bootpg(void)
22 {
23         return (phys_addr_t)&secondary_boot_code;
24 }
25
26 int fsl_lsch3_wake_seconday_cores(void)
27 {
28         struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
29         struct ccsr_reset __iomem *rst = (void *)(CONFIG_SYS_FSL_RST_ADDR);
30         u32 cores, cpu_up_mask = 1;
31         int i, timeout = 10;
32         u64 *table = get_spin_tbl_addr();
33
34         cores = cpu_mask();
35         /* Clear spin table so that secondary processors
36          * observe the correct value after waking up from wfe.
37          */
38         memset(table, 0, CONFIG_MAX_CPUS*SPIN_TABLE_ELEM_SIZE);
39         flush_dcache_range((unsigned long)table,
40                            (unsigned long)table +
41                            (CONFIG_MAX_CPUS*SPIN_TABLE_ELEM_SIZE));
42
43         printf("Waking secondary cores to start from %lx\n", gd->relocaddr);
44         out_le32(&gur->bootlocptrh, (u32)(gd->relocaddr >> 32));
45         out_le32(&gur->bootlocptrl, (u32)gd->relocaddr);
46         out_le32(&gur->scratchrw[6], 1);
47         asm volatile("dsb st" : : : "memory");
48         rst->brrl = cores;
49         asm volatile("dsb st" : : : "memory");
50
51         /* This is needed as a precautionary measure.
52          * If some code before this has accidentally  released the secondary
53          * cores then the pre-bootloader code will trap them in a "wfe" unless
54          * the scratchrw[6] is set. In this case we need a sev here to get these
55          * cores moving again.
56          */
57         asm volatile("sev");
58
59         while (timeout--) {
60                 flush_dcache_range((unsigned long)table, (unsigned long)table +
61                                    CONFIG_MAX_CPUS * 64);
62                 for (i = 1; i < CONFIG_MAX_CPUS; i++) {
63                         if (table[i * WORDS_PER_SPIN_TABLE_ENTRY +
64                                         SPIN_TABLE_ELEM_STATUS_IDX])
65                                 cpu_up_mask |= 1 << i;
66                 }
67                 if (hweight32(cpu_up_mask) == hweight32(cores))
68                         break;
69                 udelay(10);
70         }
71         if (timeout <= 0) {
72                 printf("Not all cores (0x%x) are up (0x%x)\n",
73                        cores, cpu_up_mask);
74                 return 1;
75         }
76         printf("All (%d) cores are up.\n", hweight32(cores));
77
78         return 0;
79 }
80
81 int is_core_valid(unsigned int core)
82 {
83         return !!((1 << core) & cpu_mask());
84 }
85
86 int cpu_reset(int nr)
87 {
88         puts("Feature is not implemented.\n");
89
90         return 0;
91 }
92
93 int cpu_disable(int nr)
94 {
95         puts("Feature is not implemented.\n");
96
97         return 0;
98 }
99
100 int core_to_pos(int nr)
101 {
102         u32 cores = cpu_mask();
103         int i, count = 0;
104
105         if (nr == 0) {
106                 return 0;
107         } else if (nr >= hweight32(cores)) {
108                 puts("Not a valid core number.\n");
109                 return -1;
110         }
111
112         for (i = 1; i < 32; i++) {
113                 if (is_core_valid(i)) {
114                         count++;
115                         if (count == nr)
116                                 break;
117                 }
118         }
119
120         return count;
121 }
122
123 int cpu_status(int nr)
124 {
125         u64 *table;
126         int pos;
127
128         if (nr == 0) {
129                 table = (u64 *)get_spin_tbl_addr();
130                 printf("table base @ 0x%p\n", table);
131         } else {
132                 pos = core_to_pos(nr);
133                 if (pos < 0)
134                         return -1;
135                 table = (u64 *)get_spin_tbl_addr() + pos *
136                         WORDS_PER_SPIN_TABLE_ENTRY;
137                 printf("table @ 0x%p\n", table);
138                 printf("   addr - 0x%016llx\n",
139                        table[SPIN_TABLE_ELEM_ENTRY_ADDR_IDX]);
140                 printf("   status   - 0x%016llx\n",
141                        table[SPIN_TABLE_ELEM_STATUS_IDX]);
142                 printf("   lpid  - 0x%016llx\n",
143                        table[SPIN_TABLE_ELEM_LPID_IDX]);
144         }
145
146         return 0;
147 }
148
149 int cpu_release(int nr, int argc, char * const argv[])
150 {
151         u64 boot_addr;
152         u64 *table = (u64 *)get_spin_tbl_addr();
153         int pos;
154
155         pos = core_to_pos(nr);
156         if (pos <= 0)
157                 return -1;
158
159         table += pos * WORDS_PER_SPIN_TABLE_ENTRY;
160         boot_addr = simple_strtoull(argv[0], NULL, 16);
161         table[SPIN_TABLE_ELEM_ENTRY_ADDR_IDX] = boot_addr;
162         flush_dcache_range((unsigned long)table,
163                            (unsigned long)table + SPIN_TABLE_ELEM_SIZE);
164         asm volatile("dsb st");
165         smp_kick_all_cpus();    /* only those with entry addr set will run */
166
167         return 0;
168 }