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
This commit is contained in:
Sandrine Bailleux 2019-09-18 14:51:13 +00:00 committed by TrustedFirmware Code Review
commit 3ea2cc00fc
29 changed files with 4992 additions and 2039 deletions

View File

@ -1,165 +0,0 @@
/*
* 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);
}

View File

@ -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 */

View File

@ -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);

View File

@ -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 */

View File

@ -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 \

View File

@ -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();
}
/*******************************************************************************

View File

@ -0,0 +1,259 @@
/*
* 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 */
}

View File

@ -0,0 +1,34 @@
/*
* 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__ */

View File

@ -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;

View File

@ -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);

View File

@ -0,0 +1,328 @@
/*
* 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__);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,170 @@
/*
* 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;
}

View File

@ -0,0 +1,50 @@
/*
* 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 */

View File

@ -0,0 +1,255 @@
/*
* 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);
}

View File

@ -0,0 +1,13 @@
/*
* 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__*/

View File

@ -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])

View File

@ -0,0 +1,159 @@
/*
* 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;
}

View File

@ -0,0 +1,32 @@
/*
* 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__ */

View File

@ -0,0 +1,111 @@
/*
* Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <lib/mmio.h>
#include <uart.h>
static struct mt_uart uart_save_addr[DRV_SUPPORT_UART_PORTS];
static const unsigned int uart_base_addr[DRV_SUPPORT_UART_PORTS] = {
UART0_BASE,
UART1_BASE
};
void mt_uart_restore(void)
{
int uart_idx = UART_PORT0;
struct mt_uart *uart;
unsigned long base;
/* Must NOT print any debug log before UART restore */
for (uart_idx = UART_PORT0; uart_idx < HW_SUPPORT_UART_PORTS;
uart_idx++) {
uart = &uart_save_addr[uart_idx];
base = uart->base;
mmio_write_32(UART_LCR(base), UART_LCR_MODE_B);
mmio_write_32(UART_EFR(base), uart->registers.efr);
mmio_write_32(UART_LCR(base), uart->registers.lcr);
mmio_write_32(UART_FCR(base), uart->registers.fcr);
/* baudrate */
mmio_write_32(UART_HIGHSPEED(base), uart->registers.highspeed);
mmio_write_32(UART_FRACDIV_L(base), uart->registers.fracdiv_l);
mmio_write_32(UART_FRACDIV_M(base), uart->registers.fracdiv_m);
mmio_write_32(UART_LCR(base),
uart->registers.lcr | UART_LCR_DLAB);
mmio_write_32(UART_DLL(base), uart->registers.dll);
mmio_write_32(UART_DLH(base), uart->registers.dlh);
mmio_write_32(UART_LCR(base), uart->registers.lcr);
mmio_write_32(UART_SAMPLE_COUNT(base),
uart->registers.sample_count);
mmio_write_32(UART_SAMPLE_POINT(base),
uart->registers.sample_point);
mmio_write_32(UART_GUARD(base), uart->registers.guard);
/* flow control */
mmio_write_32(UART_ESCAPE_EN(base), uart->registers.escape_en);
mmio_write_32(UART_MCR(base), uart->registers.mcr);
mmio_write_32(UART_IER(base), uart->registers.ier);
mmio_write_32(UART_SCR(base), uart->registers.scr);
}
}
void mt_uart_save(void)
{
int uart_idx = UART_PORT0;
struct mt_uart *uart;
unsigned long base;
for (uart_idx = UART_PORT0; uart_idx < HW_SUPPORT_UART_PORTS;
uart_idx++) {
uart_save_addr[uart_idx].base = uart_base_addr[uart_idx];
base = uart_base_addr[uart_idx];
uart = &uart_save_addr[uart_idx];
uart->registers.lcr = mmio_read_32(UART_LCR(base));
mmio_write_32(UART_LCR(base), UART_LCR_MODE_B);
uart->registers.efr = mmio_read_32(UART_EFR(base));
mmio_write_32(UART_LCR(base), uart->registers.lcr);
uart->registers.fcr = mmio_read_32(UART_FCR_RD(base));
/* baudrate */
uart->registers.highspeed = mmio_read_32(UART_HIGHSPEED(base));
uart->registers.fracdiv_l = mmio_read_32(UART_FRACDIV_L(base));
uart->registers.fracdiv_m = mmio_read_32(UART_FRACDIV_M(base));
mmio_write_32(UART_LCR(base),
uart->registers.lcr | UART_LCR_DLAB);
uart->registers.dll = mmio_read_32(UART_DLL(base));
uart->registers.dlh = mmio_read_32(UART_DLH(base));
mmio_write_32(UART_LCR(base), uart->registers.lcr);
uart->registers.sample_count = mmio_read_32(
UART_SAMPLE_COUNT(base));
uart->registers.sample_point = mmio_read_32(
UART_SAMPLE_POINT(base));
uart->registers.guard = mmio_read_32(UART_GUARD(base));
/* flow control */
uart->registers.escape_en = mmio_read_32(UART_ESCAPE_EN(base));
uart->registers.mcr = mmio_read_32(UART_MCR(base));
uart->registers.ier = mmio_read_32(UART_IER(base));
uart->registers.scr = mmio_read_32(UART_SCR(base));
}
}
void mt_console_uart_cg(int on)
{
if (on)
mmio_write_32(UART_CLOCK_GATE_CLR, UART0_CLOCK_GATE_BIT);
else
mmio_write_32(UART_CLOCK_GATE_SET, UART0_CLOCK_GATE_BIT);
}
int mt_console_uart_cg_status(void)
{
return mmio_read_32(UART_CLOCK_GATE_STA) & UART0_CLOCK_GATE_BIT;
}

View File

@ -0,0 +1,100 @@
/*
* Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __UART_H__
#define __UART_H__
#include <platform_def.h>
/* UART HW information */
#define HW_SUPPORT_UART_PORTS 2
#define DRV_SUPPORT_UART_PORTS 2
/* console UART clock cg */
#define UART_CLOCK_GATE_SET (INFRACFG_AO_BASE + 0x80)
#define UART_CLOCK_GATE_CLR (INFRACFG_AO_BASE + 0x84)
#define UART_CLOCK_GATE_STA (INFRACFG_AO_BASE + 0x90)
#define UART0_CLOCK_GATE_BIT (1U<<22)
#define UART1_CLOCK_GATE_BIT (1U<<23)
/* UART registers */
#define UART_RBR(_baseaddr) (_baseaddr + 0x0)
#define UART_THR(_baseaddr) (_baseaddr + 0x0)
#define UART_IER(_baseaddr) (_baseaddr + 0x4)
#define UART_IIR(_baseaddr) (_baseaddr + 0x8)
#define UART_FCR(_baseaddr) (_baseaddr + 0x8)
#define UART_LCR(_baseaddr) (_baseaddr + 0xc)
#define UART_MCR(_baseaddr) (_baseaddr + 0x10)
#define UART_LSR(_baseaddr) (_baseaddr + 0x14)
#define UART_MSR(_baseaddr) (_baseaddr + 0x18)
#define UART_SCR(_baseaddr) (_baseaddr + 0x1c)
#define UART_DLL(_baseaddr) (_baseaddr + 0x0)
#define UART_DLH(_baseaddr) (_baseaddr + 0x4)
#define UART_EFR(_baseaddr) (_baseaddr + 0x8)
#define UART_XON1(_baseaddr) (_baseaddr + 0x10)
#define UART_XON2(_baseaddr) (_baseaddr + 0x14)
#define UART_XOFF1(_baseaddr) (_baseaddr + 0x18)
#define UART_XOFF2(_baseaddr) (_baseaddr + 0x1c)
#define UART_AUTOBAUD(_baseaddr) (_baseaddr + 0x20)
#define UART_HIGHSPEED(_baseaddr) (_baseaddr + 0x24)
#define UART_SAMPLE_COUNT(_baseaddr) (_baseaddr + 0x28)
#define UART_SAMPLE_POINT(_baseaddr) (_baseaddr + 0x2c)
#define UART_AUTOBAUD_REG(_baseaddr) (_baseaddr + 0x30)
#define UART_RATE_FIX_REG(_baseaddr) (_baseaddr + 0x34)
#define UART_AUTO_BAUDSAMPLE(_baseaddr) (_baseaddr + 0x38)
#define UART_GUARD(_baseaddr) (_baseaddr + 0x3c)
#define UART_ESCAPE_DAT(_baseaddr) (_baseaddr + 0x40)
#define UART_ESCAPE_EN(_baseaddr) (_baseaddr + 0x44)
#define UART_SLEEP_EN(_baseaddr) (_baseaddr + 0x48)
#define UART_DMA_EN(_baseaddr) (_baseaddr + 0x4c)
#define UART_RXTRI_AD(_baseaddr) (_baseaddr + 0x50)
#define UART_FRACDIV_L(_baseaddr) (_baseaddr + 0x54)
#define UART_FRACDIV_M(_baseaddr) (_baseaddr + 0x58)
#define UART_FCR_RD(_baseaddr) (_baseaddr + 0x5C)
#define UART_USB_RX_SEL(_baseaddr) (_baseaddr + 0xB0)
#define UART_SLEEP_REQ(_baseaddr) (_baseaddr + 0xB4)
#define UART_SLEEP_ACK(_baseaddr) (_baseaddr + 0xB8)
#define UART_SPM_SEL(_baseaddr) (_baseaddr + 0xBC)
#define UART_LCR_DLAB 0x0080
#define UART_LCR_MODE_B 0x00bf
enum uart_port_ID {
UART_PORT0 = 0,
UART_PORT1
};
struct mt_uart_register {
unsigned int dll;
unsigned int dlh;
unsigned int ier;
unsigned int lcr;
unsigned int mcr;
unsigned int fcr;
unsigned int lsr;
unsigned int scr;
unsigned int efr;
unsigned int highspeed;
unsigned int sample_count;
unsigned int sample_point;
unsigned int fracdiv_l;
unsigned int fracdiv_m;
unsigned int escape_en;
unsigned int guard;
unsigned int rx_sel;
};
struct mt_uart {
unsigned long base;
struct mt_uart_register registers;
};
/* external API */
void mt_uart_save(void);
void mt_uart_restore(void);
void mt_console_uart_cg(int on);
int mt_console_uart_cg_status(void);
#endif /* __UART_H__ */

