Commit 3ea2cc00 authored by Sandrine Bailleux's avatar Sandrine Bailleux Committed by TrustedFirmware Code Review
Browse files

Merge changes I93ecff4d,I30dd9a95,I8207eea9,Id4197b07,Ib810125b, ... into integration

* changes:
  mediatek: mt8183: add MTK MCDI driver
  mediatek: mt8183: add MTK SSPM driver
  mediatek: mt8183: add MTK SPM driver
  mediatek: mt8183: add MTK uart driver for controlling clock gate
  mediatek: mt8183: configure MCUSYS DCM
  mediatek: mt8173: refactor RTC and PMIC drivers
parents ea735643 539061b8
/*
* Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <lib/mmio.h>
#include <mt8173_def.h>
#include <pmic_wrap_init.h>
/* pmic wrap module wait_idle and read polling interval (in microseconds) */
enum {
WAIT_IDLE_POLLING_DELAY_US = 1,
READ_POLLING_DELAY_US = 2
};
static inline uint32_t wait_for_state_idle(uint32_t timeout_us,
void *wacs_register,
void *wacs_vldclr_register,
uint32_t *read_reg)
{
uint32_t reg_rdata;
uint32_t retry;
retry = (timeout_us + WAIT_IDLE_POLLING_DELAY_US) /
WAIT_IDLE_POLLING_DELAY_US;
do {
udelay(WAIT_IDLE_POLLING_DELAY_US);
reg_rdata = mmio_read_32((uintptr_t)wacs_register);
/* if last read command timeout,clear vldclr bit
read command state machine:FSM_REQ-->wfdle-->WFVLDCLR;
write:FSM_REQ-->idle */
switch (((reg_rdata >> RDATA_WACS_FSM_SHIFT) &
RDATA_WACS_FSM_MASK)) {
case WACS_FSM_WFVLDCLR:
mmio_write_32((uintptr_t)wacs_vldclr_register, 1);
ERROR("WACS_FSM = PMIC_WRAP_WACS_VLDCLR\n");
break;
case WACS_FSM_WFDLE:
ERROR("WACS_FSM = WACS_FSM_WFDLE\n");
break;
case WACS_FSM_REQ:
ERROR("WACS_FSM = WACS_FSM_REQ\n");
break;
case WACS_FSM_IDLE:
goto done;
default:
break;
}
retry--;
} while (retry);
done:
if (!retry) /* timeout */
return E_PWR_WAIT_IDLE_TIMEOUT;
if (read_reg)
*read_reg = reg_rdata;
return 0;
}
static inline uint32_t wait_for_state_ready(uint32_t timeout_us,
void *wacs_register,
uint32_t *read_reg)
{
uint32_t reg_rdata;
uint32_t retry;
retry = (timeout_us + READ_POLLING_DELAY_US) / READ_POLLING_DELAY_US;
do {
udelay(READ_POLLING_DELAY_US);
reg_rdata = mmio_read_32((uintptr_t)wacs_register);
if (((reg_rdata >> RDATA_WACS_FSM_SHIFT) & RDATA_WACS_FSM_MASK)
== WACS_FSM_WFVLDCLR)
break;
retry--;
} while (retry);
if (!retry) { /* timeout */
ERROR("timeout when waiting for idle\n");
return E_PWR_WAIT_IDLE_TIMEOUT_READ;
}
if (read_reg)
*read_reg = reg_rdata;
return 0;
}
static int32_t pwrap_wacs2(uint32_t write,
uint32_t adr,
uint32_t wdata,
uint32_t *rdata,
uint32_t init_check)
{
uint32_t reg_rdata = 0;
uint32_t wacs_write = 0;
uint32_t wacs_adr = 0;
uint32_t wacs_cmd = 0;
uint32_t return_value = 0;
if (init_check) {
reg_rdata = mmio_read_32((uintptr_t)&mt8173_pwrap->wacs2_rdata);
/* Prevent someone to used pwrap before pwrap init */
if (((reg_rdata >> RDATA_INIT_DONE_SHIFT) &
RDATA_INIT_DONE_MASK) != WACS_INIT_DONE) {
ERROR("initialization isn't finished\n");
return E_PWR_NOT_INIT_DONE;
}
}
reg_rdata = 0;
/* Check IDLE in advance */
return_value = wait_for_state_idle(TIMEOUT_WAIT_IDLE,
&mt8173_pwrap->wacs2_rdata,
&mt8173_pwrap->wacs2_vldclr,
0);
if (return_value != 0) {
ERROR("wait_for_fsm_idle fail,return_value=%d\n", return_value);
goto FAIL;
}
wacs_write = write << 31;
wacs_adr = (adr >> 1) << 16;
wacs_cmd = wacs_write | wacs_adr | wdata;
mmio_write_32((uintptr_t)&mt8173_pwrap->wacs2_cmd, wacs_cmd);
if (write == 0) {
if (NULL == rdata) {
ERROR("rdata is a NULL pointer\n");
return_value = E_PWR_INVALID_ARG;
goto FAIL;
}
return_value = wait_for_state_ready(TIMEOUT_READ,
&mt8173_pwrap->wacs2_rdata,
&reg_rdata);
if (return_value != 0) {
ERROR("wait_for_fsm_vldclr fail,return_value=%d\n",
return_value);
goto FAIL;
}
*rdata = ((reg_rdata >> RDATA_WACS_RDATA_SHIFT)
& RDATA_WACS_RDATA_MASK);
mmio_write_32((uintptr_t)&mt8173_pwrap->wacs2_vldclr, 1);
}
FAIL:
return return_value;
}
/* external API for pmic_wrap user */
int32_t pwrap_read(uint32_t adr, uint32_t *rdata)
{
return pwrap_wacs2(0, adr, 0, rdata, 1);
}
int32_t pwrap_write(uint32_t adr, uint32_t wdata)
{
return pwrap_wacs2(1, adr, wdata, 0, 1);
}
......@@ -7,11 +7,13 @@
#ifndef PMIC_WRAP_INIT_H
#define PMIC_WRAP_INIT_H
#include <platform_def.h>
/* external API */
int32_t pwrap_read(uint32_t adr, uint32_t *rdata);
int32_t pwrap_write(uint32_t adr, uint32_t wdata);
static struct mt8173_pmic_wrap_regs *const mt8173_pwrap =
static struct mt8173_pmic_wrap_regs *const mtk_pwrap =
(void *)PMIC_WRAP_BASE;
/* timeout setting */
......
......@@ -5,66 +5,11 @@
*/
#include <assert.h>
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <mt8173_def.h>
#include <pmic_wrap_init.h>
#include <rtc.h>
/* RTC busy status polling interval and retry count */
enum {
RTC_WRTGR_POLLING_DELAY_MS = 10,
RTC_WRTGR_POLLING_CNT = 100
};
static uint16_t RTC_Read(uint32_t addr)
{
uint32_t rdata = 0;
pwrap_read((uint32_t)addr, &rdata);
return (uint16_t)rdata;
}
static void RTC_Write(uint32_t addr, uint16_t data)
{
pwrap_write((uint32_t)addr, (uint32_t)data);
}
static inline int32_t rtc_busy_wait(void)
{
uint64_t retry = RTC_WRTGR_POLLING_CNT;
do {
mdelay(RTC_WRTGR_POLLING_DELAY_MS);
if (!(RTC_Read(RTC_BBPU) & RTC_BBPU_CBUSY))
return 1;
retry--;
} while (retry);
ERROR("[RTC] rtc cbusy time out!\n");
return 0;
}
static int32_t Write_trigger(void)
{
RTC_Write(RTC_WRTGR, 1);
return rtc_busy_wait();
}
static int32_t Writeif_unlock(void)
{
RTC_Write(RTC_PROT, RTC_PROT_UNLOCK1);
if (!Write_trigger())
return 0;
RTC_Write(RTC_PROT, RTC_PROT_UNLOCK2);
if (!Write_trigger())
return 0;
return 1;
}
void rtc_bbpu_power_down(void)
{
uint16_t bbpu;
......@@ -73,7 +18,7 @@ void rtc_bbpu_power_down(void)
bbpu = RTC_BBPU_KEY | RTC_BBPU_AUTO | RTC_BBPU_PWREN;
if (Writeif_unlock()) {
RTC_Write(RTC_BBPU, bbpu);
if (!Write_trigger())
if (!RTC_Write_Trigger())
assert(0);
} else {
assert(0);
......
......@@ -49,6 +49,12 @@ enum {
RTC_BBPU_KEY = 0x43 << 8
};
/* external API */
uint16_t RTC_Read(uint32_t addr);
void RTC_Write(uint32_t addr, uint16_t data);
int32_t rtc_busy_wait(void);
int32_t RTC_Write_Trigger(void);
int32_t Writeif_unlock(void);
void rtc_bbpu_power_down(void);
#endif /* RTC_H */
......@@ -35,6 +35,8 @@ BL31_SOURCES += common/desc_image_load.c \
lib/cpus/aarch64/cortex_a53.S \
lib/cpus/aarch64/cortex_a57.S \
lib/cpus/aarch64/cortex_a72.S \
${MTK_PLAT}/common/drivers/pmic_wrap/pmic_wrap_init.c \
${MTK_PLAT}/common/drivers/rtc/rtc_common.c \
${MTK_PLAT}/common/mtk_plat_common.c \
${MTK_PLAT}/common/mtk_sip_svc.c \
${MTK_PLAT_SOC}/aarch64/plat_helpers.S \
......@@ -42,7 +44,6 @@ BL31_SOURCES += common/desc_image_load.c \
${MTK_PLAT_SOC}/bl31_plat_setup.c \
${MTK_PLAT_SOC}/drivers/crypt/crypt.c \
${MTK_PLAT_SOC}/drivers/mtcmos/mtcmos.c \
${MTK_PLAT_SOC}/drivers/pmic/pmic_wrap_init.c \
${MTK_PLAT_SOC}/drivers/rtc/rtc.c \
${MTK_PLAT_SOC}/drivers/spm/spm.c \
${MTK_PLAT_SOC}/drivers/spm/spm_hotplug.c \
......
......@@ -16,6 +16,7 @@
#include <mt_gic_v3.h>
#include <lib/coreboot.h>
#include <lib/mmio.h>
#include <mtk_mcdi.h>
#include <mtk_plat_common.h>
#include <mtspmc.h>
#include <plat_debug.h>
......@@ -23,6 +24,7 @@
#include <plat_private.h>
#include <platform_def.h>
#include <scu.h>
#include <spm.h>
#include <drivers/ti/uart/uart_16550.h>
static entry_point_info_t bl32_ep_info;
......@@ -32,15 +34,49 @@ static void platform_setup_cpu(void)
{
mmio_write_32((uintptr_t)&mt8183_mcucfg->mp0_rw_rsvd0, 0x00000001);
VERBOSE("addr of cci_adb400_dcm_config: 0x%x\n",
mmio_read_32((uintptr_t)&mt8183_mcucfg->cci_adb400_dcm_config));
VERBOSE("addr of sync_dcm_config: 0x%x\n",
mmio_read_32((uintptr_t)&mt8183_mcucfg->sync_dcm_config));
VERBOSE("mp0_spmc: 0x%x\n",
mmio_read_32((uintptr_t)&mt8183_mcucfg->mp0_cputop_spmc_ctl));
VERBOSE("mp1_spmc: 0x%x\n",
mmio_read_32((uintptr_t)&mt8183_mcucfg->mp1_cputop_spmc_ctl));
/* Mcusys dcm control */
/* Enable pll plldiv dcm */
mmio_setbits_32((uintptr_t)&mt8183_mcucfg->bus_pll_divider_cfg,
BUS_PLLDIV_DCM);
mmio_setbits_32((uintptr_t)&mt8183_mcucfg->mp0_pll_divider_cfg,
MP0_PLLDIV_DCM);
mmio_setbits_32((uintptr_t)&mt8183_mcucfg->mp2_pll_divider_cfg,
MP2_PLLDIV_DCM);
/* Enable mscib dcm */
mmio_clrsetbits_32((uintptr_t)&mt8183_mcucfg->mscib_dcm_en,
MCSIB_CACTIVE_SEL_MASK, MCSIB_CACTIVE_SEL);
mmio_clrsetbits_32((uintptr_t)&mt8183_mcucfg->mscib_dcm_en,
MCSIB_DCM_MASK, MCSIB_DCM);
/* Enable adb400 dcm */
mmio_clrsetbits_32((uintptr_t)&mt8183_mcucfg->cci_adb400_dcm_config,
CCI_ADB400_DCM_MASK, CCI_ADB400_DCM);
/* Enable bus clock dcm */
mmio_setbits_32((uintptr_t)&mt8183_mcucfg->cci_clk_ctrl,
MCU_BUS_DCM);
/* Enable bus fabric dcm */
mmio_clrsetbits_32(
(uintptr_t)&mt8183_mcucfg->mcusys_bus_fabric_dcm_ctrl,
MCUSYS_BUS_FABRIC_DCM_MASK,
MCUSYS_BUS_FABRIC_DCM);
/* Enable l2c sram dcm */
mmio_setbits_32((uintptr_t)&mt8183_mcucfg->l2c_sram_ctrl,
L2C_SRAM_DCM);
/* Enable busmp0 sync dcm */
mmio_clrsetbits_32((uintptr_t)&mt8183_mcucfg->sync_dcm_config,
SYNC_DCM_MASK, SYNC_DCM);
/* Enable cntvalue dcm */
mmio_setbits_32((uintptr_t)&mt8183_mcucfg->mcu_misc_dcm_ctrl,
CNTVALUEB_DCM);
/* Enable dcm cluster stall */
mmio_clrsetbits_32(
(uintptr_t)&mt8183_mcucfg->sync_dcm_cluster_config,
MCUSYS_MAX_ACCESS_LATENCY_MASK,
MCUSYS_MAX_ACCESS_LATENCY);
mmio_setbits_32((uintptr_t)&mt8183_mcucfg->sync_dcm_cluster_config,
MCU0_SYNC_DCM_STALL_WR_EN);
/* Enable rgu dcm */
mmio_setbits_32((uintptr_t)&mt8183_mcucfg->mp0_rgu_dcm_config,
CPUSYS_RGU_DCM_CINFIG);
}
/*******************************************************************************
......@@ -112,6 +148,8 @@ void bl31_platform_setup(void)
#if SPMC_MODE == 1
spmc_init();
#endif
spm_boot_init();
mcdi_init();
}
/*******************************************************************************
......
/*
* Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <lib/mmio.h>
#include <sspm_reg.h>
#include <mtk_mcdi.h>
static inline uint32_t mcdi_mbox_read(uint32_t id)
{
return mmio_read_32(SSPM_MBOX_3_BASE + (id << 2));
}
static inline void mcdi_mbox_write(uint32_t id, uint32_t val)
{
mmio_write_32(SSPM_MBOX_3_BASE + (id << 2), val);
}
void sspm_set_bootaddr(uint32_t bootaddr)
{
mcdi_mbox_write(MCDI_MBOX_BOOTADDR, bootaddr);
}
void sspm_cluster_pwr_off_notify(uint32_t cluster)
{
mcdi_mbox_write(MCDI_MBOX_CLUSTER_0_ATF_ACTION_DONE + cluster, 1);
}
void sspm_cluster_pwr_on_notify(uint32_t cluster)
{
mcdi_mbox_write(MCDI_MBOX_CLUSTER_0_ATF_ACTION_DONE + cluster, 0);
}
void sspm_standbywfi_irq_enable(uint32_t cpu_idx)
{
mmio_write_32(SSPM_CFGREG_ACAO_INT_SET, STANDBYWFI_EN(cpu_idx));
}
uint32_t mcdi_avail_cpu_mask_read(void)
{
return mcdi_mbox_read(MCDI_MBOX_AVAIL_CPU_MASK);
}
uint32_t mcdi_avail_cpu_mask_write(uint32_t mask)
{
mcdi_mbox_write(MCDI_MBOX_AVAIL_CPU_MASK, mask);
return mask;
}
uint32_t mcdi_avail_cpu_mask_set(uint32_t mask)
{
uint32_t m;
m = mcdi_mbox_read(MCDI_MBOX_AVAIL_CPU_MASK);
m |= mask;
mcdi_mbox_write(MCDI_MBOX_AVAIL_CPU_MASK, m);
return m;
}
uint32_t mcdi_avail_cpu_mask_clr(uint32_t mask)
{
uint32_t m;
m = mcdi_mbox_read(MCDI_MBOX_AVAIL_CPU_MASK);
m &= ~mask;
mcdi_mbox_write(MCDI_MBOX_AVAIL_CPU_MASK, m);
return m;
}
uint32_t mcdi_cpu_cluster_pwr_stat_read(void)
{
return mcdi_mbox_read(MCDI_MBOX_CPU_CLUSTER_PWR_STAT);
}
#define PAUSE_BIT 1
#define CLUSTER_OFF_OFS 20
#define CPU_OFF_OFS 24
#define CLUSTER_ON_OFS 4
#define CPU_ON_OFS 8
static uint32_t target_mask(int cluster, int cpu_idx, bool on)
{
uint32_t t = 0;
if (on) {
if (cluster >= 0)
t |= BIT(cluster + CLUSTER_ON_OFS);
if (cpu_idx >= 0)
t |= BIT(cpu_idx + CPU_ON_OFS);
} else {
if (cluster >= 0)
t |= BIT(cluster + CLUSTER_OFF_OFS);
if (cpu_idx >= 0)
t |= BIT(cpu_idx + CPU_OFF_OFS);
}
return t;
}
void mcdi_pause_clr(int cluster, int cpu_idx, bool on)
{
uint32_t tgt = target_mask(cluster, cpu_idx, on);
uint32_t m = mcdi_mbox_read(MCDI_MBOX_PAUSE_ACTION);
m &= ~tgt;
mcdi_mbox_write(MCDI_MBOX_PAUSE_ACTION, m);
}
void mcdi_pause_set(int cluster, int cpu_idx, bool on)
{
uint32_t tgt = target_mask(cluster, cpu_idx, on);
uint32_t m = mcdi_mbox_read(MCDI_MBOX_PAUSE_ACTION);
uint32_t tgtn = target_mask(-1, cpu_idx, !on);
/* request on and off at the same time to ensure it can be paused */
m |= tgt | tgtn;
mcdi_mbox_write(MCDI_MBOX_PAUSE_ACTION, m);
/* wait pause_ack */
while (!mcdi_mbox_read(MCDI_MBOX_PAUSE_ACK))
;
/* clear non-requested operation */
m &= ~tgtn;
mcdi_mbox_write(MCDI_MBOX_PAUSE_ACTION, m);
}
void mcdi_pause(void)
{
uint32_t m = mcdi_mbox_read(MCDI_MBOX_PAUSE_ACTION) | BIT(PAUSE_BIT);
mcdi_mbox_write(MCDI_MBOX_PAUSE_ACTION, m);
/* wait pause_ack */
while (!mcdi_mbox_read(MCDI_MBOX_PAUSE_ACK))
;
}
void mcdi_unpause(void)
{
uint32_t m = mcdi_mbox_read(MCDI_MBOX_PAUSE_ACTION) & ~BIT(PAUSE_BIT);
mcdi_mbox_write(MCDI_MBOX_PAUSE_ACTION, m);
}
void mcdi_hotplug_wait_ack(int cluster, int cpu_idx, bool on)
{
uint32_t tgt = target_mask(cluster, cpu_idx, on);
uint32_t ack = mcdi_mbox_read(MCDI_MBOX_HP_ACK);
/* wait until ack */
while (!(ack & tgt))
ack = mcdi_mbox_read(MCDI_MBOX_HP_ACK);
}
void mcdi_hotplug_clr(int cluster, int cpu_idx, bool on)
{
uint32_t tgt = target_mask(cluster, cpu_idx, on);
uint32_t tgt_cpu = target_mask(-1, cpu_idx, on);
uint32_t cmd = mcdi_mbox_read(MCDI_MBOX_HP_CMD);
uint32_t ack = mcdi_mbox_read(MCDI_MBOX_HP_ACK);
if (!(cmd & tgt))
return;
/* wait until ack */
while (!(ack & tgt_cpu))
ack = mcdi_mbox_read(MCDI_MBOX_HP_ACK);
cmd &= ~tgt;
mcdi_mbox_write(MCDI_MBOX_HP_CMD, cmd);
}
void mcdi_hotplug_set(int cluster, int cpu_idx, bool on)
{
uint32_t tgt = target_mask(cluster, cpu_idx, on);
uint32_t tgt_cpu = target_mask(-1, cpu_idx, on);
uint32_t cmd = mcdi_mbox_read(MCDI_MBOX_HP_CMD);
uint32_t ack = mcdi_mbox_read(MCDI_MBOX_HP_ACK);
if ((cmd & tgt) == tgt)
return;
/* wait until ack clear */
while (ack & tgt_cpu)
ack = mcdi_mbox_read(MCDI_MBOX_HP_ACK);
cmd |= tgt;
mcdi_mbox_write(MCDI_MBOX_HP_CMD, cmd);
}
bool check_mcdi_ctl_stat(void)
{
uint32_t clk_regs[] = {0x100010ac, 0x100010c8};
uint32_t clk_mask[] = {0x00028000, 0x00000018};
uint32_t tgt = target_mask(0, 0, true);
uint32_t m;
int i;
/* check clk status */
for (i = 0; i < ARRAY_SIZE(clk_regs); i++) {
if (mmio_read_32(clk_regs[i]) & clk_mask[i]) {
WARN("mcdi: clk check fail.\n");
return false;
}
}
/* check mcdi cmd handling */
m = mcdi_mbox_read(MCDI_MBOX_PAUSE_ACTION) | BIT(PAUSE_BIT);
mcdi_mbox_write(MCDI_MBOX_PAUSE_ACTION, m);
i = 500;
while (!mcdi_mbox_read(MCDI_MBOX_PAUSE_ACK) && --i > 0)
udelay(10);
m = mcdi_mbox_read(MCDI_MBOX_PAUSE_ACTION) & ~BIT(PAUSE_BIT);
mcdi_mbox_write(MCDI_MBOX_PAUSE_ACTION, m);
if (i == 0) {
WARN("mcdi: pause_action fail.\n");
return false;
}
/* check mcdi cmd handling */
if (mcdi_mbox_read(MCDI_MBOX_HP_CMD) ||
mcdi_mbox_read(MCDI_MBOX_HP_ACK)) {
WARN("mcdi: hp_cmd fail.\n");
return false;
}
mcdi_mbox_write(MCDI_MBOX_HP_CMD, tgt);
i = 500;
while ((mcdi_mbox_read(MCDI_MBOX_HP_ACK) & tgt) != tgt && --i > 0)
udelay(10);
mcdi_mbox_write(MCDI_MBOX_HP_CMD, 0);
if (i == 0) {
WARN("mcdi: hp_ack fail.\n");
return false;
}
return true;
}
void mcdi_init(void)
{
mcdi_avail_cpu_mask_write(0x01); /* cpu0 default on */
}
/*
* Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __MTK_MCDI_H__
#define __MTK_MCDI_H__
#include <stdbool.h>
void sspm_set_bootaddr(uint32_t bootaddr);
void sspm_standbywfi_irq_enable(uint32_t cpu_idx);
void sspm_cluster_pwr_off_notify(uint32_t cluster);
void sspm_cluster_pwr_on_notify(uint32_t cluster);
uint32_t mcdi_avail_cpu_mask_read(void);
uint32_t mcdi_avail_cpu_mask_write(uint32_t mask);
uint32_t mcdi_avail_cpu_mask_set(uint32_t mask);
uint32_t mcdi_avail_cpu_mask_clr(uint32_t mask);
uint32_t mcdi_cpu_cluster_pwr_stat_read(void);
void mcdi_pause(void);
void mcdi_unpause(void);
void mcdi_pause_set(int cluster, int cpu_idx, bool on);
void mcdi_pause_clr(int cluster, int cpu_idx, bool on);
void mcdi_hotplug_set(int cluster, int cpu_idx, bool on);
void mcdi_hotplug_clr(int cluster, int cpu_idx, bool on);
void mcdi_hotplug_wait_ack(int cluster, int cpu_idx, bool on);
bool check_mcdi_ctl_stat(void);
void mcdi_init(void);
#endif /* __MTK_MCDI_H__ */
......@@ -7,6 +7,24 @@
#include <pmic_wrap_init.h>
#include <pmic.h>
void bcpu_enable(uint32_t en)
{
pwrap_write(PMIC_VPROC11_OP_EN, 0x1);
if (en)
pwrap_write(PMIC_VPROC11_CON0, 1);
else
pwrap_write(PMIC_VPROC11_CON0, 0);
}
void bcpu_sram_enable(uint32_t en)
{
pwrap_write(PMIC_VSRAM_PROC11_OP_EN, 0x1);
if (en)
pwrap_write(PMIC_VSRAM_PROC11_CON0, 1);
else
pwrap_write(PMIC_VSRAM_PROC11_CON0, 0);
}
void wk_pmic_enable_sdn_delay(void)
{
uint32_t con;
......
......@@ -10,7 +10,11 @@
enum {
PMIC_TMA_KEY = 0x03a8,
PMIC_PWRHOLD = 0x0a08,
PMIC_PSEQ_ELR11 = 0x0a62
PMIC_PSEQ_ELR11 = 0x0a62,
PMIC_VPROC11_CON0 = 0x1388,
PMIC_VPROC11_OP_EN = 0x1390,
PMIC_VSRAM_PROC11_CON0 = 0x1b46,
PMIC_VSRAM_PROC11_OP_EN = 0x1b4e
};
enum {
......@@ -18,6 +22,8 @@ enum {
};
/* external API */
void bcpu_enable(uint32_t en);
void bcpu_sram_enable(uint32_t en);
void wk_pmic_enable_sdn_delay(void);
void pmic_power_off(void);
......
/*
* Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <lib/bakery_lock.h>
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <lib/mmio.h>
#include <spm.h>
#include <spm_pmic_wrap.h>
DEFINE_BAKERY_LOCK(spm_lock);
const char *wakeup_src_str[32] = {
[0] = "R12_PCM_TIMER",
[1] = "R12_SSPM_WDT_EVENT_B",
[2] = "R12_KP_IRQ_B",
[3] = "R12_APWDT_EVENT_B",
[4] = "R12_APXGPT1_EVENT_B",
[5] = "R12_CONN2AP_SPM_WAKEUP_B",
[6] = "R12_EINT_EVENT_B",
[7] = "R12_CONN_WDT_IRQ_B",
[8] = "R12_CCIF0_EVENT_B",
[9] = "R12_LOWBATTERY_IRQ_B",
[10] = "R12_SSPM_SPM_IRQ_B",
[11] = "R12_SCP_SPM_IRQ_B",
[12] = "R12_SCP_WDT_EVENT_B",
[13] = "R12_PCM_WDT_WAKEUP_B",
[14] = "R12_USB_CDSC_B ",
[15] = "R12_USB_POWERDWN_B",
[16] = "R12_SYS_TIMER_EVENT_B",
[17] = "R12_EINT_EVENT_SECURE_B",
[18] = "R12_CCIF1_EVENT_B",
[19] = "R12_UART0_IRQ_B",
[20] = "R12_AFE_IRQ_MCU_B",
[21] = "R12_THERM_CTRL_EVENT_B",
[22] = "R12_SYS_CIRQ_IRQ_B",
[23] = "R12_MD2AP_PEER_EVENT_B",
[24] = "R12_CSYSPWREQ_B",
[25] = "R12_MD1_WDT_B ",
[26] = "R12_CLDMA_EVENT_B",
[27] = "R12_SEJ_WDT_GPT_B",
[28] = "R12_ALL_SSPM_WAKEUP_B",
[29] = "R12_CPU_IRQ_B",
[30] = "R12_CPU_WFI_AND_B"
};
const char *spm_get_firmware_version(void)
{
return "DYNAMIC_SPM_FW_VERSION";
}
void spm_lock_init(void)
{
bakery_lock_init(&spm_lock);
}
void spm_lock_get(void)
{
bakery_lock_get(&spm_lock);
}
void spm_lock_release(void)
{
bakery_lock_release(&spm_lock);
}
void spm_set_bootaddr(unsigned long bootaddr)
{
/* initialize core4~7 boot entry address */
mmio_write_32(SW2SPM_MAILBOX_3, bootaddr);
}
void spm_set_cpu_status(int cpu)
{
if (cpu >= 0 && cpu < 4) {
mmio_write_32(ROOT_CPUTOP_ADDR, 0x10006204);
mmio_write_32(ROOT_CORE_ADDR, 0x10006208 + (cpu * 0x4));
} else if (cpu >= 4 && cpu < 8) {
mmio_write_32(ROOT_CPUTOP_ADDR, 0x10006218);
mmio_write_32(ROOT_CORE_ADDR, 0x1000621c + ((cpu - 4) * 0x4));
} else {
ERROR("%s: error cpu number %d\n", __func__, cpu);
}
}
void spm_set_power_control(const struct pwr_ctrl *pwrctrl)
{
mmio_write_32(SPM_AP_STANDBY_CON,
((pwrctrl->wfi_op & 0x1) << 0) |
((pwrctrl->mp0_cputop_idle_mask & 0x1) << 1) |
((pwrctrl->mp1_cputop_idle_mask & 0x1) << 2) |
((pwrctrl->mcusys_idle_mask & 0x1) << 4) |
((pwrctrl->mm_mask_b & 0x3) << 16) |
((pwrctrl->md_ddr_en_0_dbc_en & 0x1) << 18) |
((pwrctrl->md_ddr_en_1_dbc_en & 0x1) << 19) |
((pwrctrl->md_mask_b & 0x3) << 20) |
((pwrctrl->sspm_mask_b & 0x1) << 22) |
((pwrctrl->scp_mask_b & 0x1) << 23) |
((pwrctrl->srcclkeni_mask_b & 0x1) << 24) |
((pwrctrl->md_apsrc_1_sel & 0x1) << 25) |
((pwrctrl->md_apsrc_0_sel & 0x1) << 26) |
((pwrctrl->conn_ddr_en_dbc_en & 0x1) << 27) |
((pwrctrl->conn_mask_b & 0x1) << 28) |
((pwrctrl->conn_apsrc_sel & 0x1) << 29));
mmio_write_32(SPM_SRC_REQ,
((pwrctrl->spm_apsrc_req & 0x1) << 0) |
((pwrctrl->spm_f26m_req & 0x1) << 1) |
((pwrctrl->spm_infra_req & 0x1) << 3) |
((pwrctrl->spm_vrf18_req & 0x1) << 4) |
((pwrctrl->spm_ddren_req & 0x1) << 7) |
((pwrctrl->spm_rsv_src_req & 0x7) << 8) |
((pwrctrl->spm_ddren_2_req & 0x1) << 11) |
((pwrctrl->cpu_md_dvfs_sop_force_on & 0x1) << 16));
mmio_write_32(SPM_SRC_MASK,
((pwrctrl->csyspwreq_mask & 0x1) << 0) |
((pwrctrl->ccif0_md_event_mask_b & 0x1) << 1) |
((pwrctrl->ccif0_ap_event_mask_b & 0x1) << 2) |
((pwrctrl->ccif1_md_event_mask_b & 0x1) << 3) |
((pwrctrl->ccif1_ap_event_mask_b & 0x1) << 4) |
((pwrctrl->ccif2_md_event_mask_b & 0x1) << 5) |
((pwrctrl->ccif2_ap_event_mask_b & 0x1) << 6) |
((pwrctrl->ccif3_md_event_mask_b & 0x1) << 7) |
((pwrctrl->ccif3_ap_event_mask_b & 0x1) << 8) |
((pwrctrl->md_srcclkena_0_infra_mask_b & 0x1) << 9) |
((pwrctrl->md_srcclkena_1_infra_mask_b & 0x1) << 10) |
((pwrctrl->conn_srcclkena_infra_mask_b & 0x1) << 11) |
((pwrctrl->ufs_infra_req_mask_b & 0x1) << 12) |
((pwrctrl->srcclkeni_infra_mask_b & 0x1) << 13) |
((pwrctrl->md_apsrc_req_0_infra_mask_b & 0x1) << 14) |
((pwrctrl->md_apsrc_req_1_infra_mask_b & 0x1) << 15) |
((pwrctrl->conn_apsrcreq_infra_mask_b & 0x1) << 16) |
((pwrctrl->ufs_srcclkena_mask_b & 0x1) << 17) |
((pwrctrl->md_vrf18_req_0_mask_b & 0x1) << 18) |
((pwrctrl->md_vrf18_req_1_mask_b & 0x1) << 19) |
((pwrctrl->ufs_vrf18_req_mask_b & 0x1) << 20) |
((pwrctrl->gce_vrf18_req_mask_b & 0x1) << 21) |
((pwrctrl->conn_infra_req_mask_b & 0x1) << 22) |
((pwrctrl->gce_apsrc_req_mask_b & 0x1) << 23) |
((pwrctrl->disp0_apsrc_req_mask_b & 0x1) << 24) |
((pwrctrl->disp1_apsrc_req_mask_b & 0x1) << 25) |
((pwrctrl->mfg_req_mask_b & 0x1) << 26) |
((pwrctrl->vdec_req_mask_b & 0x1) << 27));
mmio_write_32(SPM_SRC2_MASK,
((pwrctrl->md_ddr_en_0_mask_b & 0x1) << 0) |
((pwrctrl->md_ddr_en_1_mask_b & 0x1) << 1) |
((pwrctrl->conn_ddr_en_mask_b & 0x1) << 2) |
((pwrctrl->ddren_sspm_apsrc_req_mask_b & 0x1) << 3) |
((pwrctrl->ddren_scp_apsrc_req_mask_b & 0x1) << 4) |
((pwrctrl->disp0_ddren_mask_b & 0x1) << 5) |
((pwrctrl->disp1_ddren_mask_b & 0x1) << 6) |
((pwrctrl->gce_ddren_mask_b & 0x1) << 7) |
((pwrctrl->ddren_emi_self_refresh_ch0_mask_b & 0x1)
<< 8) |
((pwrctrl->ddren_emi_self_refresh_ch1_mask_b & 0x1)
<< 9));
mmio_write_32(SPM_WAKEUP_EVENT_MASK,
((pwrctrl->spm_wakeup_event_mask & 0xffffffff) << 0));
mmio_write_32(SPM_WAKEUP_EVENT_EXT_MASK,
((pwrctrl->spm_wakeup_event_ext_mask & 0xffffffff)
<< 0));
mmio_write_32(SPM_SRC3_MASK,
((pwrctrl->md_ddr_en_2_0_mask_b & 0x1) << 0) |
((pwrctrl->md_ddr_en_2_1_mask_b & 0x1) << 1) |
((pwrctrl->conn_ddr_en_2_mask_b & 0x1) << 2) |
((pwrctrl->ddren2_sspm_apsrc_req_mask_b & 0x1) << 3) |
((pwrctrl->ddren2_scp_apsrc_req_mask_b & 0x1) << 4) |
((pwrctrl->disp0_ddren2_mask_b & 0x1) << 5) |
((pwrctrl->disp1_ddren2_mask_b & 0x1) << 6) |
((pwrctrl->gce_ddren2_mask_b & 0x1) << 7) |
((pwrctrl->ddren2_emi_self_refresh_ch0_mask_b & 0x1)
<< 8) |
((pwrctrl->ddren2_emi_self_refresh_ch1_mask_b & 0x1)
<< 9));
mmio_write_32(MP0_CPU0_WFI_EN,
((pwrctrl->mp0_cpu0_wfi_en & 0x1) << 0));
mmio_write_32(MP0_CPU1_WFI_EN,
((pwrctrl->mp0_cpu1_wfi_en & 0x1) << 0));
mmio_write_32(MP0_CPU2_WFI_EN,
((pwrctrl->mp0_cpu2_wfi_en & 0x1) << 0));
mmio_write_32(MP0_CPU3_WFI_EN,
((pwrctrl->mp0_cpu3_wfi_en & 0x1) << 0));
mmio_write_32(MP1_CPU0_WFI_EN,
((pwrctrl->mp1_cpu0_wfi_en & 0x1) << 0));
mmio_write_32(MP1_CPU1_WFI_EN,
((pwrctrl->mp1_cpu1_wfi_en & 0x1) << 0));
mmio_write_32(MP1_CPU2_WFI_EN,
((pwrctrl->mp1_cpu2_wfi_en & 0x1) << 0));
mmio_write_32(MP1_CPU3_WFI_EN,
((pwrctrl->mp1_cpu3_wfi_en & 0x1) << 0));
}
void spm_disable_pcm_timer(void)
{
mmio_clrsetbits_32(PCM_CON1, PCM_TIMER_EN_LSB, SPM_REGWR_CFG_KEY);
}
void spm_set_wakeup_event(const struct pwr_ctrl *pwrctrl)
{
uint32_t val, mask, isr;
val = pwrctrl->timer_val ? pwrctrl->timer_val : PCM_TIMER_MAX;
mmio_write_32(PCM_TIMER_VAL, val);
mmio_setbits_32(PCM_CON1, SPM_REGWR_CFG_KEY | PCM_TIMER_EN_LSB);
mask = pwrctrl->wake_src;
if (pwrctrl->csyspwreq_mask)
mask &= ~WAKE_SRC_R12_CSYSPWREQ_B;
mmio_write_32(SPM_WAKEUP_EVENT_MASK, ~mask);
isr = mmio_read_32(SPM_IRQ_MASK) & SPM_TWAM_IRQ_MASK_LSB;
mmio_write_32(SPM_IRQ_MASK, isr | ISRM_RET_IRQ_AUX);
}
void spm_set_pcm_flags(const struct pwr_ctrl *pwrctrl)
{
mmio_write_32(SPM_SW_FLAG, pwrctrl->pcm_flags);
mmio_write_32(SPM_SW_RSV_2, pwrctrl->pcm_flags1);
}
void spm_set_pcm_wdt(int en)
{
if (en) {
mmio_clrsetbits_32(PCM_CON1, PCM_WDT_WAKE_MODE_LSB,
SPM_REGWR_CFG_KEY);
if (mmio_read_32(PCM_TIMER_VAL) > PCM_TIMER_MAX)
mmio_write_32(PCM_TIMER_VAL, PCM_TIMER_MAX);
mmio_write_32(PCM_WDT_VAL,
mmio_read_32(PCM_TIMER_VAL) + PCM_WDT_TIMEOUT);
mmio_setbits_32(PCM_CON1, SPM_REGWR_CFG_KEY | PCM_WDT_EN_LSB);
} else {
mmio_clrsetbits_32(PCM_CON1, PCM_WDT_EN_LSB,
SPM_REGWR_CFG_KEY);
}
}
void spm_send_cpu_wakeup_event(void)
{
mmio_write_32(PCM_REG_DATA_INI, 0);
mmio_write_32(SPM_CPU_WAKEUP_EVENT, 1);
}
void spm_get_wakeup_status(struct wake_status *wakesta)
{
wakesta->assert_pc = mmio_read_32(PCM_REG_DATA_INI);
wakesta->r12 = mmio_read_32(SPM_SW_RSV_0);
wakesta->r12_ext = mmio_read_32(PCM_REG12_EXT_DATA);
wakesta->raw_sta = mmio_read_32(SPM_WAKEUP_STA);
wakesta->raw_ext_sta = mmio_read_32(SPM_WAKEUP_EXT_STA);
wakesta->wake_misc = mmio_read_32(SPM_BSI_D0_SR);
wakesta->timer_out = mmio_read_32(SPM_BSI_D1_SR);
wakesta->r13 = mmio_read_32(PCM_REG13_DATA);
wakesta->idle_sta = mmio_read_32(SUBSYS_IDLE_STA);
wakesta->req_sta = mmio_read_32(SRC_REQ_STA);
wakesta->sw_flag = mmio_read_32(SPM_SW_FLAG);
wakesta->sw_flag1 = mmio_read_32(SPM_SW_RSV_2);
wakesta->r15 = mmio_read_32(PCM_REG15_DATA);
wakesta->debug_flag = mmio_read_32(SPM_SW_DEBUG);
wakesta->debug_flag1 = mmio_read_32(WDT_LATCH_SPARE0_FIX);
wakesta->event_reg = mmio_read_32(SPM_BSI_D2_SR);
wakesta->isr = mmio_read_32(SPM_IRQ_STA);
}
void spm_clean_after_wakeup(void)
{
mmio_write_32(SPM_SW_RSV_0,
mmio_read_32(SPM_WAKEUP_STA) |
mmio_read_32(SPM_SW_RSV_0));
mmio_write_32(SPM_CPU_WAKEUP_EVENT, 0);
mmio_write_32(SPM_WAKEUP_EVENT_MASK, ~0);
mmio_setbits_32(SPM_IRQ_MASK, ISRM_ALL_EXC_TWAM);
mmio_write_32(SPM_IRQ_STA, ISRC_ALL_EXC_TWAM);
mmio_write_32(SPM_SWINT_CLR, PCM_SW_INT_ALL);
}
void spm_output_wake_reason(struct wake_status *wakesta, const char *scenario)
{
uint32_t i;
if (wakesta->assert_pc != 0) {
INFO("%s: PCM ASSERT AT %u, ULPOSC_CON = 0x%x\n",
scenario, wakesta->assert_pc, mmio_read_32(ULPOSC_CON));
goto spm_debug_flags;
}
for (i = 0; i <= 31; i++) {
if (wakesta->r12 & (1U << i)) {
INFO("%s: wake up by %s, timer_out = %u\n",
scenario, wakeup_src_str[i], wakesta->timer_out);
break;
}
}
spm_debug_flags:
INFO("r15 = 0x%x, r13 = 0x%x, debug_flag = 0x%x 0x%x\n",
wakesta->r15, wakesta->r13, wakesta->debug_flag,
wakesta->debug_flag1);
INFO("sw_flag = 0x%x 0x%x, r12 = 0x%x, r12_ext = 0x%x\n",
wakesta->sw_flag, wakesta->sw_flag1, wakesta->r12,
wakesta->r12_ext);
INFO("idle_sta = 0x%x, req_sta = 0x%x, event_reg = 0x%x\n",
wakesta->idle_sta, wakesta->req_sta, wakesta->event_reg);
INFO("isr = 0x%x, raw_sta = 0x%x, raw_ext_sta = 0x%x\n",
wakesta->isr, wakesta->raw_sta, wakesta->raw_ext_sta);
INFO("wake_misc = 0x%x\n", wakesta->wake_misc);
}
void spm_boot_init(void)
{
NOTICE("%s() start\n", __func__);
spm_lock_init();
mt_spm_pmic_wrap_set_phase(PMIC_WRAP_PHASE_ALLINONE);
NOTICE("%s() end\n", __func__);
}
/*
* Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <common/debug.h>
#include <lib/mmio.h>
#include <platform_def.h>
#include <spm.h>
#include <spm_pmic_wrap.h>
#include <lib/libc/string.h>
#define SLEEP_REG_MD_SPM_DVFS_CMD20 (SLEEP_REG_MD_BASE + 0x010)
#define SLEEP_REG_MD_SPM_DVFS_CMD21 (SLEEP_REG_MD_BASE + 0x014)
#define SLEEP_REG_MD_SPM_DVFS_CMD22 (SLEEP_REG_MD_BASE + 0x018)
#define SLEEP_REG_MD_SPM_DVFS_CMD23 (SLEEP_REG_MD_BASE + 0x01C)
/* PMIC_WRAP -> PMIC MT6358 */
#define VCORE_BASE_UV 50000
#define VOLT_TO_PMIC_VAL(volt) (((volt) - VCORE_BASE_UV + 625 - 1) / 625)
#define PMIC_VAL_TO_VOLT(pmic) (((pmic) * 625) + VCORE_BASE_UV)
#define DEFAULT_VOLT_VSRAM (100000)
#define DEFAULT_VOLT_VCORE (100000)
#define NR_PMIC_WRAP_CMD (NR_IDX_ALL)
#define MAX_RETRY_COUNT (100)
#define SPM_DATA_SHIFT (16)
#define BUCK_VCORE_ELR0 0x14AA
#define BUCK_VPROC12_CON0 0x1408
#define BUCK_VPROC11_CON0 0x1388
#define TOP_SPI_CON0 0x044C
#define LDO_VSRAM_PROC12_CON0 0x1B88
#define LDO_VSRAM_PROC11_CON0 0x1B46
#define BUCK_VMODEM_ELR0 0x15A6
struct pmic_wrap_cmd {
unsigned long cmd_addr;
unsigned long cmd_wdata;
};
struct pmic_wrap_setting {
enum pmic_wrap_phase_id phase;
struct pmic_wrap_cmd addr[NR_PMIC_WRAP_CMD];
struct {
struct {
unsigned long cmd_addr;
unsigned long cmd_wdata;
} _[NR_PMIC_WRAP_CMD];
const int nr_idx;
} set[NR_PMIC_WRAP_PHASE];
};
static struct pmic_wrap_setting pw = {
.phase = NR_PMIC_WRAP_PHASE,
.addr = {{0, 0} },
.set[PMIC_WRAP_PHASE_ALLINONE] = {
._[CMD_0] = {BUCK_VCORE_ELR0, VOLT_TO_PMIC_VAL(70000),},
._[CMD_1] = {BUCK_VCORE_ELR0, VOLT_TO_PMIC_VAL(80000),},
._[CMD_2] = {BUCK_VPROC12_CON0, 0x3,},
._[CMD_3] = {BUCK_VPROC12_CON0, 0x1,},
._[CMD_4] = {BUCK_VPROC11_CON0, 0x3,},
._[CMD_5] = {BUCK_VPROC11_CON0, 0x1,},
._[CMD_6] = {TOP_SPI_CON0, 0x1,},
._[CMD_7] = {TOP_SPI_CON0, 0x0,},
._[CMD_8] = {BUCK_VPROC12_CON0, 0x0,},
._[CMD_9] = {BUCK_VPROC12_CON0, 0x1,},
._[CMD_10] = {BUCK_VPROC11_CON0, 0x0,},
._[CMD_11] = {BUCK_VPROC11_CON0, 0x1,},
._[CMD_12] = {LDO_VSRAM_PROC12_CON0, 0x0,},
._[CMD_13] = {LDO_VSRAM_PROC12_CON0, 0x1,},
._[CMD_14] = {LDO_VSRAM_PROC11_CON0, 0x0,},
._[CMD_15] = {LDO_VSRAM_PROC11_CON0, 0x1,},
._[CMD_20] = {BUCK_VMODEM_ELR0, VOLT_TO_PMIC_VAL(55000),},
._[CMD_21] = {BUCK_VCORE_ELR0, VOLT_TO_PMIC_VAL(60000),},
._[CMD_22] = {LDO_VSRAM_PROC11_CON0, 0x3,},
._[CMD_23] = {LDO_VSRAM_PROC11_CON0, 0x1,},
.nr_idx = NR_IDX_ALL
}
};
void _mt_spm_pmic_table_init(void)
{
struct pmic_wrap_cmd pwrap_cmd_default[NR_PMIC_WRAP_CMD] = {
{(uint32_t)SPM_DVFS_CMD0, (uint32_t)SPM_DVFS_CMD0,},
{(uint32_t)SPM_DVFS_CMD1, (uint32_t)SPM_DVFS_CMD1,},
{(uint32_t)SPM_DVFS_CMD2, (uint32_t)SPM_DVFS_CMD2,},
{(uint32_t)SPM_DVFS_CMD3, (uint32_t)SPM_DVFS_CMD3,},
{(uint32_t)SPM_DVFS_CMD4, (uint32_t)SPM_DVFS_CMD4,},
{(uint32_t)SPM_DVFS_CMD5, (uint32_t)SPM_DVFS_CMD5,},
{(uint32_t)SPM_DVFS_CMD6, (uint32_t)SPM_DVFS_CMD6,},
{(uint32_t)SPM_DVFS_CMD7, (uint32_t)SPM_DVFS_CMD7,},
{(uint32_t)SPM_DVFS_CMD8, (uint32_t)SPM_DVFS_CMD8,},
{(uint32_t)SPM_DVFS_CMD9, (uint32_t)SPM_DVFS_CMD9,},
{(uint32_t)SPM_DVFS_CMD10, (uint32_t)SPM_DVFS_CMD10,},
{(uint32_t)SPM_DVFS_CMD11, (uint32_t)SPM_DVFS_CMD11,},
{(uint32_t)SPM_DVFS_CMD12, (uint32_t)SPM_DVFS_CMD12,},
{(uint32_t)SPM_DVFS_CMD13, (uint32_t)SPM_DVFS_CMD13,},
{(uint32_t)SPM_DVFS_CMD14, (uint32_t)SPM_DVFS_CMD14,},
{(uint32_t)SPM_DVFS_CMD15, (uint32_t)SPM_DVFS_CMD15,},
{(uint32_t)SLEEP_REG_MD_SPM_DVFS_CMD20,
(uint32_t)SLEEP_REG_MD_SPM_DVFS_CMD20,},
{(uint32_t)SLEEP_REG_MD_SPM_DVFS_CMD21,
(uint32_t)SLEEP_REG_MD_SPM_DVFS_CMD21,},
{(uint32_t)SLEEP_REG_MD_SPM_DVFS_CMD22,
(uint32_t)SLEEP_REG_MD_SPM_DVFS_CMD22,},
{(uint32_t)SLEEP_REG_MD_SPM_DVFS_CMD23,
(uint32_t)SLEEP_REG_MD_SPM_DVFS_CMD23,}
};
memcpy(pw.addr, pwrap_cmd_default, sizeof(pwrap_cmd_default));
}
void mt_spm_pmic_wrap_set_phase(enum pmic_wrap_phase_id phase)
{
uint32_t idx, addr, data;
if (phase >= NR_PMIC_WRAP_PHASE)
return;
if (pw.phase == phase)
return;
if (pw.addr[0].cmd_addr == 0)
_mt_spm_pmic_table_init();
pw.phase = phase;
mmio_write_32(POWERON_CONFIG_EN, SPM_REGWR_CFG_KEY |
BCLK_CG_EN_LSB | MD_BCLK_CG_EN_LSB);
for (idx = 0; idx < pw.set[phase].nr_idx; idx++) {
addr = pw.set[phase]._[idx].cmd_addr << SPM_DATA_SHIFT;
data = pw.set[phase]._[idx].cmd_wdata;
mmio_write_32(pw.addr[idx].cmd_addr, addr | data);
}
}
void mt_spm_pmic_wrap_set_cmd(enum pmic_wrap_phase_id phase, uint32_t idx,
uint32_t cmd_wdata)
{
uint32_t addr;
if (phase >= NR_PMIC_WRAP_PHASE)
return;
if (idx >= pw.set[phase].nr_idx)
return;
pw.set[phase]._[idx].cmd_wdata = cmd_wdata;
mmio_write_32(POWERON_CONFIG_EN, SPM_REGWR_CFG_KEY |
BCLK_CG_EN_LSB | MD_BCLK_CG_EN_LSB);
if (pw.phase == phase) {
addr = pw.set[phase]._[idx].cmd_addr << SPM_DATA_SHIFT;
mmio_write_32(pw.addr[idx].cmd_addr, addr | cmd_wdata);
}
}
uint64_t mt_spm_pmic_wrap_get_cmd(enum pmic_wrap_phase_id phase, uint32_t idx)
{
if (phase >= NR_PMIC_WRAP_PHASE)
return 0;
if (idx >= pw.set[phase].nr_idx)
return 0;
return pw.set[phase]._[idx].cmd_wdata;
}
/*
* Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/****************************************************************
* Auto generated by DE, please DO NOT modify this file directly.
*****************************************************************/
#ifndef SPM_PMIC_WRAP__H
#define SPM_PMIC_WRAP__H
enum pmic_wrap_phase_id {
PMIC_WRAP_PHASE_ALLINONE,
NR_PMIC_WRAP_PHASE
};
/* IDX mapping */
enum {
CMD_0, /* 0x0 *//* PMIC_WRAP_PHASE_ALLINONE */
CMD_1, /* 0x1 */
CMD_2, /* 0x2 */
CMD_3, /* 0x3 */
CMD_4, /* 0x4 */
CMD_5, /* 0x5 */
CMD_6, /* 0x6 */
CMD_7, /* 0x7 */
CMD_8, /* 0x8 */
CMD_9, /* 0x9 */
CMD_10, /* 0xA */
CMD_11, /* 0xB */
CMD_12, /* 0xC */
CMD_13, /* 0xD */
CMD_14, /* 0xE */
CMD_15, /* 0xF */
CMD_20, /* 0x14 */
CMD_21, /* 0x15 */
CMD_22, /* 0x16 */
CMD_23, /* 0x17 */
NR_IDX_ALL
};
/* APIs */
void mt_spm_pmic_wrap_set_phase(enum pmic_wrap_phase_id phase);
void mt_spm_pmic_wrap_set_cmd(enum pmic_wrap_phase_id phase,
uint32_t idx, uint32_t cmd_wdata);
uint64_t mt_spm_pmic_wrap_get_cmd(enum pmic_wrap_phase_id phase, uint32_t idx);
#endif /* SPM_PMIC_WRAP__H */
/*
* Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <mt_gic_v3.h>
#include <lib/mmio.h>
#include <platform_def.h>
#include <pmic.h>
#include <spm.h>
#include <uart.h>
#define SPM_SYSCLK_SETTLE 99
#define WAKE_SRC_FOR_SUSPEND \
(WAKE_SRC_R12_PCM_TIMER | \
WAKE_SRC_R12_SSPM_WDT_EVENT_B | \
WAKE_SRC_R12_KP_IRQ_B | \
WAKE_SRC_R12_CONN2AP_SPM_WAKEUP_B | \
WAKE_SRC_R12_EINT_EVENT_B | \
WAKE_SRC_R12_CONN_WDT_IRQ_B | \
WAKE_SRC_R12_CCIF0_EVENT_B | \
WAKE_SRC_R12_SSPM_SPM_IRQ_B | \
WAKE_SRC_R12_SCP_SPM_IRQ_B | \
WAKE_SRC_R12_SCP_WDT_EVENT_B | \
WAKE_SRC_R12_USB_CDSC_B | \
WAKE_SRC_R12_USB_POWERDWN_B | \
WAKE_SRC_R12_SYS_TIMER_EVENT_B | \
WAKE_SRC_R12_EINT_EVENT_SECURE_B | \
WAKE_SRC_R12_CCIF1_EVENT_B | \
WAKE_SRC_R12_MD2AP_PEER_EVENT_B | \
WAKE_SRC_R12_MD1_WDT_B | \
WAKE_SRC_R12_CLDMA_EVENT_B | \
WAKE_SRC_R12_SEJ_WDT_GPT_B)
#define SLP_PCM_FLAGS \
(SPM_FLAG_DIS_VCORE_DVS | SPM_FLAG_DIS_VCORE_DFS | \
SPM_FLAG_DIS_ATF_ABORT | SPM_FLAG_DISABLE_MMSYS_DVFS | \
SPM_FLAG_DIS_INFRA_PDN | SPM_FLAG_SUSPEND_OPTION)
#define SLP_PCM_FLAGS1 \
(SPM_FLAG1_DISABLE_MCDSR)
static const struct pwr_ctrl suspend_ctrl = {
.wake_src = WAKE_SRC_FOR_SUSPEND,
.pcm_flags = SLP_PCM_FLAGS,
.pcm_flags1 = SLP_PCM_FLAGS1,
/* SPM_AP_STANDBY_CON */
.wfi_op = 0x1,
.mp0_cputop_idle_mask = 0,
.mp1_cputop_idle_mask = 0,
.mcusys_idle_mask = 0,
.mm_mask_b = 0,
.md_ddr_en_0_dbc_en = 0x1,
.md_ddr_en_1_dbc_en = 0,
.md_mask_b = 0x1,
.sspm_mask_b = 0x1,
.scp_mask_b = 0x1,
.srcclkeni_mask_b = 0x1,
.md_apsrc_1_sel = 0,
.md_apsrc_0_sel = 0,
.conn_ddr_en_dbc_en = 0x1,
.conn_mask_b = 0x1,
.conn_apsrc_sel = 0,
/* SPM_SRC_REQ */
.spm_apsrc_req = 0,
.spm_f26m_req = 0,
.spm_infra_req = 0,
.spm_vrf18_req = 0,
.spm_ddren_req = 0,
.spm_rsv_src_req = 0,
.spm_ddren_2_req = 0,
.cpu_md_dvfs_sop_force_on = 0,
/* SPM_SRC_MASK */
.csyspwreq_mask = 0x1,
.ccif0_md_event_mask_b = 0x1,
.ccif0_ap_event_mask_b = 0x1,
.ccif1_md_event_mask_b = 0x1,
.ccif1_ap_event_mask_b = 0x1,
.ccif2_md_event_mask_b = 0x1,
.ccif2_ap_event_mask_b = 0x1,
.ccif3_md_event_mask_b = 0x1,
.ccif3_ap_event_mask_b = 0x1,
.md_srcclkena_0_infra_mask_b = 0x1,
.md_srcclkena_1_infra_mask_b = 0,
.conn_srcclkena_infra_mask_b = 0,
.ufs_infra_req_mask_b = 0,
.srcclkeni_infra_mask_b = 0,
.md_apsrc_req_0_infra_mask_b = 0x1,
.md_apsrc_req_1_infra_mask_b = 0x1,
.conn_apsrcreq_infra_mask_b = 0x1,
.ufs_srcclkena_mask_b = 0,
.md_vrf18_req_0_mask_b = 0,
.md_vrf18_req_1_mask_b = 0,
.ufs_vrf18_req_mask_b = 0,
.gce_vrf18_req_mask_b = 0,
.conn_infra_req_mask_b = 0x1,
.gce_apsrc_req_mask_b = 0,
.disp0_apsrc_req_mask_b = 0,
.disp1_apsrc_req_mask_b = 0,
.mfg_req_mask_b = 0,
.vdec_req_mask_b = 0,
/* SPM_SRC2_MASK */
.md_ddr_en_0_mask_b = 0x1,
.md_ddr_en_1_mask_b = 0,
.conn_ddr_en_mask_b = 0x1,
.ddren_sspm_apsrc_req_mask_b = 0x1,
.ddren_scp_apsrc_req_mask_b = 0x1,
.disp0_ddren_mask_b = 0x1,
.disp1_ddren_mask_b = 0x1,
.gce_ddren_mask_b = 0x1,
.ddren_emi_self_refresh_ch0_mask_b = 0,
.ddren_emi_self_refresh_ch1_mask_b = 0,
/* SPM_WAKEUP_EVENT_MASK */
.spm_wakeup_event_mask = 0xF1782218,
/* SPM_WAKEUP_EVENT_EXT_MASK */
.spm_wakeup_event_ext_mask = 0xFFFFFFFF,
/* SPM_SRC3_MASK */
.md_ddr_en_2_0_mask_b = 0x1,
.md_ddr_en_2_1_mask_b = 0,
.conn_ddr_en_2_mask_b = 0x1,
.ddren2_sspm_apsrc_req_mask_b = 0x1,
.ddren2_scp_apsrc_req_mask_b = 0x1,
.disp0_ddren2_mask_b = 0,
.disp1_ddren2_mask_b = 0,
.gce_ddren2_mask_b = 0,
.ddren2_emi_self_refresh_ch0_mask_b = 0,
.ddren2_emi_self_refresh_ch1_mask_b = 0,
.mp0_cpu0_wfi_en = 0x1,
.mp0_cpu1_wfi_en = 0x1,
.mp0_cpu2_wfi_en = 0x1,
.mp0_cpu3_wfi_en = 0x1,
.mp1_cpu0_wfi_en = 0x1,
.mp1_cpu1_wfi_en = 0x1,
.mp1_cpu2_wfi_en = 0x1,
.mp1_cpu3_wfi_en = 0x1
};
static uint32_t spm_set_sysclk_settle(void)
{
mmio_write_32(SPM_CLK_SETTLE, SPM_SYSCLK_SETTLE);
return mmio_read_32(SPM_CLK_SETTLE);
}
void go_to_sleep_before_wfi(void)
{
int cpu = MPIDR_AFFLVL0_VAL(read_mpidr());
uint32_t settle;
settle = spm_set_sysclk_settle();
spm_set_cpu_status(cpu);
spm_set_power_control(&suspend_ctrl);
spm_set_wakeup_event(&suspend_ctrl);
spm_set_pcm_flags(&suspend_ctrl);
spm_send_cpu_wakeup_event();
spm_set_pcm_wdt(0);
spm_disable_pcm_timer();
if (is_infra_pdn(suspend_ctrl.pcm_flags))
mt_uart_save();
if (!mt_console_uart_cg_status())
console_switch_state(CONSOLE_FLAG_BOOT);
INFO("cpu%d: \"%s\", wakesrc = 0x%x, pcm_con1 = 0x%x\n",
cpu, spm_get_firmware_version(), suspend_ctrl.wake_src,
mmio_read_32(PCM_CON1));
INFO("settle = %u, sec = %u, sw_flag = 0x%x 0x%x, src_req = 0x%x\n",
settle, mmio_read_32(PCM_TIMER_VAL) / 32768,
suspend_ctrl.pcm_flags, suspend_ctrl.pcm_flags1,
mmio_read_32(SPM_SRC_REQ));
if (!mt_console_uart_cg_status())
console_switch_state(CONSOLE_FLAG_RUNTIME);
}
static void go_to_sleep_after_wfi(void)
{
struct wake_status spm_wakesta;
if (is_infra_pdn(suspend_ctrl.pcm_flags))
mt_uart_restore();
spm_set_pcm_wdt(0);
spm_get_wakeup_status(&spm_wakesta);
spm_clean_after_wakeup();
if (!mt_console_uart_cg_status())
console_switch_state(CONSOLE_FLAG_BOOT);
spm_output_wake_reason(&spm_wakesta, "suspend");
if (!mt_console_uart_cg_status())
console_switch_state(CONSOLE_FLAG_RUNTIME);
}
static void spm_enable_armpll_l(void)
{
/* power on */
mmio_setbits_32(ARMPLL_L_PWR_CON0, 0x1);
/* clear isolation */
mmio_clrbits_32(ARMPLL_L_PWR_CON0, 0x2);
/* enable pll */
mmio_setbits_32(ARMPLL_L_CON0, 0x1);
/* Add 20us delay for turning on PLL */
udelay(20);
}
static void spm_disable_armpll_l(void)
{
/* disable pll */
mmio_clrbits_32(ARMPLL_L_CON0, 0x1);
/* isolation */
mmio_setbits_32(ARMPLL_L_PWR_CON0, 0x2);
/* power off */
mmio_clrbits_32(ARMPLL_L_PWR_CON0, 0x1);
}
void spm_system_suspend(void)
{
spm_disable_armpll_l();
bcpu_enable(0);
bcpu_sram_enable(0);
spm_lock_get();
go_to_sleep_before_wfi();
spm_lock_release();
}
void spm_system_suspend_finish(void)
{
spm_lock_get();
go_to_sleep_after_wfi();
spm_lock_release();
spm_enable_armpll_l();
bcpu_sram_enable(1);
bcpu_enable(1);
}
/*
* Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __SPM_SUSPEND_H__
#define __SPM_SUSPEND_H__
void spm_system_suspend(void);
void spm_system_suspend_finish(void);
#endif /* __SPM_SUSPEND_H__*/
......@@ -136,8 +136,7 @@ static const struct per_cpu_reg SPM_CLUSTER_PWR[] = {
/*
* MCU configuration registers
*/
#define MCUCFG_MP0_AXI_CONFIG ((uintptr_t)&mt8183_mcucfg->mp0_axi_config)
#define MCUCFG_MP1_AXI_CONFIG ((uintptr_t)&mt8183_mcucfg->mp1_axi_config)
/* bit-fields of MCUCFG_MP?_AXI_CONFIG */
#define MCUCFG_AXI_CONFIG_BROADCASTINNER (1 << 0)
#define MCUCFG_AXI_CONFIG_BROADCASTOUTER (1 << 1)
......@@ -146,11 +145,6 @@ static const struct per_cpu_reg SPM_CLUSTER_PWR[] = {
#define MCUCFG_AXI_CONFIG_ACINACTM (1 << 4)
#define MCUCFG_AXI_CONFIG_AINACTS (1 << 5)
/* per_cpu registers for MCUCFG_MP?_AXI_CONFIG */
static const struct per_cpu_reg MCUCFG_SCUCTRL[] = {
[0] = { .cluster_addr = MCUCFG_MP0_AXI_CONFIG },
[1] = { .cluster_addr = MCUCFG_MP1_AXI_CONFIG },
};
#define MCUCFG_MP0_MISC_CONFIG2 ((uintptr_t)&mt8183_mcucfg->mp0_misc_config[2])
#define MCUCFG_MP0_MISC_CONFIG3 ((uintptr_t)&mt8183_mcucfg->mp0_misc_config[3])
......
/*
* Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <errno.h>
#include <lib/mmio.h>
#include <sspm.h>
static void memcpy_to_sspm(uint32_t dst, uint32_t *src, uint32_t len)
{
while (len--) {
mmio_write_32(dst, *src);
dst += sizeof(uint32_t);
src++;
}
}
static void memcpy_from_sspm(uint32_t *dst, uint32_t src, uint32_t len)
{
while (len--) {
*dst = mmio_read_32(src);
dst++;
src += sizeof(uint32_t);
}
}
int sspm_mbox_read(uint32_t slot, uint32_t *data, uint32_t len)
{
if (slot >= 32) {
ERROR("%s:slot = %d\n", __func__, slot);
return -EINVAL;
}
if (data)
memcpy_from_sspm(data,
MBOX3_BASE + slot * 4,
len);
return 0;
}
int sspm_mbox_write(uint32_t slot, uint32_t *data, uint32_t len)
{
if (slot >= 32) {
ERROR("%s:slot = %d\n", __func__, slot);
return -EINVAL;
}
if (data)
memcpy_to_sspm(MBOX3_BASE + slot * 4,
data,
len);
return 0;
}
static int sspm_ipi_check_ack(uint32_t id)
{
int ret = 0;
if (id == IPI_ID_PLATFORM) {
if ((mmio_read_32(MBOX0_BASE + MBOX_IN_IRQ_OFS) & 0x1) == 0x1)
ret = -EINPROGRESS;
} else if (id == IPI_ID_SUSPEND) {
if ((mmio_read_32(MBOX1_BASE + MBOX_IN_IRQ_OFS) & 0x2) == 0x2)
ret = -EINPROGRESS;
} else {
ERROR("%s: id = %d\n", __func__, id);
ret = -EINVAL;
}
return ret;
}
int sspm_ipi_send_non_blocking(uint32_t id, uint32_t *data)
{
int ret = 0;
ret = sspm_ipi_check_ack(id);
if (ret)
return ret;
if (id == IPI_ID_PLATFORM) {
memcpy_to_sspm(MBOX0_BASE + PINR_OFFSET_PLATFORM * 4,
data,
PINR_SIZE_PLATFORM);
dsb();
mmio_write_32(MBOX0_BASE + MBOX_OUT_IRQ_OFS, 0x1);
} else if (id == IPI_ID_SUSPEND) {
memcpy_to_sspm(MBOX1_BASE + PINR_OFFSET_SUSPEND * 4,
data,
PINR_SIZE_SUSPEND);
dsb();
mmio_write_32(MBOX1_BASE + MBOX_OUT_IRQ_OFS,
0x2);
}
return 0;
}
int sspm_ipi_recv_non_blocking(uint32_t id, uint32_t *data, uint32_t len)
{
int ret = 0;
ret = sspm_ipi_check_ack(id);
if (ret == -EINPROGRESS) {
if (id == IPI_ID_PLATFORM) {
memcpy_from_sspm(data,
MBOX0_BASE + PINR_OFFSET_PLATFORM * 4,
len);
dsb();
/* clear interrupt bit*/
mmio_write_32(MBOX0_BASE + MBOX_IN_IRQ_OFS,
0x1);
ret = 0;
} else if (id == IPI_ID_SUSPEND) {
memcpy_from_sspm(data,
MBOX1_BASE + PINR_OFFSET_SUSPEND * 4,
len);
dsb();
/* clear interrupt bit*/
mmio_write_32(MBOX1_BASE + MBOX_IN_IRQ_OFS,
0x2);
ret = 0;
}
} else if (ret == 0) {
ret = -EBUSY;
}
return ret;
}
int sspm_alive_show(void)
{
uint32_t ipi_data, count;
int ret = 0;
count = 5;
ipi_data = 0xdead;
if (sspm_ipi_send_non_blocking(IPI_ID_PLATFORM, &ipi_data) != 0) {
ERROR("sspm init send fail! ret=%d\n", ret);
return -1;
}
while (sspm_ipi_recv_non_blocking(IPI_ID_PLATFORM,
&ipi_data,
sizeof(ipi_data))
&& count) {
mdelay(100);
count--;
}
return (ipi_data == 1) ? 0 : -1;
}
/*
* Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __SSPM_H__
#define __SSPM_H__
/* These should sync with sspm.bin */
#define IPI_ID_PLATFORM 0
#define IPI_ID_SUSPEND 6
#define PINR_OFFSET_PLATFORM 0
#define PINR_SIZE_PLATFORM 3
#define PINR_OFFSET_SUSPEND 2
#define PINR_SIZE_SUSPEND 8
#define MBOX0_BASE 0x10450000
#define MBOX1_BASE 0x10460000
#define MBOX3_BASE 0x10480000
#define MBOX_OUT_IRQ_OFS 0x1000
#define MBOX_IN_IRQ_OFS 0x1004
#define SHAREMBOX_OFFSET_MCDI 0
#define SHAREMBOX_SIZE_MCDI 20
#define SHAREMBOX_OFFSET_SUSPEND 26
#define SHAREMBOX_SIZE_SUSPEND 6
int sspm_mbox_read(uint32_t slot, uint32_t *data, uint32_t len);
int sspm_mbox_write(uint32_t slot, uint32_t *data, uint32_t len);
int sspm_ipi_send_non_blocking(uint32_t id, uint32_t *data);
int sspm_ipi_recv_non_blocking(uint32_t slot, uint32_t *data, uint32_t len);
int sspm_alive_show(void);
#endif /* __SSPM_H__ */
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment