Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update generic platform #345

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion sm/opensbi
57 changes: 57 additions & 0 deletions sm/plat/generic/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# SPDX-License-Identifier: BSD-2-Clause

config PLATFORM_GENERIC
bool
select FDT
select FDT_DOMAIN
select FDT_PMU
default y

if PLATFORM_GENERIC

config PLATFORM_GENERIC_NAME
string "Platform default name"
default "Generic"

config PLATFORM_GENERIC_MAJOR_VER
int "Platform major version"
range 0 65535
default 0

config PLATFORM_GENERIC_MINOR_VER
int "Platform minor version"
range 0 65535
default 1

config PLATFORM_ALLWINNER_D1
bool "Allwinner D1 support"
depends on FDT_IRQCHIP_PLIC
default n

config PLATFORM_ANDES_AE350
bool "Andes AE350 support"
select SYS_ATCSMU
default n

config PLATFORM_RENESAS_RZFIVE
bool "Renesas RZ/Five support"
select ANDES45_PMA
select ANDES_SBI
default n

config PLATFORM_SIFIVE_FU540
bool "SiFive FU540 support"
default n

config PLATFORM_SIFIVE_FU740
bool "SiFive FU740 support"
depends on FDT_RESET && FDT_I2C
default n

config PLATFORM_STARFIVE_JH7110
bool "StarFive JH7110 support"
default n

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

endif
6 changes: 6 additions & 0 deletions sm/plat/generic/allwinner/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_ALLWINNER_D1) += sun20i_d1
platform-objs-$(CONFIG_PLATFORM_ALLWINNER_D1) += allwinner/sun20i-d1.o
291 changes: 291 additions & 0 deletions sm/plat/generic/allwinner/sun20i-d1.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,291 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 Samuel Holland <[email protected]>
*/

#include <platform_override.h>
#include <thead_c9xx.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_pmu.h>
#include <sbi/sbi_scratch.h>
#include <sbi_utils/fdt/fdt_fixup.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/irqchip/fdt_irqchip_plic.h>

#define SUN20I_D1_CCU_BASE ((void *)0x02001000)
#define SUN20I_D1_RISCV_CFG_BASE ((void *)0x06010000)
#define SUN20I_D1_PPU_BASE ((void *)0x07001000)
#define SUN20I_D1_PRCM_BASE ((void *)0x07010000)

/*
* CCU
*/

#define CCU_BGR_ENABLE (BIT(16) | BIT(0))

#define RISCV_CFG_BGR_REG 0xd0c
#define PPU_BGR_REG 0x1ac

/*
* CSRs
*/

#define CSR_MXSTATUS 0x7c0
#define CSR_MHCR 0x7c1
#define CSR_MCOR 0x7c2
#define CSR_MHINT 0x7c5

static unsigned long csr_mxstatus;
static unsigned long csr_mhcr;
static unsigned long csr_mhint;

static void sun20i_d1_csr_save(void)
{
/* Save custom CSRs. */
csr_mxstatus = csr_read(CSR_MXSTATUS);
csr_mhcr = csr_read(CSR_MHCR);
csr_mhint = csr_read(CSR_MHINT);

/* Flush and disable caches. */
csr_write(CSR_MCOR, 0x22);
csr_write(CSR_MHCR, 0x0);
}

static void sun20i_d1_csr_restore(void)
{
/* Invalidate caches and the branch predictor. */
csr_write(CSR_MCOR, 0x70013);

/* Restore custom CSRs, including the cache state. */
csr_write(CSR_MXSTATUS, csr_mxstatus);
csr_write(CSR_MHCR, csr_mhcr);
csr_write(CSR_MHINT, csr_mhint);
}

/*
* PLIC
*/

#define PLIC_SOURCES 175
#define PLIC_IE_WORDS (PLIC_SOURCES / 32 + 1)

static u8 plic_priority[1 + PLIC_SOURCES];
static u32 plic_sie[PLIC_IE_WORDS];
static u32 plic_threshold;

