summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnson Huang <Anson.Huang@nxp.com>2018-08-10 17:49:00 +0800
committerBai Ping <ping.bai@nxp.com>2018-09-15 00:18:32 +0800
commit7b60954d68e074d6d0d1a6f828f4392cf7c7137d (patch)
treeb8c02b2582e001eb86dc8e2f67aa88c478a0d079
parentca98a9fca54b491755e515ca0f0d7f53a19ad74f (diff)
plat: imx8mm: Add support for imx8mm lpa
For i.MX8MM low power audio playback, when Linux suspend, M4 still needs to be active for audio playback, so system can NOT enter DSM mode but only force A core platform into STOP mode, PLLs/NoC/DRAM need to be active as well and MU interrupt wakeup needs to be enabled for waking up Linux by MU message sent by M4. Signed-off-by: Anson Huang <Anson.Huang@nxp.com> Signed-off-by: Bai Ping <ping.bai@nxp.com>
-rw-r--r--plat/imx/imx8mm/gpc.c105
-rw-r--r--plat/imx/imx8mm/imx8mm_bl31_setup.c5
-rw-r--r--plat/imx/imx8mm/imx8mm_psci.c6
-rw-r--r--plat/imx/imx8mm/include/soc.h5
4 files changed, 87 insertions, 34 deletions
diff --git a/plat/imx/imx8mm/gpc.c b/plat/imx/imx8mm/gpc.c
index f35eae38..e6db4116 100644
--- a/plat/imx/imx8mm/gpc.c
+++ b/plat/imx/imx8mm/gpc.c
@@ -131,6 +131,9 @@
#define VPU_G2_PGC 0xf00
#define VPU_H1_PGC 0xf40
+#define M4RCR 0xC
+#define SRC_SCR_M4C_NON_SCLR_RST_MASK (1 << 0)
+
#define IMX_PD_DOMAIN(name) \
{ \
.pwr_req = name##_PWR_REQ, \
@@ -209,6 +212,21 @@ static struct plat_gic_ctx imx_gicv3_ctx;
static unsigned int pu_domain_status;
+bool imx_is_m4_enabled(void)
+{
+ return !( mmio_read_32(IMX_SRC_BASE + M4RCR)
+ & SRC_SCR_M4C_NON_SCLR_RST_MASK);
+}
+
+#define M4_LPA_ACTIVE 0x5555
+#define M4_LPA_IDLE 0x0
+#define SRC_GPR9 0x94
+
+bool imx_m4_lpa_active(void)
+{
+ return mmio_read_32(IMX_SRC_BASE + SRC_GPR9) & M4_LPA_ACTIVE;
+}
+
void imx_set_cpu_secure_entry(int core_id, uint64_t sec_entrypoint)
{
uint64_t temp_base;
@@ -462,6 +480,20 @@ void imx_set_sys_lpm(bool retention)
SLPCR_BYPASS_PMIC_READY | SLPCR_RBC_EN);
mmio_write_32(IMX_GPC_BASE + SLPCR, val);
+
+ if (imx_is_m4_enabled() && imx_m4_lpa_active()) {
+ val = mmio_read_32(IMX_GPC_BASE + SLPCR);
+ val |= SLPCR_A53_FASTWUP_STOP;
+ mmio_write_32(IMX_GPC_BASE + 0x14, val);
+ return;
+ }
+
+ if (!imx_is_m4_enabled()) {
+ /* mask M4 DSM trigger if M4 is NOT enabled */
+ val = mmio_read_32(IMX_GPC_BASE + LPCR_M4);
+ val |= 1 << 31;
+ mmio_write_32(IMX_GPC_BASE + LPCR_M4, val);
+ }
}
void imx_set_rbc_count(void)
@@ -490,6 +522,8 @@ void imx_anamix_pre_suspend()
{
int i;
uint32_t pll_ctrl;
+ if (imx_is_m4_enabled() && imx_m4_lpa_active())
+ return;
/* bypass all the plls before enter DSM mode */
for (i = 0; i < ARRAY_SIZE(pll_ctrl_offset); i++) {
pll_ctrl = mmio_read_32(IMX_ANAMIX_BASE + pll_ctrl_offset[i]);
@@ -514,6 +548,8 @@ void imx_anamix_post_resume(void)
{
int i;
uint32_t pll_ctrl;
+ if (imx_is_m4_enabled() && imx_m4_lpa_active())
+ return;
/* unbypass all the plls after exit from DSM mode */
for (i = 0; i < ARRAY_SIZE(pll_ctrl_offset); i++) {
pll_ctrl = mmio_read_32(IMX_ANAMIX_BASE + pll_ctrl_offset[i]);
@@ -555,20 +591,22 @@ void noc_wrapper_pre_suspend(unsigned int proc_num)
{
uint32_t val;
- /* enable MASTER1 & MASTER2 power down in A53 LPM mode */
- val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC);
- val &= ~(1 << 7);
- val &= ~(1 << 8);
- mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val);
+ if (!imx_is_m4_enabled() || !imx_m4_lpa_active()) {
+ /* enable MASTER1 & MASTER2 power down in A53 LPM mode */
+ val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC);
+ val &= ~(1 << 7);
+ val &= ~(1 << 8);
+ mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val);
- val = mmio_read_32(IMX_GPC_BASE + MST_CPU_MAPPING);
- val |= (0x3 << 1);
- mmio_write_32(IMX_GPC_BASE + MST_CPU_MAPPING, val);
+ val = mmio_read_32(IMX_GPC_BASE + MST_CPU_MAPPING);
+ val |= (0x3 << 1);
+ mmio_write_32(IMX_GPC_BASE + MST_CPU_MAPPING, val);
- /* noc can only be power down when all the pu domain is off */
- if (!pu_domain_status)
- /* enable noc power down */
- imx_noc_slot_config(true);
+ /* noc can only be power down when all the pu domain is off */
+ if (!pu_domain_status)
+ /* enable noc power down */
+ imx_noc_slot_config(true);
+ }
/*
* gic redistributor context save must be called when
* the GIC CPU interface is disabled and before distributor save.
@@ -580,24 +618,25 @@ void noc_wrapper_post_resume(unsigned int proc_num)
{
uint32_t val;
- /* disable MASTER1 & MASTER2 power down in A53 LPM mode */
- val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC);
- val |= (1 << 7);
- val |= (1 << 8);
- mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val);
+ if (!imx_is_m4_enabled() || !imx_m4_lpa_active()) {
+ /* disable MASTER1 & MASTER2 power down in A53 LPM mode */
+ val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC);
+ val |= (1 << 7);
+ val |= (1 << 8);
+ mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val);
- val = mmio_read_32(IMX_GPC_BASE + MST_CPU_MAPPING);
- val &= ~(0x3 << 1);
- mmio_write_32(IMX_GPC_BASE + MST_CPU_MAPPING, val);
+ val = mmio_read_32(IMX_GPC_BASE + MST_CPU_MAPPING);
+ val &= ~(0x3 << 1);
+ mmio_write_32(IMX_GPC_BASE + MST_CPU_MAPPING, val);
- /* noc can only be power down when all the pu domain is off */
- if (!pu_domain_status) {
- /* re-init the tz380 if resume from noc power down */
- imx8mm_tz380_init();
- /* disable noc power down */
- imx_noc_slot_config(false);
+ /* noc can only be power down when all the pu domain is off */
+ if (!pu_domain_status) {
+ /* re-init the tz380 if resume from noc power down */
+ imx8mm_tz380_init();
+ /* disable noc power down */
+ imx_noc_slot_config(false);
+ }
}
-
/* restore gic context */
plat_gic_restore(proc_num, &imx_gicv3_ctx);
}
@@ -630,6 +669,13 @@ void imx_set_sys_wakeup(int last_core, bool pdn)
mmio_write_32(IMX_GPC_BASE + gpc_imr_offset[last_core] + i * 4,
irq_mask);
}
+
+ /* enable the MU wakeup */
+ if (imx_is_m4_enabled()) {
+ val = mmio_read_32(IMX_GPC_BASE + GPC_IMR1_CORE0_A53 + 0x8);
+ val &= ~(1 << 24);
+ mmio_write_32(IMX_GPC_BASE + GPC_IMR1_CORE0_A53 + 0x8, val);
+ }
}
static void imx_gpc_set_wake_irq(uint32_t hwirq, uint32_t on)
@@ -864,11 +910,6 @@ void imx_gpc_init(void)
val &= ~(0x3 << 1);
mmio_write_32(IMX_GPC_BASE + MST_CPU_MAPPING, val);
- /* mask M4 DSM trigger if M4 is NOT enabled */
- val = mmio_read_32(IMX_GPC_BASE + LPCR_M4);
- val |= 1 << 31;
- mmio_write_32(IMX_GPC_BASE + LPCR_M4, val);
-
/*set all mix/PU in A53 domain */
mmio_write_32(IMX_GPC_BASE + GPC_PGC_CPU_0_1_MAPPING, 0xffff);
diff --git a/plat/imx/imx8mm/imx8mm_bl31_setup.c b/plat/imx/imx8mm/imx8mm_bl31_setup.c
index 587b74dd..9b3145c4 100644
--- a/plat/imx/imx8mm/imx8mm_bl31_setup.c
+++ b/plat/imx/imx8mm/imx8mm_bl31_setup.c
@@ -234,6 +234,11 @@ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
#endif
bl31_tzc380_setup();
+ /* Assign M4 to domain 1 */
+ mmio_write_32(IMX_RDC_BASE + 0x204, 0x1);
+ mmio_write_32(IMX_RDC_BASE + 0x518, 0xfc);
+ mmio_write_32(IMX_RDC_BASE + 0x5A4, 0xf3);
+
#if defined (CSU_RDC_TEST)
csu_test();
rdc_test();
diff --git a/plat/imx/imx8mm/imx8mm_psci.c b/plat/imx/imx8mm/imx8mm_psci.c
index eb82ec33..ec3a8c1a 100644
--- a/plat/imx/imx8mm/imx8mm_psci.c
+++ b/plat/imx/imx8mm/imx8mm_psci.c
@@ -130,7 +130,8 @@ void imx_domain_suspend(const psci_power_state_t *target_state)
/* do system level power mode setting */
if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) {
- dram_enter_retention();
+ if (!imx_is_m4_enabled() || !imx_m4_lpa_active())
+ dram_enter_retention();
imx_set_sys_lpm(true);
imx_anamix_pre_suspend();
noc_wrapper_pre_suspend(core_id);
@@ -151,7 +152,8 @@ void imx_domain_suspend_finish(const psci_power_state_t *target_state)
imx_set_sys_wakeup(core_id, false);
imx_anamix_post_resume();
imx_clear_rbc_count();
- dram_exit_retention();
+ if (!imx_is_m4_enabled() || !imx_m4_lpa_active())
+ dram_exit_retention();
noc_wrapper_post_resume(core_id);
}
diff --git a/plat/imx/imx8mm/include/soc.h b/plat/imx/imx8mm/include/soc.h
index 475b0bc8..00052d32 100644
--- a/plat/imx/imx8mm/include/soc.h
+++ b/plat/imx/imx8mm/include/soc.h
@@ -7,6 +7,8 @@
#ifndef __IMX_SOC_H
#define __IMX_SOC_H
+#include <stdbool.h>
+
void imx_gpc_set_m_core_pgc(unsigned int cpu, bool pdn);
void imx_anamix_pre_suspend(void);
void imx_anamix_post_resume(void);
@@ -30,4 +32,7 @@ void noc_wrapper_post_resume(unsigned int proc_num);
void ddrc_enter_retention(void);
void ddrc_exit_retention(void);
+bool imx_is_m4_enabled(void);
+bool imx_m4_lpa_active(void);
+
#endif /* __IMX_SOC_H */