Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions platform/generic/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ config PLATFORM_THEAD
select THEAD_C9XX_PMU
default n

config PLATFORM_XUANTIE
bool "XuanTie 9xx support"
default n

source "$(OPENSBI_SRC_DIR)/platform/generic/andes/Kconfig"
source "$(OPENSBI_SRC_DIR)/platform/generic/thead/Kconfig"

Expand Down
1 change: 1 addition & 0 deletions platform/generic/configs/defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ CONFIG_PLATFORM_SIFIVE_FU740=y
CONFIG_PLATFORM_SOPHGO_SG2042=y
CONFIG_PLATFORM_STARFIVE_JH7110=y
CONFIG_PLATFORM_THEAD=y
CONFIG_PLATFORM_XUANTIE=y
CONFIG_FDT_GPIO=y
CONFIG_FDT_GPIO_DESIGNWARE=y
CONFIG_FDT_GPIO_SIFIVE=y
Expand Down
6 changes: 6 additions & 0 deletions platform/generic/xuantie/objects.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#
# SPDX-License-Identifier: BSD-2-Clause
#

carray-platform_override_modules-$(CONFIG_PLATFORM_XUANTIE) += xuantie_pmc
platform-objs-$(CONFIG_PLATFORM_XUANTIE) += xuantie/xuantie_pmc.o
215 changes: 215 additions & 0 deletions platform/generic/xuantie/xuantie_pmc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*/

#include <libfdt.h>
#include <platform_override.h>
#include <thead/c9xx_encoding.h>
#include <thead/c9xx_pmu.h>
#include <sbi/riscv_asm.h>
#include <sbi/riscv_io.h>
#include <sbi/sbi_bitops.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hsm.h>
#include <sbi/sbi_system.h>
#include <sbi/sbi_pmu.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_platform.h>
#include <sbi_utils/fdt/fdt_fixup.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/irqchip/fdt_irqchip_plic.h>

#include "xuantie_pmc.h"

static struct xuantie_pmc_data pmc = { 0 };
static unsigned long zsb_addr = 0;

static inline void xuantie_riscv_cfg_init(void)
{
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();

if (!zsb_addr) {
zsb_addr = scratch->next_addr - 0x00008000;
}
}

static inline int pmc_set_command(struct xuantie_pmc_data *pmc, u32 hartid, u32 blkid, u32 val)
{
u64 pmc_base, blk_sw_mode_ctl;

if (pmc) {
pmc_base = pmc->pmc_addr + 0x1000 * hartid;
blk_sw_mode_ctl = 0x100 + 0x4 * blkid;
writel_relaxed(val, (void *)(uintptr_t)(pmc_base + blk_sw_mode_ctl));
return 0;
} else
return SBI_EINVAL;
}

static inline void xuantie_hart_poweroff(u32 hartid, bool is_dynamic)
{
if (is_dynamic) {
/* cpu_idle power down, set trans bit to dynamic mode */
pmc_set_command(&pmc, hartid, PMC_BLK_CORE, PMC_TRANS_MODE_DYNAMIC | PMC_BLK_MODE_CONFIG_OFF);
pmc_set_command(&pmc, hartid, PMC_BLK_CORE_VFPU, PMC_TRANS_MODE_DYNAMIC | PMC_BLK_LOW_POWER_STATE_OFF);
} else {
/* cpu_hotplug power down, set trans bit to direct mode */
pmc_set_command(&pmc, hartid, PMC_BLK_CORE, PMC_TRANS_MODE_DIRECT | PMC_BLK_MODE_CONFIG_OFF);
pmc_set_command(&pmc, hartid, PMC_BLK_CORE_VFPU, PMC_TRANS_MODE_DIRECT | PMC_BLK_LOW_POWER_STATE_OFF);
}

/* close the prefetch */
csr_clear(THEAD_C9XX_CSR_MHINT, 0x1 << 2);

/* clean and invalid core's dcache */
asm volatile(XUANTIE_DCACHE_INVAL_CLEAN_ALL);

/* close the dcache */
csr_clear(THEAD_C9XX_CSR_MHCR, 0x1 << 1);

/* close the snoop */
csr_clear(THEAD_C9XX_CSR_MSMPR, 0x1 << 0);

/* sync.s */
asm volatile(XUANTIE_SYNC_S);

wfi();
}

static int xuantie_hart_suspend(u32 suspend_type)
{
u32 hartid = current_hartid();

/* Use the generic code for retentive suspend. */
if (!(suspend_type & SBI_HSM_SUSP_NON_RET_BIT))
return SBI_ENOTSUPP;

xuantie_hart_poweroff(hartid, true);

return 0;
}

static void xuantie_hart_resume(void)
{
u32 hartid = current_hartid();

pmc_set_command(&pmc, hartid, PMC_BLK_CORE, PMC_TRANS_MODE_DIRECT | PMC_BLK_MODE_CONFIG_ON);
pmc_set_command(&pmc, hartid, PMC_BLK_CORE_VFPU, PMC_TRANS_MODE_DIRECT | PMC_BLK_LOW_POWER_STATE_RET);
}

int xuantie_hart_start(u32 hartid, ulong saddr)
{
pmc_set_command(&pmc, hartid, PMC_BLK_CORE, PMC_TRANS_MODE_DIRECT | PMC_BLK_MODE_CONFIG_ON);
pmc_set_command(&pmc, hartid, PMC_BLK_CORE_VFPU, PMC_TRANS_MODE_DIRECT | PMC_BLK_LOW_POWER_STATE_RET);

return 0;
}

