2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2019 Western Digital Corporation or its affiliates.
7 * Anup Patel <anup.patel@wdc.com>
8 * Nick Kossifidis <mick@ics.forth.gr>
11 #include <sbi/riscv_asm.h>
12 #include <sbi/sbi_bitops.h>
13 #include <sbi/sbi_domain.h>
14 #include <sbi/sbi_hart.h>
15 #include <sbi/sbi_hsm.h>
16 #include <sbi/sbi_platform.h>
17 #include <sbi/sbi_system.h>
18 #include <sbi/sbi_ipi.h>
19 #include <sbi/sbi_init.h>
21 static SBI_LIST_HEAD(reset_devices_list);
23 const struct sbi_system_reset_device *sbi_system_reset_get_device(
24 u32 reset_type, u32 reset_reason)
26 struct sbi_system_reset_device *reset_dev = NULL;
27 struct sbi_dlist *pos;
28 /** lowest priority - any non zero is our candidate */
31 /* Check each reset device registered for supported reset type */
32 sbi_list_for_each(pos, &(reset_devices_list)) {
33 struct sbi_system_reset_device *dev =
34 to_system_reset_device(pos);
35 if (dev->system_reset_check) {
36 int status = dev->system_reset_check(reset_type,
38 /** reset_type not supported */
42 if (status > priority) {
52 void sbi_system_reset_add_device(struct sbi_system_reset_device *dev)
54 if (!dev || !dev->system_reset_check)
57 sbi_list_add(&(dev->node), &(reset_devices_list));
60 bool sbi_system_reset_supported(u32 reset_type, u32 reset_reason)
62 return !!sbi_system_reset_get_device(reset_type, reset_reason);
65 void __noreturn sbi_system_reset(u32 reset_type, u32 reset_reason)
67 ulong hbase = 0, hmask;
68 u32 cur_hartid = current_hartid();
69 struct sbi_domain *dom = sbi_domain_thishart_ptr();
70 struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
72 /* Send HALT IPI to every hart other than the current hart */
73 while (!sbi_hsm_hart_interruptible_mask(dom, hbase, &hmask)) {
74 if (hbase <= cur_hartid)
75 hmask &= ~(1UL << (cur_hartid - hbase));
77 sbi_ipi_send_halt(hmask, hbase);
78 hbase += BITS_PER_LONG;
81 /* Stop current HART */
82 sbi_hsm_hart_stop(scratch, false);
84 /* Platform specific reset if domain allowed system reset */
85 if (dom->system_reset_allowed) {
86 const struct sbi_system_reset_device *dev =
87 sbi_system_reset_get_device(reset_type, reset_reason);
89 dev->system_reset(reset_type, reset_reason);
92 /* If platform specific reset did not work then do sbi_exit() */
96 static const struct sbi_system_suspend_device *suspend_dev = NULL;
98 const struct sbi_system_suspend_device *sbi_system_suspend_get_device(void)
103 void sbi_system_suspend_set_device(struct sbi_system_suspend_device *dev)
105 if (!dev || suspend_dev)
111 bool sbi_system_suspend_supported(u32 sleep_type)
113 return suspend_dev && suspend_dev->system_suspend_check &&
114 suspend_dev->system_suspend_check(sleep_type);
117 int sbi_system_suspend(u32 sleep_type, ulong resume_addr, ulong opaque)