1 INTERFACE [arm && exynos]:
5 #include "mem_layout.h"
6 #include "mmio_register_block.h"
8 EXTENSION class Platform_control
12 class Pmu : public Mmio_register_block
15 explicit Pmu(Address virt) : Mmio_register_block(virt) {}
23 ARM_COMMON_OPTION = 0x2408,
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; }
29 Mword read(unsigned reg) const
30 { return Mmio_register_block::read<Mword>(reg); }
32 void write(Mword val, unsigned reg) const
33 { Mmio_register_block::write(val, reg); }
35 Mword core_read(Cpu_phys_id cpu, unsigned reg) const
36 { return Mmio_register_block::read<Mword>(core_pwr_reg(cpu, reg)); }
38 void core_write(Mword val, Cpu_phys_id cpu, unsigned reg) const
39 { Mmio_register_block::write(val, core_pwr_reg(cpu, reg)); }
44 Aftr, Lpa, Dstop, Sleep,
51 Pmu_core_local_power_enable = 3,
54 static Static_object<Pmu> pmu;
57 //--------------------------------------------------------------------------
58 INTERFACE [arm && exynos && (exynos_extgic || exynos5) && cpu_suspend]:
60 #include "per_cpu_data.h"
62 EXTENSION class Platform_control
65 static Per_cpu<bool> _suspend_allowed;
68 //--------------------------------------------------------------------------
69 IMPLEMENTATION [arm && exynos && !mp]:
73 Platform_control::power_up_core(Cpu_phys_id)
75 return -L4_err::ENodev;
78 //--------------------------------------------------------------------------
79 IMPLEMENTATION [arm && exynos]:
81 #include "per_cpu_data.h"
83 Static_object<Platform_control::Pmu> Platform_control::pmu;
85 //--------------------------------------------------------------------------
86 IMPLEMENTATION [arm && exynos && mp && cpu_suspend]:
88 #include "poll_timeout_kclock.h"
92 Platform_control::power_up_core(Cpu_phys_id cpu)
94 // CPU already powered up?
95 if ((pmu->core_read(cpu, Pmu::Status) & Pmu_core_local_power_enable) != 0)
98 pmu->core_write(Pmu_core_local_power_enable, cpu, Pmu::Config);
100 Lock_guard<Cpu_lock, Lock_guard_inverse_policy> cpu_lock_guard(&cpu_lock);
102 Poll_timeout_kclock pt(10000);
103 while (pt.test((pmu->core_read(cpu, Pmu::Status)
104 & Pmu_core_local_power_enable)
105 != Pmu_core_local_power_enable))
108 return pt.timed_out() ? -L4_err::ENodev : 0;
111 //--------------------------------------------------------------------------
112 IMPLEMENTATION [arm && exynos && mp && !cpu_suspend]:
116 Platform_control::power_up_core(Cpu_phys_id)
122 //--------------------------------------------------------------------------
123 IMPLEMENTATION [arm && exynos]:
126 #include "mem_unit.h"
127 #include "outer_cache.h"
131 Platform_control::write_phys_mem_coherent(Mword addr_p, Mword value)
133 Mword addr_v = Kmem::mmio_remap(addr_p);
134 Io::write<Mword>(value, addr_v);
135 Mem_unit::flush_dcache((void *)addr_v, (void *)(addr_v + sizeof(value)));
136 Outer_cache::flush(addr_p);
139 //--------------------------------------------------------------------------
140 IMPLEMENTATION [arm && exynos && arm_em_ns && arm_smif_mc]:
144 Platform_control::cpuboot(Mword startup_vector, Cpu_phys_id cpu)
146 unsigned long b = Mem_layout::Sysram_phys_base;
147 if (Platform::is_5410())
150 b += Platform::is_4210() ? 0x1f01c : 0x2f01c;
152 if (Platform::is_4412())
153 b += cxx::int_value<Cpu_phys_id>(cpu) * 4;
155 write_phys_mem_coherent(b, startup_vector);
156 Exynos_smc::call(Exynos_smc::Cpu1boot, cxx::int_value<Cpu_phys_id>(cpu));
159 // ------------------------------------------------------------------------
160 IMPLEMENTATION [exynos && (!arm_em_ns || arm_smif_none)]:
162 #include "mem_layout.h"
163 #include "platform.h"
167 Platform_control::cpuboot(Mword startup_vector, Cpu_phys_id cpu)
169 unsigned long b = Mem_layout::Sysram_phys_base;
171 if (Platform::is_4210() && Platform::subrev() == 0x11)
172 b = Mem_layout::Pmu_phys_base + 0x814;
173 else if (Platform::is_4210() && Platform::subrev() == 0)
176 if (Platform::is_4412())
177 b += cxx::int_value<Cpu_phys_id>(cpu) * 4;
179 write_phys_mem_coherent(b, startup_vector);
182 //--------------------------------------------------------------------------
183 IMPLEMENTATION [arm && exynos && mp]:
187 #include "mem_unit.h"
188 #include "outer_cache.h"
189 #include "platform.h"
194 Platform_control::boot_ap_cpus(Address phys_reset_vector)
196 assert(current_cpu() == Cpu_number::boot_cpu());
198 if (Platform::is_4412() || Platform::is_5410())
200 for (Cpu_phys_id i = Cpu_phys_id(1);
201 i < Cpu_phys_id(4) && i < Cpu_phys_id(Config::Max_num_cpus);
205 if (Platform::is_4412())
206 cpuboot(phys_reset_vector, i);
207 Ipi::send(Ipi::Global_request, Cpu_number::boot_cpu(), i);
213 Cpu_phys_id const second = Cpu_phys_id(1);
214 power_up_core(second);
215 cpuboot(phys_reset_vector, second);
216 Ipi::send(Ipi::Global_request, Cpu_number::boot_cpu(), second);
220 //--------------------------------------------------------------------------
221 IMPLEMENTATION [arm && ((exynos && !exynos_extgic && !exynos5 && cpu_suspend) || !cpu_suspend)]:
223 #include "l4_types.h"
227 Platform_control::cpu_suspend_allowed(Cpu_number)
232 Platform_control::do_core_n_off(Cpu_number)
234 return -L4_err::EBusy;
237 //--------------------------------------------------------------------------
238 IMPLEMENTATION [arm && exynos && mp && (exynos_extgic || exynos5) && cpu_suspend]:
245 #include "kmem_space.h"
247 #include "processor.h"
252 Platform_control::cpu_shutdown_available()
255 PRIVATE static inline
257 Platform_control::resume_cpu(Cpu_number cpu)
259 Cpu_phys_id const pcpu = Cpu::cpus.cpu(cpu).phys_id();
261 if ((r = power_up_core(pcpu)))
264 set_suspend_state(cpu, false);
265 extern char _tramp_mp_entry[];
266 cpuboot(Kmem_space::kdir()->virt_to_phys((Address)_tramp_mp_entry), pcpu);
267 Ipi::send(Ipi::Global_request, current_cpu(), pcpu);
272 PRIVATE static inline
274 Platform_control::suspend_cpu(Cpu_number cpu)
276 set_suspend_state(cpu, true);
277 Ipi::send(Ipi::Global_request, current_cpu(), cpu);
284 Platform_control::cpu_allow_shutdown(Cpu_number cpu, bool allow)
286 if (allow && !Cpu::online(cpu))
288 else if (!allow && Cpu::online(cpu))
291 return -L4_err::ENodev;
297 //--------------------------------------------------------------------------
298 IMPLEMENTATION [arm && exynos && cpu_suspend && arm_em_ns]:
300 PRIVATE static inline
302 Platform_control::do_sleep()
304 // FIXME: I miss: Exynos_smc::cpusleep();
305 asm volatile("dsb; wfi" : : : "memory", "cc");
308 //--------------------------------------------------------------------------
309 IMPLEMENTATION [arm && exynos && cpu_suspend && !arm_em_ns]:
311 PRIVATE static inline
313 Platform_control::do_sleep()
315 asm volatile("dsb; wfi" : : : "memory", "cc");
318 //--------------------------------------------------------------------------
319 IMPLEMENTATION [arm && exynos && (exynos_extgic || exynos5) && cpu_suspend]:
327 #include "processor.h"
329 DEFINE_PER_CPU Per_cpu<bool> Platform_control::_suspend_allowed;
333 Platform_control::init(Cpu_number cpu)
335 if (cpu == Cpu_number::boot_cpu())
337 assert (!pmu->get_mmio_base());
338 pmu.construct(Kmem::mmio_remap(Mem_layout::Pmu_phys_base));
340 for (Cpu_phys_id i = Cpu_phys_id(0);
343 pmu->core_write((pmu->core_read(i, Pmu::Option) & ~(1 << 0)) | (1 << 1), i, Pmu::Option);
345 pmu->write(2, Pmu::ARM_COMMON_OPTION);
351 Platform_control::set_suspend_state(Cpu_number cpu, bool state)
353 _suspend_allowed.cpu(cpu) = state;
358 Platform_control::cpu_suspend_allowed(Cpu_number cpu)
360 return _suspend_allowed.cpu(cpu);
365 Platform_control::do_print_cpu_info(Cpu_phys_id cpu)
367 printf("fiasco: core%d: %lx/%lx/%lx\n", cxx::int_value<Cpu_phys_id>(cpu),
368 pmu->core_read(cpu, Pmu::Config),
369 pmu->core_read(cpu, Pmu::Status),
370 pmu->core_read(cpu, Pmu::Option));
375 Platform_control::do_core_n_off(Cpu_number cpu)
377 if (cpu == Cpu_number::boot_cpu())
378 return -L4_err::EBusy;
380 Cpu_phys_id const phys_cpu = Cpu::cpus.cpu(cpu).phys_id();
382 do_print_cpu_info(phys_cpu);
384 assert(cpu_lock.test()); // required for wfi
386 pmu->core_write(0, phys_cpu, Pmu::Config);
388 Mem_unit::flush_cache();
389 Mem_unit::tlb_flush();
390 Mem_unit::kernel_tlb_flush();
393 Cpu::disable_dcache();
397 // we only reach here if the wfi was not done due to a pending event
399 Cpu::enable_dcache();
402 // todo: the timer irq needs a proper cpu setting here too
403 // (save + restore state)
406 do_print_cpu_info(phys_cpu);