View File

@ -28,51 +28,141 @@ struct mt8183_mcucfg_regs {
uint32_t mp0_rw_rsvd0; /* 0x6C */
uint32_t mp0_rw_rsvd1; /* 0x70 */
uint32_t mp0_ro_rsvd; /* 0x74 */
uint32_t reserved0_0[98]; /* 0x78 */
uint32_t mp1_ca7l_cache_config; /* 0x200 */
uint32_t mp1_miscdbg; /* 0x204 */
uint32_t reserved0_1[9]; /* 0x208 */
uint32_t mp1_axi_config; /* 0x22C */
uint32_t mp1_misc_config[10]; /* 0x230 */
uint32_t reserved0_2[3]; /* 0x258 */
uint32_t mp1_ca7l_misc_config; /* 0x264 */
uint32_t reserved0_3[310]; /* 0x268 */
uint32_t reserved0_0; /* 0x78 */
uint32_t mp0_l2_cache_parity1_rdata; /* 0x7C */
uint32_t mp0_l2_cache_parity2_rdata; /* 0x80 */
uint32_t reserved0_1; /* 0x84 */
uint32_t mp0_rgu_dcm_config; /* 0x88 */
uint32_t mp0_ca53_specific_ctrl; /* 0x8C */
uint32_t mp0_esr_case; /* 0x90 */
uint32_t mp0_esr_mask; /* 0x94 */
uint32_t mp0_esr_trig_en; /* 0x98 */
uint32_t reserved_0_2; /* 0x9C */
uint32_t mp0_ses_cg_en; /* 0xA0 */
uint32_t reserved0_3[216]; /* 0xA4 */
uint32_t mp_dbg_ctrl; /* 0x404 */
uint32_t reserved0_4[34]; /* 0x408 */
uint32_t mp_dfd_ctrl; /* 0x490 */
uint32_t dfd_cnt_l; /* 0x494 */
uint32_t dfd_cnt_h; /* 0x498 */
uint32_t misccfg_ro_rsvd; /* 0x49C */
uint32_t reserved0_5[24]; /* 0x4A0 */
uint32_t mp1_rst_status; /* 0x500 */
uint32_t mp1_dbg_ctrl; /* 0x504 */
uint32_t mp1_dbg_flag; /* 0x508 */
uint32_t mp1_ca7l_ir_mon; /* 0x50C */
uint32_t reserved0_6[32]; /* 0x510 */
uint32_t mcusys_dbg_mon_sel_a; /* 0x590 */
uint32_t mcucys_dbg_mon; /* 0x594 */
uint32_t misccfg_sec_voi_status0; /* 0x598 */
uint32_t misccfg_sec_vio_status1; /* 0x59C */
uint32_t reserved0_7[18]; /* 0x5A0 */
uint32_t gic500_int_mask; /* 0x5E8 */
uint32_t core_rst_en_latch; /* 0x5EC */
uint32_t reserved0_8[3]; /* 0x5F0 */
uint32_t dbg_core_ret; /* 0x5FC */
uint32_t mcusys_config_a; /* 0x600 */
uint32_t mcusys_config1_a; /* 0x604 */
uint32_t mcusys_gic_prebase_a; /* 0x608 */
uint32_t mcusys_pinmux; /* 0x60C */
uint32_t sec_range0_start; /* 0x610 */
uint32_t sec_range0_end; /* 0x614 */
uint32_t sec_range_enable; /* 0x618 */
uint32_t l2c_mm_base; /* 0x61C */
uint32_t reserved0_9[8]; /* 0x620 */
uint32_t aclken_div; /* 0x640 */
uint32_t pclken_div; /* 0x644 */
uint32_t l2c_sram_ctrl; /* 0x648 */
uint32_t armpll_jit_ctrl; /* 0x64C */
uint32_t cci_addrmap; /* 0x650 */
uint32_t cci_config; /* 0x654 */
uint32_t cci_periphbase; /* 0x658 */
uint32_t cci_nevntcntovfl; /* 0x65C */
uint32_t cci_clk_ctrl; /* 0x660 */
uint32_t cci_acel_s1_ctrl; /* 0x664 */
uint32_t mcusys_bus_fabric_dcm_ctrl; /* 0x668 */
uint32_t mcu_misc_dcm_ctrl; /* 0x66C */
uint32_t xgpt_ctl; /* 0x670 */
uint32_t xgpt_idx; /* 0x674 */
uint32_t reserved0_10[3]; /* 0x678 */
uint32_t mcusys_rw_rsvd0; /* 0x684 */
uint32_t mcusys_rw_rsvd1; /* 0x688 */
uint32_t reserved0_11[13]; /* 0x68C */
uint32_t gic_500_delsel_ctl; /* 0x6C0 */
uint32_t etb_delsel_ctl; /* 0x6C4 */
uint32_t etb_rst_ctl; /* 0x6C8 */
uint32_t reserved0_12[29]; /* 0x6CC */
uint32_t cci_adb400_dcm_config; /* 0x740 */
uint32_t sync_dcm_config; /* 0x744 */
uint32_t reserved0_4[16]; /* 0x748 */
uint32_t mp0_cputop_spmc_ctl; /* 0x788 */
uint32_t mp1_cputop_spmc_ctl; /* 0x78C */
uint32_t mp1_cputop_spmc_sram_ctl; /* 0x790 */
uint32_t reserved0_5[23]; /* 0x794 */
uint32_t reserved0_13; /* 0x748 */
uint32_t sync_dcm_cluster_config; /* 0x74C */
uint32_t sw_udi; /* 0x750 */
uint32_t reserved0_14; /* 0x754 */
uint32_t gic_sync_dcm; /* 0x758 */
uint32_t big_dbg_pwr_ctrl; /* 0x75C */
uint32_t gic_cpu_periphbase; /* 0x760 */
uint32_t axi_cpu_config; /* 0x764 */
uint32_t reserved0_15[2]; /* 0x768 */
uint32_t mcsib_sys_ctrl1; /* 0x770 */
uint32_t mcsib_sys_ctrl2; /* 0x774 */
uint32_t mcsib_sys_ctrl3; /* 0x778 */
uint32_t mcsib_sys_ctrl4; /* 0x77C */
uint32_t mcsib_dbg_ctrl1; /* 0x780 */
uint32_t pwrmcu_apb2to1; /* 0x784 */
uint32_t mp0_spmc; /* 0x788 */
uint32_t reserved0_16; /* 0x78C */
uint32_t mp0_spmc_sram_ctl; /* 0x790 */
uint32_t reserved0_17; /* 0x794 */
uint32_t mp0_sw_rst_wait_cycle; /* 0x798 */
uint32_t reserved0_18; /* 0x79C */
uint32_t mp0_pll_divider_cfg; /* 0x7A0 */
uint32_t reserved0_19; /* 0x7A4 */
uint32_t mp2_pll_divider_cfg; /* 0x7A8 */
uint32_t reserved0_20[5]; /* 0x7AC */
uint32_t bus_pll_divider_cfg; /* 0x7C0 */
uint32_t reserved0_21[7]; /* 0x7C4 */
uint32_t clusterid_aff1; /* 0x7E0 */
uint32_t clusterid_aff2; /* 0x7E4 */
uint32_t reserved0_22[2]; /* 0x7E8 */
uint32_t l2_cfg_mp0; /* 0x7F0 */
uint32_t l2_cfg_mp1; /* 0x7F4 */
uint32_t reserved0_6[1282]; /* 0x7F8 */
uint32_t reserved0_23[218]; /* 0x7F8 */
uint32_t mscib_dcm_en; /* 0xB60 */
uint32_t reserved0_24[1063]; /* 0xB64 */
uint32_t cpusys0_sparkvretcntrl; /* 0x1C00 */
uint32_t cpusys0_sparken; /* 0x1C04 */
uint32_t cpusys0_amuxsel; /* 0x1C08 */
uint32_t reserved0_7[9]; /* 0x1C0C */
uint32_t reserved0_25[9]; /* 0x1C0C */
uint32_t cpusys0_cpu0_spmc_ctl; /* 0x1C30 */
uint32_t cpusys0_cpu1_spmc_ctl; /* 0x1C34 */
uint32_t cpusys0_cpu2_spmc_ctl; /* 0x1C38 */
uint32_t cpusys0_cpu3_spmc_ctl; /* 0x1C3C */
uint32_t reserved0_8[370]; /* 0x1C40 */
uint32_t reserved0_26[8]; /* 0x1C40 */
uint32_t mp0_sync_dcm_cgavg_ctrl; /* 0x1C60 */
uint32_t mp0_sync_dcm_cgavg_fact; /* 0x1C64 */
uint32_t mp0_sync_dcm_cgavg_rfact; /* 0x1C68 */
uint32_t mp0_sync_dcm_cgavg; /* 0x1C6C */
uint32_t mp0_l2_parity_clr; /* 0x1C70 */
uint32_t reserved0_27[357]; /* 0x1C74 */
uint32_t mp2_cpucfg; /* 0x2208 */
uint32_t mp2_axi_config; /* 0x220C */
uint32_t reserved0_9[36]; /* 0x2210 */
uint32_t mp2_cputop_spm_ctl; /* 0x22A0 */
uint32_t mp2_cputop_spm_sta; /* 0x22A4 */
uint32_t reserved0_10[98]; /* 0x22A8 */
uint32_t cpusys2_cpu0_spmc_ctl; /* 0x2430 */
uint32_t cpusys2_cpu0_spmc_sta; /* 0x2434 */
uint32_t cpusys2_cpu1_spmc_ctl; /* 0x2438 */
uint32_t cpusys2_cpu1_spmc_sta; /* 0x243C */
uint32_t reserved0_11[176]; /* 0x2440 */
uint32_t reserved0_28[25]; /* 0x2210 */
uint32_t mp2_sync_dcm; /* 0x2274 */
uint32_t reserved0_29[10]; /* 0x2278 */
uint32_t ptp3_cputop_spmc0; /* 0x22A0 */
uint32_t ptp3_cputop_spmc1; /* 0x22A4 */
uint32_t reserved0_30[98]; /* 0x22A8 */
uint32_t ptp3_cpu0_spmc0; /* 0x2430 */
uint32_t ptp3_cpu0_spmc1; /* 0x2434 */
uint32_t ptp3_cpu1_spmc0; /* 0x2438 */
uint32_t ptp3_cpu1_spmc1; /* 0x243C */
uint32_t ptp3_cpu2_spmc0; /* 0x2440 */
uint32_t ptp3_cpu2_spmc1; /* 0x2444 */
uint32_t ptp3_cpu3_spmc0; /* 0x2448 */
uint32_t ptp3_cpu3_spmc1; /* 0x244C */
uint32_t ptp3_cpux_spmc; /* 0x2450 */
uint32_t reserved0_31[171]; /* 0x2454 */
uint32_t spark2ld0; /* 0x2700 */
uint32_t reserved0_12[1355]; /* 0x2704 */
uint32_t cpusys1_cpu0_spmc_ctl; /* 0x3C30 */
uint32_t cpusys1_cpu1_spmc_ctl; /* 0x3C34 */
uint32_t cpusys1_cpu2_spmc_ctl; /* 0x3C38 */
uint32_t cpusys1_cpu3_spmc_ctl; /* 0x3C3C */
};
static struct mt8183_mcucfg_regs *const mt8183_mcucfg = (void *)MCUCFG_BASE;
@ -244,4 +334,235 @@ enum {
MP1_L2RSTDISABLE = 1 << MP1_L2RSTDISABLE_SHIFT
};
/* bus pll divider dcm related */
enum {
BUS_PLLDIVIDER_DCM_DBC_CNT_0_SHIFT = 11,
BUS_PLLDIV_ARMWFI_DCM_EN_SHIFT = 24,
BUS_PLLDIV_ARMWFE_DCM_EN_SHIFT = 25,
BUS_PLLDIV_DCM = (1 << BUS_PLLDIVIDER_DCM_DBC_CNT_0_SHIFT) |
(1 << BUS_PLLDIV_ARMWFI_DCM_EN_SHIFT) |
(1 << BUS_PLLDIV_ARMWFE_DCM_EN_SHIFT)
};
/* mp0 pll divider dcm related */
enum {
MP0_PLLDIV_DCM_DBC_CNT_0_SHIFT = 11,
MP0_PLLDIV_ARMWFI_DCM_EN_SHIFT = 24,
MP0_PLLDIV_ARMWFE_DCM_EN_SHIFT = 25,
MP0_PLLDIV_LASTCORE_IDLE_EN_SHIFT = 31,
MP0_PLLDIV_DCM = (1 << MP0_PLLDIV_DCM_DBC_CNT_0_SHIFT) |
(1 << MP0_PLLDIV_ARMWFI_DCM_EN_SHIFT) |
(1 << MP0_PLLDIV_ARMWFE_DCM_EN_SHIFT) |
(1u << MP0_PLLDIV_LASTCORE_IDLE_EN_SHIFT)
};
/* mp2 pll divider dcm related */
enum {
MP2_PLLDIV_DCM_DBC_CNT_0_SHIFT = 11,
MP2_PLLDIV_ARMWFI_DCM_EN_SHIFT = 24,
MP2_PLLDIV_ARMWFE_DCM_EN_SHIFT = 25,
MP2_PLLDIV_LASTCORE_IDLE_EN_SHIFT = 31,
MP2_PLLDIV_DCM = (1 << MP2_PLLDIV_DCM_DBC_CNT_0_SHIFT) |
(1 << MP2_PLLDIV_ARMWFI_DCM_EN_SHIFT) |
(1 << MP2_PLLDIV_ARMWFE_DCM_EN_SHIFT) |
(1u << MP2_PLLDIV_LASTCORE_IDLE_EN_SHIFT)
};
/* mcsib dcm related */
enum {
MCSIB_CACTIVE_SEL_SHIFT = 0,
MCSIB_DCM_EN_SHIFT = 16,
MCSIB_CACTIVE_SEL_MASK = 0xffff << MCSIB_CACTIVE_SEL_SHIFT,
MCSIB_CACTIVE_SEL = 0xffff << MCSIB_CACTIVE_SEL_SHIFT,
MCSIB_DCM_MASK = 0xffffu << MCSIB_DCM_EN_SHIFT,
MCSIB_DCM = 0xffffu << MCSIB_DCM_EN_SHIFT,
};
/* cci adb400 dcm related */
enum {
CCI_M0_ADB400_DCM_EN_SHIFT = 0,
CCI_M1_ADB400_DCM_EN_SHIFT = 1,
CCI_M2_ADB400_DCM_EN_SHIFT = 2,
CCI_S2_ADB400_DCM_EN_SHIFT = 3,
CCI_S3_ADB400_DCM_EN_SHIFT = 4,
CCI_S4_ADB400_DCM_EN_SHIFT = 5,
CCI_S5_ADB400_DCM_EN_SHIFT = 6,
ACP_S3_ADB400_DCM_EN_SHIFT = 11,
CCI_ADB400_DCM_MASK = (1 << CCI_M0_ADB400_DCM_EN_SHIFT) |
(1 << CCI_M1_ADB400_DCM_EN_SHIFT) |
(1 << CCI_M2_ADB400_DCM_EN_SHIFT) |
(1 << CCI_S2_ADB400_DCM_EN_SHIFT) |
(1 << CCI_S4_ADB400_DCM_EN_SHIFT) |
(1 << CCI_S4_ADB400_DCM_EN_SHIFT) |
(1 << CCI_S5_ADB400_DCM_EN_SHIFT) |
(1 << ACP_S3_ADB400_DCM_EN_SHIFT),
CCI_ADB400_DCM = (1 << CCI_M0_ADB400_DCM_EN_SHIFT) |
(1 << CCI_M1_ADB400_DCM_EN_SHIFT) |
(1 << CCI_M2_ADB400_DCM_EN_SHIFT) |
(0 << CCI_S2_ADB400_DCM_EN_SHIFT) |
(0 << CCI_S4_ADB400_DCM_EN_SHIFT) |
(0 << CCI_S4_ADB400_DCM_EN_SHIFT) |
(0 << CCI_S5_ADB400_DCM_EN_SHIFT) |
(1 << ACP_S3_ADB400_DCM_EN_SHIFT)
};
/* sync dcm related */
enum {
CCI_SYNC_DCM_DIV_EN_SHIFT = 0,
CCI_SYNC_DCM_UPDATE_TOG_SHIFT = 1,
CCI_SYNC_DCM_DIV_SEL_SHIFT = 2,
MP0_SYNC_DCM_DIV_EN_SHIFT = 10,
MP0_SYNC_DCM_UPDATE_TOG_SHIFT = 11,
MP0_SYNC_DCM_DIV_SEL_SHIFT = 12,
SYNC_DCM_MASK = (1 << CCI_SYNC_DCM_DIV_EN_SHIFT) |
(1 << CCI_SYNC_DCM_UPDATE_TOG_SHIFT) |
(0x7f << CCI_SYNC_DCM_DIV_SEL_SHIFT) |
(1 << MP0_SYNC_DCM_DIV_EN_SHIFT) |
(1 << MP0_SYNC_DCM_UPDATE_TOG_SHIFT) |
(0x7f << MP0_SYNC_DCM_DIV_SEL_SHIFT),
SYNC_DCM = (1 << CCI_SYNC_DCM_DIV_EN_SHIFT) |
(1 << CCI_SYNC_DCM_UPDATE_TOG_SHIFT) |
(0 << CCI_SYNC_DCM_DIV_SEL_SHIFT) |
(1 << MP0_SYNC_DCM_DIV_EN_SHIFT) |
(1 << MP0_SYNC_DCM_UPDATE_TOG_SHIFT) |
(0 << MP0_SYNC_DCM_DIV_SEL_SHIFT)
};
/* mcu bus dcm related */
enum {
MCU_BUS_DCM_EN_SHIFT = 8,
MCU_BUS_DCM = 1 << MCU_BUS_DCM_EN_SHIFT
};
/* mcusys bus fabric dcm related */
enum {
ACLK_INFRA_DYNAMIC_CG_EN_SHIFT = 0,
EMI2_ADB400_S_DCM_CTRL_SHIFT = 1,
ACLK_GPU_DYNAMIC_CG_EN_SHIFT = 2,
ACLK_PSYS_DYNAMIC_CG_EN_SHIFT = 3,
MP0_ADB400_S_DCM_CTRL_SHIFT = 4,
MP0_ADB400_M_DCM_CTRL_SHIFT = 5,
MP1_ADB400_S_DCM_CTRL_SHIFT = 6,
MP1_ADB400_M_DCM_CTRL_SHIFT = 7,
EMICLK_EMI_DYNAMIC_CG_EN_SHIFT = 8,
INFRACLK_INFRA_DYNAMIC_CG_EN_SHIFT = 9,
EMICLK_GPU_DYNAMIC_CG_EN_SHIFT = 10,
INFRACLK_PSYS_DYNAMIC_CG_EN_SHIFT = 11,
EMICLK_EMI1_DYNAMIC_CG_EN_SHIFT = 12,
EMI1_ADB400_S_DCM_CTRL_SHIFT = 16,
MP2_ADB400_M_DCM_CTRL_SHIFT = 17,
MP0_ICC_AXI_STREAM_ARCH_CG_SHIFT = 18,
MP1_ICC_AXI_STREAM_ARCH_CG_SHIFT = 19,
MP2_ICC_AXI_STREAM_ARCH_CG_SHIFT = 20,
L2_SHARE_ADB400_DCM_CTRL_SHIFT = 21,
MP1_AGGRESS_DCM_CTRL_SHIFT = 22,
MP0_AGGRESS_DCM_CTRL_SHIFT = 23,
MP0_ADB400_ACP_S_DCM_CTRL_SHIFT = 24,
MP0_ADB400_ACP_M_DCM_CTRL_SHIFT = 25,
MP1_ADB400_ACP_S_DCM_CTRL_SHIFT = 26,
MP1_ADB400_ACP_M_DCM_CTRL_SHIFT = 27,
MP3_ADB400_M_DCM_CTRL_SHIFT = 28,
MP3_ICC_AXI_STREAM_ARCH_CG_SHIFT = 29,
MCUSYS_BUS_FABRIC_DCM_MASK = (1 << ACLK_INFRA_DYNAMIC_CG_EN_SHIFT) |
(1 << EMI2_ADB400_S_DCM_CTRL_SHIFT) |
(1 << ACLK_GPU_DYNAMIC_CG_EN_SHIFT) |
(1 << ACLK_PSYS_DYNAMIC_CG_EN_SHIFT) |
(1 << MP0_ADB400_S_DCM_CTRL_SHIFT) |
(1 << MP0_ADB400_M_DCM_CTRL_SHIFT) |
(1 << MP1_ADB400_S_DCM_CTRL_SHIFT) |
(1 << MP1_ADB400_M_DCM_CTRL_SHIFT) |
(1 << EMICLK_EMI_DYNAMIC_CG_EN_SHIFT) |
(1 << INFRACLK_INFRA_DYNAMIC_CG_EN_SHIFT) |
(1 << EMICLK_GPU_DYNAMIC_CG_EN_SHIFT) |
(1 << INFRACLK_PSYS_DYNAMIC_CG_EN_SHIFT) |
(1 << EMICLK_EMI1_DYNAMIC_CG_EN_SHIFT) |
(1 << EMI1_ADB400_S_DCM_CTRL_SHIFT) |
(1 << MP2_ADB400_M_DCM_CTRL_SHIFT) |
(1 << MP0_ICC_AXI_STREAM_ARCH_CG_SHIFT) |
(1 << MP1_ICC_AXI_STREAM_ARCH_CG_SHIFT) |
(1 << MP2_ICC_AXI_STREAM_ARCH_CG_SHIFT) |
(1 << L2_SHARE_ADB400_DCM_CTRL_SHIFT) |
(1 << MP1_AGGRESS_DCM_CTRL_SHIFT) |
(1 << MP0_AGGRESS_DCM_CTRL_SHIFT) |
(1 << MP0_ADB400_ACP_S_DCM_CTRL_SHIFT) |
(1 << MP0_ADB400_ACP_M_DCM_CTRL_SHIFT) |
(1 << MP1_ADB400_ACP_S_DCM_CTRL_SHIFT) |
(1 << MP1_ADB400_ACP_M_DCM_CTRL_SHIFT) |
(1 << MP3_ADB400_M_DCM_CTRL_SHIFT) |
(1 << MP3_ICC_AXI_STREAM_ARCH_CG_SHIFT),
MCUSYS_BUS_FABRIC_DCM = (1 << ACLK_INFRA_DYNAMIC_CG_EN_SHIFT) |
(1 << EMI2_ADB400_S_DCM_CTRL_SHIFT) |
(1 << ACLK_GPU_DYNAMIC_CG_EN_SHIFT) |
(1 << ACLK_PSYS_DYNAMIC_CG_EN_SHIFT) |
(0 << MP0_ADB400_S_DCM_CTRL_SHIFT) |
(0 << MP0_ADB400_M_DCM_CTRL_SHIFT) |
(1 << MP1_ADB400_S_DCM_CTRL_SHIFT) |
(1 << MP1_ADB400_M_DCM_CTRL_SHIFT) |
(1 << EMICLK_EMI_DYNAMIC_CG_EN_SHIFT) |
(1 << INFRACLK_INFRA_DYNAMIC_CG_EN_SHIFT) |
(1 << EMICLK_GPU_DYNAMIC_CG_EN_SHIFT) |
(1 << INFRACLK_PSYS_DYNAMIC_CG_EN_SHIFT) |
(1 << EMICLK_EMI1_DYNAMIC_CG_EN_SHIFT) |
(1 << EMI1_ADB400_S_DCM_CTRL_SHIFT) |
(0 << MP2_ADB400_M_DCM_CTRL_SHIFT) |
(1 << MP0_ICC_AXI_STREAM_ARCH_CG_SHIFT) |
(1 << MP1_ICC_AXI_STREAM_ARCH_CG_SHIFT) |
(1 << MP2_ICC_AXI_STREAM_ARCH_CG_SHIFT) |
(1 << L2_SHARE_ADB400_DCM_CTRL_SHIFT) |
(1 << MP1_AGGRESS_DCM_CTRL_SHIFT) |
(1 << MP0_AGGRESS_DCM_CTRL_SHIFT) |
(1 << MP0_ADB400_ACP_S_DCM_CTRL_SHIFT) |
(1 << MP0_ADB400_ACP_M_DCM_CTRL_SHIFT) |
(1 << MP1_ADB400_ACP_S_DCM_CTRL_SHIFT) |
(1 << MP1_ADB400_ACP_M_DCM_CTRL_SHIFT) |
(1 << MP3_ADB400_M_DCM_CTRL_SHIFT) |
(1 << MP3_ICC_AXI_STREAM_ARCH_CG_SHIFT)
};
/* l2c_sram dcm related */
enum {
L2C_SRAM_DCM_EN_SHIFT = 0,
L2C_SRAM_DCM = 1 << L2C_SRAM_DCM_EN_SHIFT
};
/* mcu misc dcm related */
enum {
MP0_CNTVALUEB_DCM_EN_SHIFT = 0,
MP_CNTVALUEB_DCM_EN = 8,
CNTVALUEB_DCM = (1 << MP0_CNTVALUEB_DCM_EN_SHIFT) |
(1 << MP_CNTVALUEB_DCM_EN)
};
/* sync dcm cluster config related */
enum {
MP0_SYNC_DCM_STALL_WR_EN_SHIFT = 7,
MCUSYS_MAX_ACCESS_LATENCY_SHIFT = 24,
MCU0_SYNC_DCM_STALL_WR_EN = 1 << MP0_SYNC_DCM_STALL_WR_EN_SHIFT,
MCUSYS_MAX_ACCESS_LATENCY_MASK = 0xf << MCUSYS_MAX_ACCESS_LATENCY_SHIFT,
MCUSYS_MAX_ACCESS_LATENCY = 0x5 << MCUSYS_MAX_ACCESS_LATENCY_SHIFT
};
/* cpusys rgu dcm related */
enum {
CPUSYS_RGU_DCM_CONFIG_SHIFT = 0,
CPUSYS_RGU_DCM_CINFIG = 1 << CPUSYS_RGU_DCM_CONFIG_SHIFT
};
/* mp2 sync dcm related */
enum {
MP2_DCM_EN_SHIFT = 0,
MP2_DCM_EN = 1 << MP2_DCM_EN_SHIFT
};
#endif /* MT8183_MCUCFG_H */

