]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - sys/arm/freescale/imx/imx6_mp.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / sys / arm / freescale / imx / imx6_mp.c
1 /*-
2  * Copyright (c) 2014 Juergen Weiss <weiss@uni-mainz.de>
3  * Copyright (c) 2014 Ian Lepore <ian@freebsd.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/bus.h>
32 #include <sys/kernel.h>
33 #include <sys/lock.h>
34 #include <sys/mutex.h>
35 #include <sys/smp.h>
36
37 #include <machine/smp.h>
38 #include <machine/fdt.h>
39 #include <machine/intr.h>
40
41 #define SCU_PHYSBASE                    0x00a00000
42 #define SCU_SIZE                        0x00001000
43
44 #define SCU_CONTROL_REG                 0x00
45 #define   SCU_CONTROL_ENABLE              (1 << 0)
46 #define SCU_CONFIG_REG                  0x04
47 #define   SCU_CONFIG_REG_NCPU_MASK        0x03
48 #define SCU_CPUPOWER_REG                0x08
49 #define SCU_INV_TAGS_REG                0x0c
50 #define SCU_DIAG_CONTROL                0x30
51 #define   SCU_DIAG_DISABLE_MIGBIT         (1 << 0)
52 #define SCU_FILTER_START_REG            0x40
53 #define SCU_FILTER_END_REG              0x44
54 #define SCU_SECURE_ACCESS_REG           0x50
55 #define SCU_NONSECURE_ACCESS_REG        0x54
56
57 #define SRC_PHYSBASE                    0x020d8000
58 #define SRC_SIZE                        0x4000
59 #define SRC_CONTROL_REG                 0x00
60 #define SRC_CONTROL_C1ENA_SHIFT           22    /* Bit for Core 1 enable */
61 #define SRC_CONTROL_C1RST_SHIFT           14    /* Bit for Core 1 reset */
62 #define SRC_GPR0_C1FUNC                 0x20    /* Register for Core 1 entry func */
63 #define SRC_GPR1_C1ARG                  0x24    /* Register for Core 1 entry arg */
64
65 void
66 platform_mp_init_secondary(void)
67 {
68
69         gic_init_secondary();
70 }
71
72 void
73 platform_mp_setmaxid(void)
74 {
75         bus_space_handle_t scu;
76         int hwcpu, ncpu;
77         uint32_t val;
78
79         /* If we've already set the global vars don't bother to do it again. */
80         if (mp_ncpus != 0)
81                 return;
82
83         if (bus_space_map(fdtbus_bs_tag, SCU_PHYSBASE, SCU_SIZE, 0, &scu) != 0)
84                 panic("Couldn't map the SCU\n");
85         val = bus_space_read_4(fdtbus_bs_tag, scu, SCU_CONFIG_REG);
86         hwcpu = (val & SCU_CONFIG_REG_NCPU_MASK) + 1;
87         bus_space_unmap(fdtbus_bs_tag, scu, SCU_SIZE);
88
89         ncpu = hwcpu;
90         TUNABLE_INT_FETCH("hw.ncpu", &ncpu);
91         if (ncpu < 1 || ncpu > hwcpu)
92                 ncpu = hwcpu;
93
94         mp_ncpus = ncpu;
95         mp_maxid = ncpu - 1;
96 }
97
98 int
99 platform_mp_probe(void)
100 {
101
102         /* I think platform_mp_setmaxid must get called first, but be safe. */
103         if (mp_ncpus == 0)
104                 platform_mp_setmaxid();
105
106         return (mp_ncpus > 1);
107 }
108
109 void    
110 platform_mp_start_ap(void)
111 {
112         bus_space_handle_t scu;
113         bus_space_handle_t src;
114
115         uint32_t val;
116         int i;
117
118         if (bus_space_map(fdtbus_bs_tag, SCU_PHYSBASE, SCU_SIZE, 0, &scu) != 0)
119                 panic("Couldn't map the SCU\n");
120         if (bus_space_map(fdtbus_bs_tag, SRC_PHYSBASE, SRC_SIZE, 0, &src) != 0)
121                 panic("Couldn't map the system reset controller (SRC)\n");
122
123         /*
124          * Invalidate SCU cache tags.  The 0x0000ffff constant invalidates all
125          * ways on all cores 0-3.  Per the ARM docs, it's harmless to write to
126          * the bits for cores that are not present.
127          */
128         bus_space_write_4(fdtbus_bs_tag, scu, SCU_INV_TAGS_REG, 0x0000ffff);
129
130         /*
131          * Erratum ARM/MP: 764369 (problems with cache maintenance).
132          * Setting the "disable-migratory bit" in the undocumented SCU
133          * Diagnostic Control Register helps work around the problem.
134          */
135         val = bus_space_read_4(fdtbus_bs_tag, scu, SCU_DIAG_CONTROL);
136         bus_space_write_4(fdtbus_bs_tag, scu, SCU_DIAG_CONTROL, 
137             val | SCU_DIAG_DISABLE_MIGBIT);
138
139         /*
140          * Enable the SCU, then clean the cache on this core.  After these two
141          * operations the cache tag ram in the SCU is coherent with the contents
142          * of the cache on this core.  The other cores aren't running yet so
143          * their caches can't contain valid data yet, but we've initialized
144          * their SCU tag ram above, so they will be coherent from startup.
145          */
146         val = bus_space_read_4(fdtbus_bs_tag, scu, SCU_CONTROL_REG);
147         bus_space_write_4(fdtbus_bs_tag, scu, SCU_CONTROL_REG, 
148             val | SCU_CONTROL_ENABLE);
149         cpu_idcache_wbinv_all();
150
151         /*
152          * For each AP core, set the entry point address and argument registers,
153          * and set the core-enable and core-reset bits in the control register.
154          */
155         val = bus_space_read_4(fdtbus_bs_tag, src, SRC_CONTROL_REG);
156         for (i=1; i < mp_ncpus; i++) {
157                 bus_space_write_4(fdtbus_bs_tag, src, SRC_GPR0_C1FUNC + 8*i,
158                     pmap_kextract((vm_offset_t)mpentry));
159                 bus_space_write_4(fdtbus_bs_tag, src, SRC_GPR1_C1ARG  + 8*i, 0);
160
161                 val |= ((1 << (SRC_CONTROL_C1ENA_SHIFT - 1 + i )) |
162                     ( 1 << (SRC_CONTROL_C1RST_SHIFT - 1 + i)));
163
164         }
165         bus_space_write_4(fdtbus_bs_tag, src, SRC_CONTROL_REG, val);
166
167         armv7_sev();
168
169         bus_space_unmap(fdtbus_bs_tag, scu, SCU_SIZE);
170         bus_space_unmap(fdtbus_bs_tag, src, SRC_SIZE);
171 }
172
173 void
174 platform_ipi_send(cpuset_t cpus, u_int ipi)
175 {
176
177         pic_ipi_send(cpus, ipi);
178 }