Skip to content

Commit abca237

Browse files
committed
platform: Add xuantie_ipmc_test for IPMC test
This is an example implementation of power management using C907 IPMC, which mainly implements sbi_hsm_device, sbi_system_reset_device and sbi_system_suspend_device defined by opensbi. DTS example: ``` { model = "xuantie,dummy"; compatible = "xuantie,dummy"; ipmc: xuantie_ipmc@26900000 { compatible = "xuantie,ipmc"; reg = <0x00000000 0x26900000 0x00000000 0x00001000>; }; } ``` Signed-off-by: Chen Pei <[email protected]>
1 parent a9994da commit abca237

File tree

5 files changed

+291
-0
lines changed

5 files changed

+291
-0
lines changed

platform/generic/Kconfig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ config PLATFORM_THEAD
6565
select THEAD_C9XX_PMU
6666
default n
6767

68+
config PLATFORM_XUANTIE
69+
bool "XuanTie 9xx support"
70+
default n
71+
6872
source "$(OPENSBI_SRC_DIR)/platform/generic/andes/Kconfig"
6973
source "$(OPENSBI_SRC_DIR)/platform/generic/thead/Kconfig"
7074

platform/generic/configs/defconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ CONFIG_PLATFORM_SIFIVE_FU740=y
66
CONFIG_PLATFORM_SOPHGO_SG2042=y
77
CONFIG_PLATFORM_STARFIVE_JH7110=y
88
CONFIG_PLATFORM_THEAD=y
9+
CONFIG_PLATFORM_XUANTIE=y
910
CONFIG_FDT_GPIO=y
1011
CONFIG_FDT_GPIO_DESIGNWARE=y
1112
CONFIG_FDT_GPIO_SIFIVE=y
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#
2+
# SPDX-License-Identifier: BSD-2-Clause
3+
#
4+
5+
carray-platform_override_modules-$(CONFIG_PLATFORM_XUANTIE) += xuantie_ipmc_test
6+
platform-objs-$(CONFIG_PLATFORM_XUANTIE) += xuantie/xuantie_ipmc_test.o
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
/*
2+
* SPDX-License-Identifier: BSD-2-Clause
3+
*/
4+
5+
#include <platform_override.h>
6+
#include <thead/c9xx_encoding.h>
7+
#include <thead/c9xx_pmu.h>
8+
#include <sbi/riscv_asm.h>
9+
#include <sbi/riscv_io.h>
10+
#include <sbi/sbi_bitops.h>
11+
#include <sbi/sbi_ecall_interface.h>
12+
#include <sbi/sbi_error.h>
13+
#include <sbi/sbi_hsm.h>
14+
#include <sbi/sbi_system.h>
15+
#include <sbi/sbi_pmu.h>
16+
#include <sbi/sbi_scratch.h>
17+
#include <sbi/sbi_console.h>
18+
#include <sbi/sbi_platform.h>
19+
#include <sbi_utils/fdt/fdt_fixup.h>
20+
#include <sbi_utils/fdt/fdt_helper.h>
21+
#include <sbi_utils/irqchip/fdt_irqchip_plic.h>
22+
23+
#include "xuantie_ipmc_test.h"
24+
25+
static struct xuantie_ipmc_data ipmc = { 0 };
26+
static unsigned long zsb_addr = 0;
27+
28+
static inline void xuantie_riscv_cfg_init(void)
29+
{
30+
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
31+
if (!zsb_addr) {
32+
zsb_addr = scratch->next_addr - 0x00008000;
33+
}
34+
}
35+
36+
static inline int ipmc_set_command(struct xuantie_ipmc_data *ipmc, u32 hartid, u32 blkid, u32 val)
37+
{
38+
unsigned long ipmc_base, blk_sw_mode_ctl;
39+
if (ipmc) {
40+
ipmc_base = ipmc->ipmc_addr + 0x1000 * hartid;
41+
blk_sw_mode_ctl = 0x100 + 0x4 * blkid;
42+
writew_relaxed(val, (void *)(ipmc_base + blk_sw_mode_ctl));
43+
return 0;
44+
} else
45+
return SBI_EINVAL;
46+
}
47+
48+
static inline void xuantie_hart_poweroff(u32 hartid, bool wakeup)
49+
{
50+
if (wakeup) {
51+
/* Cpuidle power down, set trans bit to auto mode */
52+
ipmc_set_command(&ipmc, hartid, IPMC_BLK_CORE, IPMC_TRANS_MODE_DYNAMIC | IPMC_BLK_MODE_CONFIG_OFF);
53+
ipmc_set_command(&ipmc, hartid, IPMC_BLK_CORE_VFPU, IPMC_TRANS_MODE_DYNAMIC | IPMC_BLK_LOW_POWER_STATE_OFF);
54+
} else {
55+
/* Hotplug power down, set trans bit to manual mode */
56+
ipmc_set_command(&ipmc, hartid, IPMC_BLK_CORE, IPMC_TRANS_MODE_DYNAMIC | IPMC_BLK_MODE_CONFIG_OFF);
57+
ipmc_set_command(&ipmc, hartid, IPMC_BLK_CORE_VFPU, IPMC_TRANS_MODE_DYNAMIC | IPMC_BLK_LOW_POWER_STATE_OFF);
58+
}
59+
60+
/* Close the Prefetch */
61+
csr_clear(THEAD_C9XX_CSR_MHINT, 0x1 << 2);
62+
63+
/* Clean and invalidate core's dcache */
64+
asm volatile(XUANTIE_DCACHE_INVAL_CLEAN_ALL);
65+
66+
/* Close the Dcache */
67+
csr_clear(THEAD_C9XX_CSR_MHCR, 0x1 << 1);
68+
asm volatile(XUANTIE_SYNC_IS);
69+
70+
/* Close the snoop */
71+
csr_clear(THEAD_C9XX_CSR_MSMPR, 0x1);
72+
73+
csr_set(CSR_MIE, MIP_MTIP | MIP_STIP | MIP_SEIP | MIP_MEIP);
74+
75+
wfi();
76+
77+
__asm__ __volatile__(
78+
"jalr x0, %0\n\t"
79+
:
80+
: "r"(zsb_addr)
81+
: "memory");
82+
}
83+
84+
static int xuantie_hart_suspend(u32 suspend_type)
85+
{
86+
u32 hartid = current_hartid();
87+
88+
/* Use the generic code for retentive suspend. */
89+
if (!(suspend_type & SBI_HSM_SUSP_NON_RET_BIT))
90+
return SBI_ENOTSUPP;
91+
92+
xuantie_hart_poweroff(hartid, true);
93+
94+
return 0;
95+
}
96+
97+
static void xuantie_hart_resume(void)
98+
{
99+
}
100+
101+
int xuantie_hart_start(u32 hartid, ulong saddr)
102+
{
103+
return 0;
104+
}
105+
106+
int xuantie_hart_stop(void)
107+
{
108+
u32 hartid = current_hartid();
109+
110+
xuantie_hart_poweroff(hartid, false);
111+
112+
return 0;
113+
}
114+
115+
static const struct sbi_hsm_device xuantie_hsm = {
116+
.name = "xuantie-hsm",
117+
.hart_suspend = xuantie_hart_suspend,
118+
.hart_resume = xuantie_hart_resume,
119+
.hart_start = xuantie_hart_start,
120+
.hart_stop = xuantie_hart_stop,
121+
};
122+
123+
static void xuantie_enable_ddr_auto_selfrefresh()
124+
{
125+
}
126+
127+
static void xuantie_system_clk_suspend()
128+
{
129+
}
130+
131+
static void xuantie_system_power_suspend()
132+
{
133+
}
134+
135+
static int xuantie_system_suspend_check(u32 sleep_type)
136+
{
137+
return sleep_type == SBI_SUSP_SLEEP_TYPE_SUSPEND ? 0 : SBI_EINVAL;
138+
}
139+
140+
static int xuantie_system_suspend(u32 sleep_type, unsigned long mmode_resume_addr)
141+
{
142+
u32 hartid = current_hartid();
143+
144+
if (sleep_type != SBI_SUSP_SLEEP_TYPE_SUSPEND)
145+
return SBI_EINVAL;
146+
147+
/* enable ddr auto selfrefresh */
148+
xuantie_enable_ddr_auto_selfrefresh();
149+
150+
/* enable wakeup irqs, disable other irqs, Linux framwork already done */
151+
/* There just make sure the mask of irq is disabled */
152+
/* xuantie_set_wakeup_source(); */
153+
154+
/* xuantie_system_clk_suspend , include clock system and plls*/
155+
xuantie_system_clk_suspend();
156+
157+
/* xuantie_system_power_suspend , close the module powers which have no wakeup sources */
158+
xuantie_system_power_suspend();
159+
160+
/* enable cpuidle, cpu poweroff after wfi */
161+
xuantie_hart_poweroff(hartid, true);
162+
163+
return 0;
164+
}
165+
166+
static struct sbi_system_suspend_device xuantie_system_suspend_dev = {
167+
.name = "xuantie-system-suspend",
168+
.system_suspend_check = xuantie_system_suspend_check,
169+
.system_suspend = xuantie_system_suspend,
170+
};
171+
172+
static int xuantie_system_reset_check(u32 type, u32 reason)
173+
{
174+
switch (type) {
175+
case SBI_SRST_RESET_TYPE_SHUTDOWN:
176+
return 1;
177+
case SBI_SRST_RESET_TYPE_COLD_REBOOT:
178+
case SBI_SRST_RESET_TYPE_WARM_REBOOT:
179+
return 255;
180+
}
181+
182+
return 0;
183+
}
184+
185+
static void xuantie_system_reset(u32 type, u32 reason)
186+
{
187+
}
188+
189+
static struct sbi_system_reset_device xuantie_reset = {
190+
.name = "xuantie-reset",
191+
.system_reset_check = xuantie_system_reset_check,
192+
.system_reset = xuantie_system_reset
193+
};
194+
195+
static int xuantie_ipmc_test_device_init(void)
196+
{
197+
void *fdt = fdt_get_address();
198+
int rc = fdt_parse_compat_addr(fdt, (uint64_t *)&ipmc.ipmc_addr, "xuantie,ipmc");
199+
if (rc) {
200+
return rc;
201+
}
202+
203+
sbi_system_reset_add_device(&xuantie_reset);
204+
sbi_hsm_set_device(&xuantie_hsm);
205+
sbi_system_suspend_set_device(&xuantie_system_suspend_dev);
206+
207+
return 0;
208+
}
209+
210+
static int xuantie_final_init(bool cold_boot, const struct fdt_match *match)
211+
{
212+
if (cold_boot) {
213+
xuantie_riscv_cfg_init();
214+
xuantie_ipmc_test_device_init();
215+
}
216+
217+
return 0;
218+
}
219+
220+
static const struct fdt_match xuantie_ipmc_test_match[] = {
221+
{ .compatible = "xuantie,dummy" },
222+
{ },
223+
};
224+
225+
const struct platform_override xuantie_ipmc_test = {
226+
.match_table = xuantie_ipmc_test_match,
227+
.final_init = xuantie_final_init,
228+
};
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* SPDX-License-Identifier: BSD-3-Clause
3+
*/
4+
5+
#ifndef __XUANTIE_IPMC_TEST_H__
6+
#define __XUANTIE_IPMC_TEST_H__
7+
8+
#include <sbi/sbi_types.h>
9+
10+
/* clang-format off */
11+
12+
#define XUANTIE_DCACHE_INVAL_CLEAN_ALL ".long 0x0030000b"
13+
#define XUANTIE_SYNC_IS ".long 0x01b0000b"
14+
15+
/*
16+
core IPMC: blk1 = VFPU; blk2 = MPU
17+
cluster IPMC: blk1 = l2cache
18+
*/
19+
#define IPMC_BLK_CORE 0
20+
#define IPMC_BLK_CORE_VFPU 1
21+
#define IPMC_BLK_CORE_MPU 2
22+
#define IPMC_BLK_CLUSTER 0
23+
#define IPMC_BLK_CLUSTER_L2 1
24+
25+
#define IPMC_TRANS_MODE_SHIFT 4
26+
#define IPMC_TRANS_MODE_DIRECT (_UL(1) << IPMC_TRANS_MODE_SHIFT)
27+
#define IPMC_TRANS_MODE_DYNAMIC (_UL(0) << IPMC_TRANS_MODE_SHIFT)
28+
/*pmc_blk_mode_config (basic type)*/
29+
#define IPMC_BLK_MODE_CONFIG_0 0 // OFF pstate enable
30+
#define IPMC_BLK_MODE_CONFIG_1 1
31+
#define IPMC_BLK_MODE_CONFIG_2 2
32+
#define IPMC_BLK_MODE_CONFIG_3 3
33+
#define IPMC_BLK_MODE_CONFIG_4 4
34+
#define IPMC_BLK_MODE_CONFIG_5 5
35+
#define IPMC_BLK_MODE_CONFIG_6 6
36+
#define IPMC_BLK_MODE_CONFIG_7 7
37+
#define IPMC_BLK_MODE_CONFIG_8 8 // ON pstate enable
38+
#define IPMC_BLK_MODE_CONFIG_9 9
39+
#define IPMC_BLK_MODE_CONFIG_ON IPMC_BLK_MODE_CONFIG_8
40+
#define IPMC_BLK_MODE_CONFIG_OFF IPMC_BLK_MODE_CONFIG_0
41+
/*pmc_blk_mode_config (pe type)*/
42+
#define IPMC_BLK_LOW_POWER_STATE_OFF 0
43+
#define IPMC_BLK_LOW_POWER_STATE_RET 1
44+
45+
46+
/* clang-format on */
47+
48+
struct xuantie_ipmc_data {
49+
unsigned long ipmc_addr;
50+
};
51+
52+
#endif /* __XUANTIE_IPMC_TEST_H__ */

0 commit comments

Comments
 (0)