View File

@ -24,8 +24,6 @@
#define BIT_CA15M_L2PARITY_EN (1 << 1)
#define BIT_CA15M_LASTPC_DIS (1 << 8)
#define MP1_CPUTOP_PWR_CON 0x10006218
#define MCU_ALL_PWR_ON_CTRL 0x0c530b58
#define PLAT_MTK_CIRCULAR_BUFFER_UNLOCK 0xefab4133
#define PLAT_MTK_CIRCULAR_BUFFER_LOCK 0xefab4134

View File

@ -41,6 +41,7 @@
#define APMIXEDSYS (IO_PHYS + 0xC000)
#define ARMPLL_LL_CON0 (APMIXEDSYS + 0x200)
#define ARMPLL_L_CON0 (APMIXEDSYS + 0x210)
#define ARMPLL_L_PWR_CON0 (APMIXEDSYS + 0x21c)
#define MAINPLL_CON0 (APMIXEDSYS + 0x220)
#define CCIPLL_CON0 (APMIXEDSYS + 0x290)
@ -74,6 +75,7 @@
#define MT_L2_WRITE_ACCESS_RATE (MCUCFG_BASE + 0x604)
#define MP0_CA7L_CACHE_CONFIG (MCUCFG_BASE + 0x7f0)
#define MP1_CA7L_CACHE_CONFIG (MCUCFG_BASE + 0x7f4)
#define EMI_WFIFO (MCUCFG_BASE + 0x0b5c)
/*******************************************************************************
* GIC related constants
@ -87,6 +89,7 @@
* UART related constants
******************************************************************************/
#define UART0_BASE (IO_PHYS + 0x01002000)
#define UART1_BASE (IO_PHYS + 0x01003000)
#define UART_BAUDRATE 115200
#define UART_CLOCK 26000000

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,41 @@
/*
* Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __SSPM_REG_H__
#define __SSPM_REG_H__
#include "platform_def.h"
#define SSPM_CFGREG_RSV_RW_REG0 (SSPM_CFGREG_BASE + 0x0100)
#define SSPM_CFGREG_ACAO_INT_SET (SSPM_CFGREG_BASE + 0x00D8)
#define SSPM_CFGREG_ACAO_INT_CLR (SSPM_CFGREG_BASE + 0x00DC)
#define SSPM_CFGREG_ACAO_WAKEUP_EN (SSPM_CFGREG_BASE + 0x0204)
#define STANDBYWFI_EN(n) (1 << (n + 8))
#define GIC_IRQOUT_EN(n) (1 << (n + 0))
#define NF_MCDI_MBOX 19
#define MCDI_MBOX_CLUSTER_0_CAN_POWER_OFF 0
#define MCDI_MBOX_CLUSTER_1_CAN_POWER_OFF 1
#define MCDI_MBOX_BUCK_POWER_OFF_MASK 2
#define MCDI_MBOX_CLUSTER_0_ATF_ACTION_DONE 3
#define MCDI_MBOX_CLUSTER_1_ATF_ACTION_DONE 4
#define MCDI_MBOX_BOOTADDR 5
#define MCDI_MBOX_PAUSE_ACTION 6
#define MCDI_MBOX_AVAIL_CPU_MASK 7
#define MCDI_MBOX_CPU_CLUSTER_PWR_STAT 8
#define MCDI_MBOX_ACTION_STAT 9
#define MCDI_MBOX_CLUSTER_0_CNT 10
#define MCDI_MBOX_CLUSTER_1_CNT 11
#define MCDI_MBOX_CPU_ISOLATION_MASK 12
#define MCDI_MBOX_PAUSE_ACK 13
#define MCDI_MBOX_PENDING_ON_EVENT 14
#define MCDI_MBOX_PROF_CMD 15
#define MCDI_MBOX_DRCC_CALI_DONE 16
#define MCDI_MBOX_HP_CMD 17
#define MCDI_MBOX_HP_ACK 18
#endif /* __SSPM_REG_H__ */