int xuantie_hart_stop(void)
{
u32 hartid = current_hartid();

xuantie_hart_poweroff(hartid, false);

return 0;
}

static const struct sbi_hsm_device xuantie_hsm = {
.name = "xuantie-hsm",
.hart_suspend = xuantie_hart_suspend,
.hart_resume = xuantie_hart_resume,
.hart_start = xuantie_hart_start,
.hart_stop = xuantie_hart_stop,
};

static int xuantie_system_suspend_check(u32 sleep_type)
{
return sleep_type == SBI_SUSP_SLEEP_TYPE_SUSPEND ? 0 : SBI_EINVAL;
}

static int xuantie_system_suspend(u32 sleep_type, unsigned long mmode_resume_addr)
{
u32 hartid = current_hartid();

if (sleep_type != SBI_SUSP_SLEEP_TYPE_SUSPEND)
return SBI_EINVAL;

/* cpu poweroff after wfi */
xuantie_hart_poweroff(hartid, true);

return 0;
}

static struct sbi_system_suspend_device xuantie_system_suspend_dev = {
.name = "xuantie-system-suspend",
.system_suspend_check = xuantie_system_suspend_check,
.system_suspend = xuantie_system_suspend,
};

static int xuantie_system_reset_check(u32 type, u32 reason)
{
switch (type) {
case SBI_SRST_RESET_TYPE_SHUTDOWN:
return 1;
case SBI_SRST_RESET_TYPE_COLD_REBOOT:
case SBI_SRST_RESET_TYPE_WARM_REBOOT:
return 255;
}

return 0;
}

static void xuantie_system_reset(u32 type, u32 reason)
{
}

static struct sbi_system_reset_device xuantie_reset = {
.name = "xuantie-reset",
.system_reset_check = xuantie_system_reset_check,
.system_reset = xuantie_system_reset
};

static int xuantie_pmc_test_device_init(void)
{
int nodeoffset, rc;
void *fdt = fdt_get_address();

nodeoffset = fdt_node_offset_by_compatible(fdt, -1, "xuantie,pmc");
if (nodeoffset < 0)
return nodeoffset;

rc = fdt_get_node_addr_size(fdt, nodeoffset, 0, (uint64_t *)&pmc.pmc_addr, NULL);
if (rc)
return SBI_ENODEV;

if (!fdt_node_is_enabled(fdt, nodeoffset))
return SBI_ENODEV;

sbi_system_reset_add_device(&xuantie_reset);
sbi_hsm_set_device(&xuantie_hsm);
sbi_system_suspend_set_device(&xuantie_system_suspend_dev);

return 0;
}

static int xuantie_final_init(bool cold_boot, const struct fdt_match *match)
{
if (cold_boot) {
xuantie_riscv_cfg_init();
xuantie_pmc_test_device_init();
}

return 0;
}

static const struct fdt_match xuantie_pmc_match[] = {
{ .compatible = "xuantie,dummy" },
{ },
};

const struct platform_override xuantie_pmc = {
.match_table = xuantie_pmc_match,
.final_init = xuantie_final_init,
};
52 changes: 52 additions & 0 deletions platform/generic/xuantie/xuantie_pmc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* SPDX-License-Identifier: BSD-3-Clause
*/

#ifndef __XUANTIE_PMC_H__
#define __XUANTIE_PMC_H__

#include <sbi/sbi_types.h>

/* clang-format off */

#define XUANTIE_DCACHE_INVAL_CLEAN_ALL ".long 0x0030000b"
#define XUANTIE_SYNC_S ".long 0x0190000b"

/*
core PMC: blk1 = VFPU; blk2 = MPU
cluster PMC: blk1 = l2cache
*/
#define PMC_BLK_CORE 0
#define PMC_BLK_CORE_VFPU 1
#define PMC_BLK_CORE_MPU 2
#define PMC_BLK_CLUSTER 0
#define PMC_BLK_CLUSTER_L2 1

#define PMC_TRANS_MODE_SHIFT 4
#define PMC_TRANS_MODE_DIRECT (_UL(1) << PMC_TRANS_MODE_SHIFT)
#define PMC_TRANS_MODE_DYNAMIC (_UL(0) << PMC_TRANS_MODE_SHIFT)
/*pmc_blk_mode_config (basic type)*/
#define PMC_BLK_MODE_CONFIG_0 0 // OFF pstate enable
#define PMC_BLK_MODE_CONFIG_1 1
#define PMC_BLK_MODE_CONFIG_2 2
#define PMC_BLK_MODE_CONFIG_3 3
#define PMC_BLK_MODE_CONFIG_4 4
#define PMC_BLK_MODE_CONFIG_5 5
#define PMC_BLK_MODE_CONFIG_6 6
#define PMC_BLK_MODE_CONFIG_7 7
#define PMC_BLK_MODE_CONFIG_8 8 // ON pstate enable
#define PMC_BLK_MODE_CONFIG_9 9
#define PMC_BLK_MODE_CONFIG_ON PMC_BLK_MODE_CONFIG_8
#define PMC_BLK_MODE_CONFIG_OFF PMC_BLK_MODE_CONFIG_0
/*pmc_blk_mode_config (pe type)*/
#define PMC_BLK_LOW_POWER_STATE_OFF 0
#define PMC_BLK_LOW_POWER_STATE_RET 1


/* clang-format on */

struct xuantie_pmc_data {
unsigned long pmc_addr;
};

#endif /* __XUANTIE_PMC_H__ */