static void sun20i_d1_plic_save(void)
{
fdt_plic_context_save(true, plic_sie, &plic_threshold, PLIC_IE_WORDS);
fdt_plic_priority_save(plic_priority, PLIC_SOURCES);
}

static void sun20i_d1_plic_restore(void)
{
thead_plic_restore();
fdt_plic_priority_restore(plic_priority, PLIC_SOURCES);
fdt_plic_context_restore(true, plic_sie, plic_threshold,
PLIC_IE_WORDS);
}

/*
* PPU
*/

#define PPU_PD_ACTIVE_CTRL 0x2c

static void sun20i_d1_ppu_save(void)
{
/* Enable MMIO access. Do not assume S-mode leaves the clock enabled. */
writel_relaxed(CCU_BGR_ENABLE, SUN20I_D1_PRCM_BASE + PPU_BGR_REG);

/* Activate automatic power-down during the next WFI. */
writel_relaxed(1, SUN20I_D1_PPU_BASE + PPU_PD_ACTIVE_CTRL);
}

static void sun20i_d1_ppu_restore(void)
{
/* Disable automatic power-down. */
writel_relaxed(0, SUN20I_D1_PPU_BASE + PPU_PD_ACTIVE_CTRL);
}

/*
* RISCV_CFG
*/

#define RESET_ENTRY_LO_REG 0x0004
#define RESET_ENTRY_HI_REG 0x0008
#define WAKEUP_EN_REG 0x0020
#define WAKEUP_MASK_REG(i) (0x0024 + 4 * (i))

static void sun20i_d1_riscv_cfg_save(void)
{
/* Enable MMIO access. Do not assume S-mode leaves the clock enabled. */
writel_relaxed(CCU_BGR_ENABLE, SUN20I_D1_CCU_BASE + RISCV_CFG_BGR_REG);

/*
* Copy the SIE bits to the wakeup registers. D1 has 160 "real"
* interrupt sources, numbered 16-175. These are the ones that map to
* the wakeup mask registers (the offset is for GIC compatibility). So
* copying SIE to the wakeup mask needs some bit manipulation.
*/
for (int i = 0; i < PLIC_IE_WORDS - 1; i++)
writel_relaxed(plic_sie[i] >> 16 | plic_sie[i + 1] << 16,
SUN20I_D1_RISCV_CFG_BASE + WAKEUP_MASK_REG(i));

/* Enable PPU wakeup for interrupts. */
writel_relaxed(1, SUN20I_D1_RISCV_CFG_BASE + WAKEUP_EN_REG);
}

static void sun20i_d1_riscv_cfg_restore(void)
{
/* Disable PPU wakeup for interrupts. */
writel_relaxed(0, SUN20I_D1_RISCV_CFG_BASE + WAKEUP_EN_REG);
}

static void sun20i_d1_riscv_cfg_init(void)
{
u64 entry = sbi_hartid_to_scratch(0)->warmboot_addr;

/* Enable MMIO access. */
writel_relaxed(CCU_BGR_ENABLE, SUN20I_D1_CCU_BASE + RISCV_CFG_BGR_REG);

/* Program the reset entry address. */
writel_relaxed(entry, SUN20I_D1_RISCV_CFG_BASE + RESET_ENTRY_LO_REG);
writel_relaxed(entry >> 32, SUN20I_D1_RISCV_CFG_BASE + RESET_ENTRY_HI_REG);
}

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

sun20i_d1_plic_save();
sun20i_d1_ppu_save();
sun20i_d1_riscv_cfg_save();
sun20i_d1_csr_save();

/*
* If no interrupt is pending, this will power down the CPU power
* domain. Otherwise, this will fall through, and the generic HSM
* code will jump to the resume address.
*/
wfi();

return 0;
}

static void sun20i_d1_hart_resume(void)
{
sun20i_d1_csr_restore();
sun20i_d1_riscv_cfg_restore();
sun20i_d1_ppu_restore();
sun20i_d1_plic_restore();
}