View File

@ -9,6 +9,7 @@
#include <lib/mmio.h>
#include <plat_debug.h>
#include <platform_def.h>
#include <spm.h>
void circular_buffer_setup(void)
{

View File

@ -16,6 +16,7 @@
#include <platform_def.h>
#include <scu.h>
#include <mt_gic_v3.h>
#include <mtk_mcdi.h>
#include <mtk_plat_common.h>
#include <mtgpio.h>
#include <mtspmc.h>
@ -25,9 +26,103 @@
#include <plat_private.h>
#include <power_tracer.h>
#include <pmic.h>
#include <spm.h>
#include <spm_suspend.h>
#include <sspm.h>
#include <rtc.h>
#define MTK_LOCAL_STATE_OFF 2
/* Local power state for power domains in Run state. */
#define MTK_LOCAL_STATE_RUN 0
/* Local power state for retention. */
#define MTK_LOCAL_STATE_RET 1
/* Local power state for OFF/power-down. */
#define MTK_LOCAL_STATE_OFF 2
#if PSCI_EXTENDED_STATE_ID
/*
* Macros used to parse state information from State-ID if it is using the
* recommended encoding for State-ID.
*/
#define MTK_LOCAL_PSTATE_WIDTH 4
#define MTK_LOCAL_PSTATE_MASK ((1 << MTK_LOCAL_PSTATE_WIDTH) - 1)
/* Macros to construct the composite power state */
/* Make composite power state parameter till power level 0 */
#define mtk_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \
(((lvl0_state) << PSTATE_ID_SHIFT) | ((type) << PSTATE_TYPE_SHIFT))
#else /* !PSCI_EXTENDED_STATE_ID */
#define mtk_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \
(((lvl0_state) << PSTATE_ID_SHIFT) | \
((pwr_lvl) << PSTATE_PWR_LVL_SHIFT) | \
((type) << PSTATE_TYPE_SHIFT))
#endif /* PSCI_EXTENDED_STATE_ID */
/* Make composite power state parameter till power level 1 */
#define mtk_make_pwrstate_lvl1(lvl1_state, lvl0_state, pwr_lvl, type) \
(((lvl1_state) << MTK_LOCAL_PSTATE_WIDTH) | \
mtk_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type))
/* Make composite power state parameter till power level 2 */
#define mtk_make_pwrstate_lvl2( \
lvl2_state, lvl1_state, lvl0_state, pwr_lvl, type) \
(((lvl2_state) << (MTK_LOCAL_PSTATE_WIDTH * 2)) | \
mtk_make_pwrstate_lvl1(lvl1_state, lvl0_state, pwr_lvl, type))
#define MTK_PWR_LVL0 0
#define MTK_PWR_LVL1 1
#define MTK_PWR_LVL2 2
/* Macros to read the MTK power domain state */
#define MTK_CORE_PWR_STATE(state) (state)->pwr_domain_state[MTK_PWR_LVL0]
#define MTK_CLUSTER_PWR_STATE(state) (state)->pwr_domain_state[MTK_PWR_LVL1]
#define MTK_SYSTEM_PWR_STATE(state) ((PLAT_MAX_PWR_LVL > MTK_PWR_LVL1) ? \
(state)->pwr_domain_state[MTK_PWR_LVL2] : 0)
#if PSCI_EXTENDED_STATE_ID
/*
* The table storing the valid idle power states. Ensure that the
* array entries are populated in ascending order of state-id to
* enable us to use binary search during power state validation.
* The table must be terminated by a NULL entry.
*/
const unsigned int mtk_pm_idle_states[] = {
/* State-id - 0x001 */
mtk_make_pwrstate_lvl2(MTK_LOCAL_STATE_RUN, MTK_LOCAL_STATE_RUN,
MTK_LOCAL_STATE_RET, MTK_PWR_LVL0, PSTATE_TYPE_STANDBY),
/* State-id - 0x002 */
mtk_make_pwrstate_lvl2(MTK_LOCAL_STATE_RUN, MTK_LOCAL_STATE_RUN,
MTK_LOCAL_STATE_OFF, MTK_PWR_LVL0, PSTATE_TYPE_POWERDOWN),
/* State-id - 0x022 */
mtk_make_pwrstate_lvl2(MTK_LOCAL_STATE_RUN, MTK_LOCAL_STATE_OFF,
MTK_LOCAL_STATE_OFF, MTK_PWR_LVL1, PSTATE_TYPE_POWERDOWN),
#if PLAT_MAX_PWR_LVL > MTK_PWR_LVL1
/* State-id - 0x222 */
mtk_make_pwrstate_lvl2(MTK_LOCAL_STATE_OFF, MTK_LOCAL_STATE_OFF,
MTK_LOCAL_STATE_OFF, MTK_PWR_LVL2, PSTATE_TYPE_POWERDOWN),
#endif
0,
};
#endif
#define CPU_IDX(cluster, cpu) ((cluster << 2) + cpu)
#define ON true
#define OFF false
/* Pause MCDI when CPU hotplug */
static bool HP_SSPM_PAUSE;
/* CPU Hotplug by SSPM */
static bool HP_SSPM_CTRL = true;
/* Turn off cluster when CPU hotplug off */
static bool HP_CLUSTER_OFF = true;
/* Turn off cluster when CPU MCDI off */
static bool MCDI_C2 = true;
/* Enable MCDI */
static bool MCDI_SSPM = true;
static uintptr_t secure_entrypoint;
@ -38,30 +133,171 @@ static void mp1_L2_desel_config(void)
dsb();
}
static bool clst_single_pwr(int cluster, int cpu)
{
uint32_t cpu_mask[2] = {0x00001e00, 0x000f0000};
uint32_t cpu_pwr_bit[] = {9, 10, 11, 12, 16, 17, 18, 19};
int my_idx = (cluster << 2) + cpu;
uint32_t pwr_stat = mmio_read_32(0x10006180);
return !(pwr_stat & (cpu_mask[cluster] & ~BIT(cpu_pwr_bit[my_idx])));
}
static bool clst_single_on(int cluster, int cpu)
{
uint32_t cpu_mask[2] = {0x0f, 0xf0};
int my_idx = (cluster << 2) + cpu;
uint32_t on_stat = mcdi_avail_cpu_mask_read();
return !(on_stat & (cpu_mask[cluster] & ~BIT(my_idx)));
}
static void plat_cluster_pwrdwn_common(uint64_t mpidr, int cluster)
{
if (cluster > 0)
mt_gic_sync_dcm_enable();
/* Disable coherency */
plat_mtk_cci_disable();
disable_scu(mpidr);
}
static void plat_cluster_pwron_common(uint64_t mpidr, int cluster)
{
if (cluster > 0) {
l2c_parity_check_setup();
circular_buffer_setup();
mp1_L2_desel_config();
mt_gic_sync_dcm_disable();
}
/* Enable coherency */
enable_scu(mpidr);
plat_mtk_cci_enable();
/* Enable big core dcm */
plat_dcm_restore_cluster_on(mpidr);
/* Enable rgu dcm */
plat_dcm_rgu_enable();
}
static void plat_cpu_standby(plat_local_state_t cpu_state)
{
unsigned int scr;
scr = read_scr_el3();
write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT);
isb();
dsb();
wfi();
write_scr_el3(scr);
}
static void mcdi_ctrl_before_hotplug_on(int cluster, int cpu)
{
if (!HP_SSPM_CTRL && HP_SSPM_PAUSE && MCDI_SSPM) {
mcdi_pause_clr(cluster, CPU_IDX(cluster, cpu), OFF);
mcdi_pause_set(cluster, CPU_IDX(cluster, cpu), ON);
}
}
static void mcdi_ctrl_before_hotplug_off(int cluster, int cpu, bool cluster_off)
{
if (!HP_SSPM_CTRL && HP_SSPM_PAUSE && MCDI_SSPM)
mcdi_pause_set(cluster_off ? cluster : -1,
CPU_IDX(cluster, cpu), OFF);
}
static void mcdi_ctrl_cluster_cpu_off(int cluster, int cpu, bool cluster_off)
{
if (MCDI_SSPM) {
sspm_set_bootaddr(secure_entrypoint);
sspm_standbywfi_irq_enable(CPU_IDX(cluster, cpu));
if (cluster_off)
sspm_cluster_pwr_off_notify(cluster);
else
sspm_cluster_pwr_on_notify(cluster);
}
}
static void mcdi_ctrl_suspend(void)
{
if (MCDI_SSPM)
mcdi_pause();
}
static void mcdi_ctrl_resume(void)
{
if (MCDI_SSPM)
mcdi_unpause();
}
static void hotplug_ctrl_cluster_on(int cluster, int cpu)
{
if (HP_SSPM_CTRL && MCDI_SSPM) {
mcdi_hotplug_clr(cluster, CPU_IDX(cluster, cpu), OFF);
mcdi_hotplug_set(cluster, -1, ON);
mcdi_hotplug_wait_ack(cluster, -1, ON);
} else {
/* power on cluster */
if (!spm_get_cluster_powerstate(cluster))
spm_poweron_cluster(cluster);
}
}
static void hotplug_ctrl_cpu_on(int cluster, int cpu)
{
if (HP_SSPM_CTRL && MCDI_SSPM)
mcdi_hotplug_set(cluster, CPU_IDX(cluster, cpu), ON);
else
spm_poweron_cpu(cluster, cpu);
}
static void hotplug_ctrl_cpu_on_finish(int cluster, int cpu)
{
spm_disable_cpu_auto_off(cluster, cpu);
if (HP_SSPM_CTRL && MCDI_SSPM)
mcdi_hotplug_clr(cluster, CPU_IDX(cluster, cpu), ON);
else if (HP_SSPM_PAUSE && MCDI_SSPM)
mcdi_pause_clr(cluster, CPU_IDX(cluster, cpu), ON);
mcdi_avail_cpu_mask_set(BIT(CPU_IDX(cluster, cpu)));
}
static void hotplug_ctrl_cluster_cpu_off(int cluster, int cpu, bool cluster_off)
{
mcdi_avail_cpu_mask_clr(BIT(CPU_IDX(cluster, cpu)));
if (HP_SSPM_CTRL && MCDI_SSPM) {
mcdi_hotplug_set(cluster_off ? cluster : -1,
CPU_IDX(cluster, cpu), OFF);
} else {
spm_enable_cpu_auto_off(cluster, cpu);
if (cluster_off)
spm_enable_cluster_auto_off(cluster);
spm_set_cpu_power_off(cluster, cpu);
}
}
static int plat_mtk_power_domain_on(unsigned long mpidr)
{
int cpu = MPIDR_AFFLVL0_VAL(mpidr);
int cluster = MPIDR_AFFLVL1_VAL(mpidr);
INFO("%s():%d: mpidr: %lx, c.c: %d.%d\n",
__func__, __LINE__, mpidr, cluster, cpu);
/* power on cluster */
if (!spm_get_cluster_powerstate(cluster)) {
spm_poweron_cluster(cluster);
if (cluster == 1) {
l2c_parity_check_setup();
circular_buffer_setup();
mp1_L2_desel_config();
mt_gic_sync_dcm_disable();
}
}
mcdi_ctrl_before_hotplug_on(cluster, cpu);
hotplug_ctrl_cluster_on(cluster, cpu);
/* init cpu reset arch as AARCH64 */
mcucfg_init_archstate(cluster, cpu, 1);
mcucfg_set_bootaddr(cluster, cpu, secure_entrypoint);
spm_poweron_cpu(cluster, cpu);
hotplug_ctrl_cpu_on(cluster, cpu);
return PSCI_E_SUCCESS;
}
@ -71,23 +307,18 @@ static void plat_mtk_power_domain_off(const psci_power_state_t *state)
uint64_t mpidr = read_mpidr();
int cpu = MPIDR_AFFLVL0_VAL(mpidr);
int cluster = MPIDR_AFFLVL1_VAL(mpidr);
const plat_local_state_t *pds = state->pwr_domain_state;
bool afflvl1 = (pds[MPIDR_AFFLVL1] == MTK_LOCAL_STATE_OFF);
bool cluster_off = (HP_CLUSTER_OFF && afflvl1 &&
clst_single_on(cluster, cpu));
INFO("%s():%d: c.c: %d.%d\n", __func__, __LINE__, cluster, cpu);
/* Prevent interrupts from spuriously waking up this cpu */
mt_gic_cpuif_disable();
spm_enable_cpu_auto_off(cluster, cpu);
if (cluster_off)
plat_cluster_pwrdwn_common(mpidr, cluster);
if (state->pwr_domain_state[MPIDR_AFFLVL1] == MTK_LOCAL_STATE_OFF) {
if (cluster == 1)
mt_gic_sync_dcm_enable();
plat_mtk_cci_disable();
spm_enable_cluster_auto_off(cluster);
}
spm_set_cpu_power_off(cluster, cpu);
mcdi_ctrl_before_hotplug_off(cluster, cpu, cluster_off);
hotplug_ctrl_cluster_cpu_off(cluster, cpu, cluster_off);
}
static void plat_mtk_power_domain_on_finish(const psci_power_state_t *state)
@ -95,29 +326,170 @@ static void plat_mtk_power_domain_on_finish(const psci_power_state_t *state)
uint64_t mpidr = read_mpidr();
int cpu = MPIDR_AFFLVL0_VAL(mpidr);
int cluster = MPIDR_AFFLVL1_VAL(mpidr);
const plat_local_state_t *pds = state->pwr_domain_state;
bool afflvl1 = (pds[MPIDR_AFFLVL1] == MTK_LOCAL_STATE_OFF);
INFO("%s():%d: c.c: %d.%d\n", __func__, __LINE__, cluster, cpu);
if (afflvl1)
plat_cluster_pwron_common(mpidr, cluster);
assert(state->pwr_domain_state[MPIDR_AFFLVL0] == MTK_LOCAL_STATE_OFF);
if (state->pwr_domain_state[MPIDR_AFFLVL1] == MTK_LOCAL_STATE_OFF) {
enable_scu(mpidr);
/* Enable coherency if this cluster was off */
plat_mtk_cci_enable();
/* Enable big core dcm if this cluster was on */
plat_dcm_restore_cluster_on(mpidr);
/* Enable rgu dcm if this cluster was off */
plat_dcm_rgu_enable();
}
spm_disable_cpu_auto_off(cluster, cpu);
/* Enable the gic cpu interface */
mt_gic_pcpu_init();
mt_gic_cpuif_enable();
hotplug_ctrl_cpu_on_finish(cluster, cpu);
}
static void plat_mtk_power_domain_suspend(const psci_power_state_t *state)
{
uint64_t mpidr = read_mpidr();
int cpu = MPIDR_AFFLVL0_VAL(mpidr);
int cluster = MPIDR_AFFLVL1_VAL(mpidr);
const plat_local_state_t *pds = state->pwr_domain_state;
bool afflvl1 = (pds[MPIDR_AFFLVL1] == MTK_LOCAL_STATE_OFF);
bool afflvl2 = (pds[MPIDR_AFFLVL2] == MTK_LOCAL_STATE_OFF);
bool cluster_off = MCDI_C2 && afflvl1 && clst_single_pwr(cluster, cpu);
/* init cpu reset arch as AARCH64 */
mcucfg_init_archstate(cluster, cpu, 1);
mcucfg_set_bootaddr(cluster, cpu, secure_entrypoint);
mt_gic_cpuif_disable();
mt_gic_irq_save();
plat_dcm_mcsi_a_backup();
if (cluster_off || afflvl2)
plat_cluster_pwrdwn_common(mpidr, cluster);
if (afflvl2) {
spm_data_t spm_d = { .cmd = SPM_SUSPEND };
uint32_t *d = (uint32_t *)&spm_d;
uint32_t l = sizeof(spm_d) / sizeof(uint32_t);
mcdi_ctrl_suspend();
spm_set_bootaddr(secure_entrypoint);
if (MCDI_SSPM)
sspm_ipi_send_non_blocking(IPI_ID_SUSPEND, d);
spm_system_suspend();
if (MCDI_SSPM)
while (sspm_ipi_recv_non_blocking(IPI_ID_SUSPEND, d, l))
;
} else {
mcdi_ctrl_cluster_cpu_off(cluster, cpu, cluster_off);
}
}
static void plat_mtk_power_domain_suspend_finish(const psci_power_state_t *state)
{
uint64_t mpidr = read_mpidr();
int cluster = MPIDR_AFFLVL1_VAL(mpidr);
const plat_local_state_t *pds = state->pwr_domain_state;
bool afflvl2 = (pds[MPIDR_AFFLVL2] == MTK_LOCAL_STATE_OFF);
if (afflvl2) {
spm_data_t spm_d = { .cmd = SPM_RESUME };
uint32_t *d = (uint32_t *)&spm_d;
uint32_t l = sizeof(spm_d) / sizeof(uint32_t);
mt_gic_init();
mt_gic_irq_restore();
mmio_write_32(EMI_WFIFO, 0xf);
if (MCDI_SSPM)
sspm_ipi_send_non_blocking(IPI_ID_SUSPEND, d);
spm_system_suspend_finish();
if (MCDI_SSPM)
while (sspm_ipi_recv_non_blocking(IPI_ID_SUSPEND, d, l))
;
mcdi_ctrl_resume();
}
plat_cluster_pwron_common(mpidr, cluster);
plat_dcm_mcsi_a_restore();
}
#if PSCI_EXTENDED_STATE_ID
static int plat_mtk_validate_power_state(unsigned int power_state,
psci_power_state_t *req_state)
{
unsigned int state_id;
int i;
assert(req_state);
if (!MCDI_SSPM)
return PSCI_E_INVALID_PARAMS;
/*
* Currently we are using a linear search for finding the matching
* entry in the idle power state array. This can be made a binary
* search if the number of entries justify the additional complexity.
*/
for (i = 0; !!mtk_pm_idle_states[i]; i++) {
if (power_state == mtk_pm_idle_states[i])
break;
}
/* Return error if entry not found in the idle state array */
if (!mtk_pm_idle_states[i])
return PSCI_E_INVALID_PARAMS;
i = 0;
state_id = psci_get_pstate_id(power_state);
/* Parse the State ID and populate the state info parameter */
while (state_id) {
req_state->pwr_domain_state[i++] = state_id &
MTK_LOCAL_PSTATE_MASK;
state_id >>= MTK_LOCAL_PSTATE_WIDTH;
}
return PSCI_E_SUCCESS;
}
#else /* if !PSCI_EXTENDED_STATE_ID */
static int plat_mtk_validate_power_state(unsigned int power_state,
psci_power_state_t *req_state)
{
int pstate = psci_get_pstate_type(power_state);
int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
int i;
assert(req_state);
if (pwr_lvl > PLAT_MAX_PWR_LVL)
return PSCI_E_INVALID_PARAMS;
/* Sanity check the requested state */
if (pstate == PSTATE_TYPE_STANDBY) {
/*
* It's possible to enter standby only on power level 0
* Ignore any other power level.
*/
if (pwr_lvl != 0)
return PSCI_E_INVALID_PARAMS;
req_state->pwr_domain_state[MTK_PWR_LVL0] = MTK_LOCAL_STATE_RET;
} else if (!MCDI_SSPM) {
return PSCI_E_INVALID_PARAMS;
} else {
for (i = 0; i <= pwr_lvl; i++)
req_state->pwr_domain_state[i] = MTK_LOCAL_STATE_OFF;
}
return PSCI_E_SUCCESS;
}
#endif /* PSCI_EXTENDED_STATE_ID */
/*******************************************************************************
* MTK handlers to shutdown/reboot the system
******************************************************************************/
@ -147,21 +519,29 @@ static void __dead2 plat_mtk_system_reset(void)
panic();
}
static void plat_mtk_get_sys_suspend_power_state(psci_power_state_t *req_state)
{
assert(PLAT_MAX_PWR_LVL >= 2);
for (int i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++)
req_state->pwr_domain_state[i] = MTK_LOCAL_STATE_OFF;
}
/*******************************************************************************
* MTK_platform handler called when an affinity instance is about to be turned
* on. The level and mpidr determine the affinity instance.
******************************************************************************/
static const plat_psci_ops_t plat_plat_pm_ops = {
.cpu_standby = NULL,
.cpu_standby = plat_cpu_standby,
.pwr_domain_on = plat_mtk_power_domain_on,
.pwr_domain_on_finish = plat_mtk_power_domain_on_finish,
.pwr_domain_off = plat_mtk_power_domain_off,
.pwr_domain_suspend = NULL,
.pwr_domain_suspend_finish = NULL,
.pwr_domain_suspend = plat_mtk_power_domain_suspend,
.pwr_domain_suspend_finish = plat_mtk_power_domain_suspend_finish,
.system_off = plat_mtk_system_off,
.system_reset = plat_mtk_system_reset,
.validate_power_state = NULL,
.get_sys_suspend_power_state = NULL,
.validate_power_state = plat_mtk_validate_power_state,
.get_sys_suspend_power_state = plat_mtk_get_sys_suspend_power_state,
};
int plat_setup_psci_ops(uintptr_t sec_entrypoint,
@ -169,5 +549,11 @@ int plat_setup_psci_ops(uintptr_t sec_entrypoint,
{
*psci_ops = &plat_plat_pm_ops;
secure_entrypoint = sec_entrypoint;
if (!check_mcdi_ctl_stat()) {
HP_SSPM_CTRL = false;
MCDI_SSPM = false;
}
return 0;
}

View File

@ -9,10 +9,14 @@ MTK_PLAT_SOC := ${MTK_PLAT}/${PLAT}
PLAT_INCLUDES := -I${MTK_PLAT}/common/ \
-I${MTK_PLAT_SOC}/drivers/ \
-I${MTK_PLAT_SOC}/drivers/mcdi/ \
-I${MTK_PLAT_SOC}/drivers/spmc/ \
-I${MTK_PLAT_SOC}/drivers/gpio/ \
-I${MTK_PLAT_SOC}/drivers/pmic/ \
-I${MTK_PLAT_SOC}/drivers/spm/ \
-I${MTK_PLAT_SOC}/drivers/sspm/ \
-I${MTK_PLAT_SOC}/drivers/rtc/ \
-I${MTK_PLAT_SOC}/drivers/uart/ \
-I${MTK_PLAT_SOC}/include/
PLAT_BL_COMMON_SOURCES := lib/xlat_tables/aarch64/xlat_tables.c \
@ -45,15 +49,21 @@ BL31_SOURCES += common/desc_image_load.c \
${MTK_PLAT_SOC}/drivers/mcsi/mcsi.c \
${MTK_PLAT_SOC}/drivers/pmic/pmic.c \
${MTK_PLAT_SOC}/drivers/rtc/rtc.c \
${MTK_PLAT_SOC}/drivers/mcdi/mtk_mcdi.c \
${MTK_PLAT_SOC}/drivers/spmc/mtspmc.c \
${MTK_PLAT_SOC}/drivers/spm/spm.c \
${MTK_PLAT_SOC}/drivers/spm/spm_pmic_wrap.c \
${MTK_PLAT_SOC}/drivers/spm/spm_suspend.c \
${MTK_PLAT_SOC}/drivers/gpio/mtgpio.c \
${MTK_PLAT_SOC}/drivers/uart/uart.c \
${MTK_PLAT_SOC}/plat_pm.c \
${MTK_PLAT_SOC}/plat_topology.c \
${MTK_PLAT_SOC}/plat_mt_gic.c \
${MTK_PLAT_SOC}/plat_dcm.c \
${MTK_PLAT_SOC}/bl31_plat_setup.c \
${MTK_PLAT_SOC}/plat_debug.c \
${MTK_PLAT_SOC}/scu.c
${MTK_PLAT_SOC}/scu.c \
${MTK_PLAT_SOC}/drivers/sspm/sspm.c
# Enable workarounds for selected Cortex-A53 erratas.
ERRATA_A53_826319 := 0