sunxi: psci: Implement H3 DRAM DVFS

Signed-off-by: Samuel Holland <samuel@sholland.org>
This commit is contained in:
Samuel Holland 2022-12-28 21:14:38 -06:00
parent c8ea2780f2
commit a74bc5a9ae
2 changed files with 131 additions and 0 deletions

View File

@ -128,6 +128,8 @@ _psci_table:
.word psi_stat_residency
.word ARM_PSCI_1_0_FN_STAT_COUNT
.word psci_stat_count
.word 0x83000033
.word sunxi_dram_dvfs_req
.word 0
.word 0

View File

@ -121,6 +121,44 @@ static inline u32 __secure read_mpidr(void)
return val;
}
static void __secure cp15_write_cntp_tval(u32 tval)
{
asm volatile ("mcr p15, 0, %0, c14, c2, 0" : : "r" (tval));
}
static void __secure cp15_write_cntp_ctl(u32 val)
{
asm volatile ("mcr p15, 0, %0, c14, c2, 1" : : "r" (val));
}
static u32 __secure cp15_read_cntp_ctl(void)
{
u32 val;
asm volatile ("mrc p15, 0, %0, c14, c2, 1" : "=r" (val));
return val;
}
#define ONE_US (CONFIG_COUNTER_FREQUENCY / 1000000)
static void __secure mdfs_udelay(u32 us)
{
u32 reg = ONE_US * us;
cp15_write_cntp_tval(reg);
isb();
cp15_write_cntp_ctl(3);
do {
isb();
reg = cp15_read_cntp_ctl();
} while (!(reg & BIT(2)));
cp15_write_cntp_ctl(0);
isb();
}
static void __secure scpi_begin_command(void)
{
u32 mpidr = read_mpidr();
@ -381,6 +419,97 @@ s32 __secure psci_system_reset2(u32 __always_unused function_id,
for (;;) wfi();
}
#define MCTL_COM_BASE ((void *)(0x1c62000))
#define MCTL_CTL_BASE ((void *)(0x1c63000))
#define _CCM_PLL_DDR_REG (CCM_PLL_BASE + 0x20)
#define MC_WORK_MODE (MCTL_COM_BASE + 0x00)
#define PIR (MCTL_CTL_BASE + 0x00)
#define PWRCTL (MCTL_CTL_BASE + 0x04)
#define PGSR0 (MCTL_CTL_BASE + 0x10)
#define STATR (MCTL_CTL_BASE + 0x18)
#define DTCR (MCTL_CTL_BASE + 0xc0)
#define ODTMAP (MCTL_CTL_BASE + 0x120)
#define DXnGCR0(x) (MCTL_CTL_BASE + 0x344 + 0x80*(x))
s32 __secure sunxi_dram_dvfs_req(u32 __always_unused function_id,
u32 freq, u32 flags)
{
u32 rank_num, reg_val;
unsigned int i = 0;
rank_num = readl(MC_WORK_MODE) & 0x1;
/* 1. enter self-refresh and disable all master access */
reg_val = readl(PWRCTL);
reg_val |= (0x1<<0);
reg_val |= (0x1<<8);
writel(reg_val, PWRCTL);
mdfs_udelay(1);
/* make sure enter self-refresh */
while ((readl(STATR) & 0x7) != 0x3)
;
/* 2.Update PLL setting and wait 1ms */
reg_val = readl(SUNXI_CCM_BASE + 0x20);
reg_val |= (1U << 20);
writel(reg_val, SUNXI_CCM_BASE + 0x20);
mdfs_udelay(1000);
/* 3.set PIR register issue phy reset and DDL calibration */
if (rank_num) {
reg_val = readl(DTCR);
reg_val &= ~(0x3<<24);
reg_val |= (0x3<<24);
writel(reg_val, DTCR);
} else {
reg_val = readl(DTCR);
reg_val &= ~(0x3<<24);
reg_val |= (0x1<<24);
writel(reg_val, DTCR);
}
/* trigger phy reset and DDL calibration */
writel(0x40000061, PIR);
/* add 1us delay here */
mdfs_udelay(1);
/* wait for DLL Lock */
while ((readl(PGSR0) & 0x1) != 0x1)
;
/*4.setting ODT configure */
if (!(flags & BIT(0))) {
/* turn off DRAMC ODT */
for (i = 0; i < 4; i++) {
reg_val = readl(DXnGCR0(i));
reg_val &= ~(0x3U<<4);
reg_val |= (0x2<<4);
writel(reg_val, DXnGCR0(i));
}
} else {
/* turn on DRAMC dynamic ODT */
for (i = 0; i < 4; i++) {
reg_val = readl(DXnGCR0(i));
reg_val &= ~(0x3U<<4);
writel(reg_val, DXnGCR0(i));
}
}
/* 5.exit self-refresh and enable all master access */
reg_val = readl(PWRCTL);
reg_val &= ~(0x1<<0);
reg_val &= ~(0x1<<8);
writel(reg_val, PWRCTL);
mdfs_udelay(1);
/* make sure exit self-refresh */
while ((readl(STATR) & 0x7) != 0x1)
;
return 0;
}
/*
* R40 is different from other single cluster SoCs. The secondary core
* entry address register is in the SRAM controller address range.