static const struct sbi_hsm_device sun20i_d1_ppu = {
.name = "sun20i-d1-ppu",
.hart_suspend = sun20i_d1_hart_suspend,
.hart_resume = sun20i_d1_hart_resume,
};

static int sun20i_d1_final_init(bool cold_boot, const struct fdt_match *match)
{
if (cold_boot) {
sun20i_d1_riscv_cfg_init();
sbi_hsm_set_device(&sun20i_d1_ppu);
}

return 0;
}

static const struct sbi_cpu_idle_state sun20i_d1_cpu_idle_states[] = {
{
.name = "cpu-nonretentive",
.suspend_param = SBI_HSM_SUSPEND_NON_RET_DEFAULT,
.local_timer_stop = true,
.entry_latency_us = 40,
.exit_latency_us = 67,
.min_residency_us = 1100,
.wakeup_latency_us = 67,
},
{ }
};

static int sun20i_d1_fdt_fixup(void *fdt, const struct fdt_match *match)
{
return fdt_add_cpu_idle_states(fdt, sun20i_d1_cpu_idle_states);
}

static void thead_c9xx_pmu_ctr_enable_irq(uint32_t ctr_idx)
{
unsigned long mip_val;

if (ctr_idx >= SBI_PMU_HW_CTR_MAX)
return;

mip_val = csr_read(CSR_MIP);
/**
* Clear out the OF bit so that next interrupt can be enabled.
* This should be done only when the corresponding overflow interrupt
* bit is cleared. That indicates that software has already handled the
* previous interrupts or the hardware yet to set an overflow interrupt.
* Otherwise, there will be race conditions where we may clear the bit
* the software is yet to handle the interrupt.
*/
if (!(mip_val & THEAD_C9XX_MIP_MOIP))
csr_clear(THEAD_C9XX_CSR_MCOUNTEROF, BIT(ctr_idx));

/**
* SSCOFPMF uses the OF bit for enabling/disabling the interrupt,
* while the C9XX has designated enable bits.
* So enable per-counter interrupt on C9xx here.
*/
csr_set(THEAD_C9XX_CSR_MCOUNTERINTEN, BIT(ctr_idx));
}

static void thead_c9xx_pmu_ctr_disable_irq(uint32_t ctr_idx)
{
csr_clear(THEAD_C9XX_CSR_MCOUNTERINTEN, BIT(ctr_idx));
}

static int thead_c9xx_pmu_irq_bit(void)
{
return THEAD_C9XX_MIP_MOIP;
}

const struct sbi_pmu_device thead_c9xx_pmu_device = {
.hw_counter_enable_irq = thead_c9xx_pmu_ctr_enable_irq,
.hw_counter_disable_irq = thead_c9xx_pmu_ctr_disable_irq,
.hw_counter_irq_bit = thead_c9xx_pmu_irq_bit,
};

static int sun20i_d1_extensions_init(const struct fdt_match *match,
struct sbi_hart_features *hfeatures)
{
sbi_pmu_set_device(&thead_c9xx_pmu_device);

/* auto-detection doesn't work on t-head c9xx cores */
hfeatures->mhpm_count = 29;
hfeatures->mhpm_bits = 64;

return 0;
}

static const struct fdt_match sun20i_d1_match[] = {
{ .compatible = "allwinner,sun20i-d1" },
{ },
};

const struct platform_override sun20i_d1 = {
.match_table = sun20i_d1_match,
.final_init = sun20i_d1_final_init,
.fdt_fixup = sun20i_d1_fdt_fixup,
.extensions_init = sun20i_d1_extensions_init,
};
9 changes: 9 additions & 0 deletions sm/plat/generic/andes/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# SPDX-License-Identifier: BSD-2-Clause

config ANDES45_PMA
bool "Andes PMA support"
default n

config ANDES_SBI
bool "Andes SBI support"
default n
Loading