]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/arm/bsp/exynos/platform_control-arm-exynos.cpp
update
[l4.git] / kernel / fiasco / src / kern / arm / bsp / exynos / platform_control-arm-exynos.cpp
1 INTERFACE [arm && exynos]:
2
3 #include "types.h"
4 #include "io.h"
5 #include "mem_layout.h"
6 #include "mmio_register_block.h"
7
8 EXTENSION class Platform_control
9 {
10 public:
11
12   class Pmu : public Mmio_register_block
13   {
14   public:
15     explicit Pmu(Address virt) : Mmio_register_block(virt) {}
16     enum Reg
17     {
18       Config      = 0,
19       Status      = 4,
20       Option      = 8,
21       Core_offset = 0x80,
22
23       ARM_COMMON_OPTION      = 0x2408,
24    };
25
26     static Mword core_pwr_reg(Cpu_phys_id cpu, unsigned func)
27     { return 0x2000 + Core_offset * cxx::int_value<Cpu_phys_id>(cpu) + func; }
28
29     Mword read(unsigned reg) const
30     { return Mmio_register_block::read<Mword>(reg); }
31
32     void write(Mword val, unsigned reg) const
33     { Mmio_register_block::write(val, reg); }
34
35     Mword core_read(Cpu_phys_id cpu, unsigned reg) const
36     { return Mmio_register_block::read<Mword>(core_pwr_reg(cpu, reg)); }
37
38     void core_write(Mword val, Cpu_phys_id cpu, unsigned reg) const
39     { Mmio_register_block::write(val, core_pwr_reg(cpu, reg)); }
40   };
41
42   enum Power_down_mode
43   {
44     Aftr, Lpa, Dstop, Sleep,
45
46     Pwr_down_mode = Aftr,
47   };
48
49   enum Pmu_regs
50   {
51     Pmu_core_local_power_enable = 3,
52   };
53
54   static Static_object<Pmu> pmu;
55 };
56
57
58 //--------------------------------------------------------------------------
59 IMPLEMENTATION [arm && exynos && !mp]:
60
61 PRIVATE static
62 int
63 Platform_control::power_up_core(Cpu_phys_id)
64 {
65   return -L4_err::ENodev;
66 }
67
68 //--------------------------------------------------------------------------
69 IMPLEMENTATION [arm && exynos]:
70
71 Static_object<Platform_control::Pmu> Platform_control::pmu;
72
73 IMPLEMENT
74 void
75 Platform_control::init(Cpu_number cpu)
76 {
77   if (cpu == Cpu_number::boot_cpu())
78     {
79       assert (!pmu->get_mmio_base());
80       pmu.construct(Kmem::mmio_remap(Mem_layout::Pmu_phys_base));
81
82       for (Cpu_phys_id i = Cpu_phys_id(0);
83            i < Cpu_phys_id(2);
84            ++i)
85         pmu->core_write((pmu->core_read(i, Pmu::Option) & ~(1 << 0)) | (1 << 1), i, Pmu::Option);
86
87       pmu->write(2, Pmu::ARM_COMMON_OPTION);
88     }
89 }
90
91 //--------------------------------------------------------------------------
92 IMPLEMENTATION [arm && exynos && mp]:
93
94 #include "ipi.h"
95 #include "outer_cache.h"
96 #include "platform.h"
97 #include "poll_timeout_kclock.h"
98 #include "smc.h"
99
100 PRIVATE static
101 int
102 Platform_control::power_up_core(Cpu_phys_id cpu)
103 {
104   // CPU already powered up?
105   if ((pmu->core_read(cpu, Pmu::Status) & Pmu_core_local_power_enable) != 0)
106     return 0;
107
108   pmu->core_write(Pmu_core_local_power_enable, cpu, Pmu::Config);
109
110   Lock_guard<Cpu_lock, Lock_guard_inverse_policy> cpu_lock_guard(&cpu_lock);
111
112   Poll_timeout_kclock pt(10000);
113   while (pt.test((pmu->core_read(cpu, Pmu::Status)
114                   & Pmu_core_local_power_enable)
115                  != Pmu_core_local_power_enable))
116       ;
117
118   return pt.timed_out() ? -L4_err::ENodev : 0;
119 }
120
121 PRIVATE static
122 void
123 Platform_control::set_one_vector(Mword addr_p, Mword vector)
124 {
125   Mword addr_v = Kmem::mmio_remap(addr_p);
126   Io::write<Mword>(vector, addr_v);
127   Mem_unit::flush_dcache((void *)addr_v, (void *)(addr_v + sizeof(void *)));
128   Outer_cache::flush(addr_p);
129 }
130
131 PUBLIC static
132 void
133 Platform_control::setup_cpu_start_vector(Cpu_phys_id cpu, Mword phys_reset_vector)
134 {
135   if ((Platform::is_4210() && Platform::subrev() == 0)
136       || Platform::is_4412())
137     {
138       printf("AP bootup sysram\n");
139
140       unsigned o = 0;
141       if (Platform::is_4412())
142         o = (Platform::running_ns() ? 0x2f01c : 0)
143             + cxx::int_value<Cpu_phys_id>(cpu) * 4;
144
145       set_one_vector(Mem_layout::Sysram_phys_base + o,
146                      phys_reset_vector);
147     }
148   else if (Platform::is_5250())
149     {
150       unsigned o = Platform::running_ns() ? 0x2f01c : 0;
151       set_one_vector(Mem_layout::Sysram_phys_base + o,
152                      phys_reset_vector);
153     }
154   else
155     {
156       printf("AP bootup inform\n");
157       set_one_vector(Mem_layout::Pmu_phys_base + 0x814,
158                      phys_reset_vector);
159     }
160 }
161
162
163 PUBLIC static
164 void
165 Platform_control::boot_ap_cpus(Address phys_reset_vector)
166 {
167   assert(current_cpu() == Cpu_number::boot_cpu());
168
169   if (Platform::is_4412())
170     {
171       for (Cpu_phys_id i = Cpu_phys_id(1);
172            i < Cpu_phys_id(4) && i < Cpu_phys_id(Config::Max_num_cpus);
173            ++i)
174         {
175           setup_cpu_start_vector(i, phys_reset_vector);
176           power_up_core(i);
177           if (Platform::running_ns())
178             Exynos_smc::cpuboot(phys_reset_vector,
179                                 cxx::int_value<Cpu_phys_id>(i));
180           Ipi::send(Ipi::Global_request, Cpu_number::boot_cpu(), i);
181         }
182
183       return;
184     }
185
186   Mem_unit::flush_dcache();
187
188   Cpu_phys_id const second = Cpu_phys_id(1);
189   setup_cpu_start_vector(second, phys_reset_vector);
190   power_up_core(second);
191
192   if (Platform::is_5250() && Platform::running_ns())
193     Exynos_smc::cpuboot(phys_reset_vector, 1);
194
195   Ipi::send(Ipi::Global_request, Cpu_number::boot_cpu(), second);
196 }