Commit 81136819 authored by Bai Ping's avatar Bai Ping
Browse files

plat: imx: Add i.MX8MQ basic support



i.MX8MQ is new SOC of NXP's i.MX8M family based on
A53. It can provide industry-leading audio, voice
and video processing for applications that scale
from consumer home audio to industrial building
automation and mobile computers

this patchset add the basic supoort to boot up
the 4 X A53. more feature will be added later.
Signed-off-by: default avatarBai Ping <ping.bai@nxp.com>
parent 46f9b2c3
Description
===========
The i.MX 8M family of applications processors based on Arm Corte-A53 and Cortex-M4
cores provide high-performance computing, power efficiency, enhanced system
reliability and embedded security needed to drive the growth of fast-growing
edge node computing, streaming multimedia, and machine learning applications.
Boot Sequence
=============
Bootrom --> SPL --> BL31 --> BL33(u-boot) --> Linux kernel
How to build
============
Build Procedure
---------------
- Prepare AARCH64 toolchain.
- Build spl and u-boot firstly, and get binary images: u-boot-spl.bin,
u-boot-nodtb.bin and dtb for the target board.
- Build TF-A
Build bl31:
.. code:: shell
CROSS_COMPILE=aarch64-linux-gnu- make PLAT=<Target_SoC> bl31
Target_SoC should be "imx8mq" for i.MX8MQ SoC.
Deploy TF-A Images
-----------------
TF-A binary(bl31.bin), u-boot-spl.bin u-boot-nodtb.bin and dtb are combined
together to generate a binary file called flash.bin, the imx-mkimage tool is
used to generate flash.bin, and flash.bin needs to be flashed into SD card
with certain offset for BOOT ROM. the u-boot and imx-mkimage will be upstreamed
soon, this doc will be updated once they are ready, and the link will be posted.
/*
* Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <asm_macros.S>
#define USE_FINISH_CONSOLE_REG_2
#include <console_macros.S>
#include <assert_macros.S>
#include "imx_uart.h"
#define URXD 0x0 /* Receiver Register */
#define UTXD 0x40 /* Transmitter Register */
#define UTS 0xb4 /* UART Test Register (mx31) */
#define URXD_RX_DATA (0xFF)
.globl console_uart_register
.globl console_uart_init
.globl console_uart_putc
.globl console_uart_getc
func console_imx_uart_register
mov x7, x30
mov x6, x3
cbz x6, register_fail
str x0, [x6, #CONSOLE_T_DRVDATA]
bl console_imx_uart_init
cbz x0, register_fail
mov x0, x6
mov x30, x7
finish_console_register imx_uart putc=1, getc=1
register_fail:
ret x7
endfunc console_imx_uart_register
func console_imx_uart_init
mov w0, #1
ret
endfunc console_imx_uart_init
func console_imx_uart_putc
ldr x1, [x1, #CONSOLE_T_DRVDATA]
cbz x1, putc_error
/* Prepare '\r' to '\n' */
cmp w0, #0xA
b.ne 2f
1:
/* Check if the transmit FIFO is full */
ldr w2, [x1, #UTS]
tbz w2, #6, 1b
mov w2, #0xD
str w2, [x1, #UTXD]
2:
/* Check if the transmit FIFO is full */
ldr w2, [x1, #UTS]
tbz w2, #6, 2b
str w0, [x1, #UTXD]
ret
putc_error:
mov w0, #-1
ret
endfunc console_imx_uart_putc
func console_imx_uart_getc
ldr x0, [x0, #CONSOLE_T_DRVDATA]
cbz x0, getc_error
1:
ldr w1, [x0, #UTS]
tbnz w1, #5, 1b
ldr w1, [x0, #URXD]
and w0, w1, #URXD_RX_DATA
ret
getc_error:
mov w0, #-1
ret
endfunc console_imx_uart_getc
/*
* Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef IMX_UART_H
#define IMX_UART_H
#include <console.h>
#ifndef __ASSEMBLY__
typedef struct {
console_t console;
uintptr_t base;
} console_uart_t;
int console_uart_register(uintptr_t baseaddr, uint32_t clock, uint32_t baud,
console_uart_t *console);
#endif /*__ASSEMBLY__*/
#endif /* IMX_UART_H */
/*
* Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <debug.h>
#include <gpc.h>
#include <mmio.h>
#include <platform_def.h>
#include <psci.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <std_svc.h>
void imx_set_cpu_secure_entry(unsigned int core_id, uintptr_t sec_entrypoint)
{
uint64_t temp_base;
temp_base = (uint64_t) sec_entrypoint;
temp_base >>= 2;
mmio_write_32(IMX_SRC_BASE + SRC_GPR1_OFFSET + (core_id << 3),
((uint32_t)(temp_base >> 22) & 0xffff));
mmio_write_32(IMX_SRC_BASE + SRC_GPR1_OFFSET + (core_id << 3) + 4,
((uint32_t)temp_base & 0x003fffff));
}
/* use wfi power down the core */
void imx_set_cpu_pwr_off(unsigned int core_id)
{
/* enable the wfi power down of the core */
mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id) |
(1 << (core_id + 20)));
/* assert the pcg pcr bit of the core */
mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1);
};
/* use the sw method to power up the core */
void imx_set_cpu_pwr_on(unsigned int core_id)
{
/* clear the wfi power down bit of the core */
mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id));
/* assert the ncpuporeset */
mmio_clrbits_32(IMX_SRC_BASE + SRC_A53RCR1, (1 << core_id));
/* assert the pcg pcr bit of the core */
mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1);
/* sw power up the core */
mmio_setbits_32(IMX_GPC_BASE + CPU_PGC_UP_TRG, (1 << core_id));
/* wait for the power up finished */
while ((mmio_read_32(IMX_GPC_BASE + CPU_PGC_UP_TRG) & (1 << core_id)) != 0)
;
/* deassert the pcg pcr bit of the core */
mmio_clrbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1);
/* deassert the ncpuporeset */
mmio_setbits_32(IMX_SRC_BASE + SRC_A53RCR1, (1 << core_id));
}
/* if out of lpm, we need to do reverse steps */
void imx_set_cpu_lpm(unsigned int core_id, bool pdn)
{
if (pdn) {
/* enable the core WFI PDN & IRQ PUP */
mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id) |
(1 << (core_id + 20)) | COREx_IRQ_WUP(core_id));
/* assert the pcg pcr bit of the core */
mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1);
} else {
/* disable CORE WFI PDN & IRQ PUP */
mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id) |
COREx_IRQ_WUP(core_id));
/* deassert the pcg pcr bit of the core */
mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1);
}
}
void imx_set_sys_wakeup(unsigned int last_core, bool pdn)
{
/* TODO */
}
void imx_pup_pdn_slot_config(int last_core, bool pdn)
{
if (pdn) {
/* SLOT0 for A53 PLAT power down */
mmio_setbits_32(IMX_GPC_BASE + SLTx_CFG(0), SLT_PLAT_PDN);
/* SLOT1 for A53 PLAT power up */
mmio_setbits_32(IMX_GPC_BASE + SLTx_CFG(1), SLT_PLAT_PUP);
/* SLOT2 for A53 primary core power up */
mmio_setbits_32(IMX_GPC_BASE + SLTx_CFG(2), SLT_COREx_PUP(last_core));
/* ACK setting: PLAT ACK for PDN, CORE ACK for PUP */
mmio_clrsetbits_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, 0xFFFFFFFF,
A53_PLAT_PDN_ACK | A53_PLAT_PUP_ACK);
} else {
mmio_clrbits_32(IMX_GPC_BASE + SLTx_CFG(0), 0xFFFFFFFF);
mmio_clrbits_32(IMX_GPC_BASE + SLTx_CFG(1), 0xFFFFFFFF);
mmio_clrbits_32(IMX_GPC_BASE + SLTx_CFG(2), 0xFFFFFFFF);
mmio_clrsetbits_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, 0xFFFFFFFF,
A53_DUMMY_PDN_ACK | A53_DUMMY_PUP_ACK);
}
}
void imx_set_cluster_standby(bool retention)
{
/*
* Enable BIT 6 of A53 AD register to make sure system
* don't enter LPM mode.
*/
if (retention)
mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_AD, (1 << 6));
else
mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_AD, (1 << 6));
}
void imx_set_cluster_powerdown(unsigned int last_core, uint8_t power_state)
{
uint32_t val;
if (is_local_state_off(power_state)) {
val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC);
val |= A53_LPM_STOP; /* enable C0-C1's STOP mode */
val &= ~CPU_CLOCK_ON_LPM; /* disable CPU clock in LPM mode */
mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val);
/* enable C2-3's STOP mode */
mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_BSC2, A53_LPM_STOP);
/* enable PLAT/SCU power down */
val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_AD);
val &= ~EN_L2_WFI_PDN;
val |= L2PGE | EN_PLAT_PDN;
val &= ~COREx_IRQ_WUP(last_core); /* disable IRQ PUP for last core */
val |= COREx_LPM_PUP(last_core); /* enable LPM PUP for last core */
mmio_write_32(IMX_GPC_BASE + LPCR_A53_AD, val);
imx_pup_pdn_slot_config(last_core, true);
/* enable PLAT PGC */
mmio_setbits_32(IMX_GPC_BASE + A53_PLAT_PGC, 0x1);
} else {
/* clear PLAT PGC */
mmio_clrbits_32(IMX_GPC_BASE + A53_PLAT_PGC, 0x1);
/* clear the slot and ack for cluster power down */
imx_pup_pdn_slot_config(last_core, false);
val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC);
val &= ~A53_LPM_MASK; /* clear the C0~1 LPM */
val |= CPU_CLOCK_ON_LPM; /* disable cpu clock in LPM */
mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val);
/* set A53 LPM to RUN mode */
mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_BSC2, A53_LPM_MASK);
/* clear PLAT/SCU power down */
val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_AD);
val |= EN_L2_WFI_PDN;
val &= ~(L2PGE | EN_PLAT_PDN);
val &= ~COREx_LPM_PUP(last_core); /* disable C0's LPM PUP */
mmio_write_32(IMX_GPC_BASE + LPCR_A53_AD, val);
}
}
/* config the system level power mode */
void imx_set_sys_lpm(bool retention)
{
uint32_t val;
/* set system DSM mode SLPCR(0x14) */
val = mmio_read_32(IMX_GPC_BASE + SLPCR);
val &= ~(SLPCR_EN_DSM | SLPCR_VSTBY | SLPCR_SBYOS |
SLPCR_BYPASS_PMIC_READY | SLPCR_RBC_EN);
if (retention)
val |= (SLPCR_EN_DSM | SLPCR_VSTBY | SLPCR_SBYOS |
SLPCR_BYPASS_PMIC_READY | SLPCR_RBC_EN |
SLPCR_A53_FASTWUP_STOP_MODE);
mmio_write_32(IMX_GPC_BASE + SLPCR, val);
}
void imx_set_rbc_count(void)
{
mmio_setbits_32(IMX_GPC_BASE + SLPCR, 0x3f << SLPCR_RBC_COUNT_SHIFT);
}
void imx_clear_rbc_count(void)
{
mmio_clrbits_32(IMX_GPC_BASE + SLPCR, 0x3f << SLPCR_RBC_COUNT_SHIFT);
}
void imx_gpc_init(void)
{
uint32_t val;
int i;
/* mask all the interrupt by default */
/* Due to the hardware design requirement, need to make
* sure GPR interrupt(#32) is unmasked during RUN mode to
* avoid entering DSM mode by mistake.
*/
for (i = 0; i < 4; i++) {
mmio_write_32(IMX_GPC_BASE + IMR1_CORE0_A53 + i * 4, 0xFFFFFFFE);
mmio_write_32(IMX_GPC_BASE + IMR1_CORE1_A53 + i * 4, 0xFFFFFFFE);
mmio_write_32(IMX_GPC_BASE + IMR1_CORE2_A53 + i * 4, 0xFFFFFFFE);
mmio_write_32(IMX_GPC_BASE + IMR1_CORE3_A53 + i * 4, 0xFFFFFFFE);
mmio_write_32(IMX_GPC_BASE + IMR1_CORE0_M4 + i * 4, ~0x0);
}
/* use external IRQs to wakeup C0~C3 from LPM */
val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC);
val |= IRQ_SRC_A53_WUP;
/* clear the MASTER0 LPM handshake */
val &= ~MASTER0_LPM_HSK;
mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val);
/* mask M4 DSM trigger if M4 is NOT enabled */
mmio_setbits_32(IMX_GPC_BASE + LPCR_M4, DSM_MODE_MASK);
/* set all mix/PU in A53 domain */
mmio_write_32(IMX_GPC_BASE + PGC_CPU_0_1_MAPPING, 0xfffd);
/* set SCU timming */
mmio_write_32(IMX_GPC_BASE + PGC_SCU_TIMING,
(0x59 << 10) | 0x5B | (0x2 << 20));
/* set DUMMY PDN/PUP ACK by default for A53 domain */
mmio_write_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, A53_DUMMY_PUP_ACK |
A53_DUMMY_PDN_ACK);
/* disable DSM mode by default */
mmio_clrbits_32(IMX_GPC_BASE + SLPCR, DSM_MODE_MASK);
/*
* USB PHY power up needs to make sure RESET bit in SRC is clear,
* otherwise, the PU power up bit in GPC will NOT self-cleared.
* only need to do it once.
*/
mmio_clrbits_32(IMX_SRC_BASE + SRC_OTG1PHY_SCR, 0x1);
mmio_clrbits_32(IMX_SRC_BASE + SRC_OTG2PHY_SCR, 0x1);
}
/*
* Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <assert.h>
#include <bl_common.h>
#include <console.h>
#include <context.h>
#include <context_mgmt.h>
#include <debug.h>
#include <gpc.h>
#include <imx_uart.h>
#include <stdbool.h>
#include <mmio.h>
#include <platform.h>
#include <platform_def.h>
#include <plat_imx8.h>
#include <xlat_tables.h>
#include <tzc380.h>
IMPORT_SYM(uintptr_t, __COHERENT_RAM_START__, BL31_COHERENT_RAM_START);
IMPORT_SYM(uintptr_t, __COHERENT_RAM_END__, BL31_COHERENT_RAM_END);
IMPORT_SYM(uintptr_t, __RO_START__, BL31_RO_START);
IMPORT_SYM(uintptr_t, __RO_END__, BL31_RO_END);
IMPORT_SYM(uintptr_t, __RW_START__, BL31_RW_START);
IMPORT_SYM(uintptr_t, __RW_END__, BL31_RW_END);
static const mmap_region_t imx_mmap[] = {
MAP_REGION_FLAT(GPV_BASE, GPV_SIZE, MT_DEVICE | MT_RW), /* GPV map */
MAP_REGION_FLAT(IMX_AIPS_BASE, IMX_AIPS_SIZE, MT_DEVICE | MT_RW), /* AIPS map */
MAP_REGION_FLAT(IMX_GIC_BASE, IMX_GIC_SIZE, MT_DEVICE | MT_RW), /* GIC map */
{0},
};
static entry_point_info_t bl32_image_ep_info;
static entry_point_info_t bl33_image_ep_info;
/* get SPSR for BL33 entry */
static uint32_t get_spsr_for_bl33_entry(void)
{
unsigned long el_status;
unsigned long mode;
uint32_t spsr;
/* figure out what mode we enter the non-secure world */
el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT;
el_status &= ID_AA64PFR0_ELX_MASK;
mode = (el_status) ? MODE_EL2 : MODE_EL1;
spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
return spsr;
}
static void bl31_tz380_setup(void)
{
unsigned int val;
val = mmio_read_32(IMX_IOMUX_GPR_BASE + IOMUXC_GPR10);
if ((val & GPR_TZASC_EN) != GPR_TZASC_EN)
return;
tzc380_init(IMX_TZASC_BASE);
/*
* Need to substact offset 0x40000000 from CPU address when
* programming tzasc region for i.mx8mq. Enable 1G-5G S/NS RW
*/
tzc380_configure_region(0, 0x00000000, TZC_ATTR_REGION_SIZE(TZC_REGION_SIZE_4G) |
TZC_ATTR_REGION_EN_MASK | TZC_ATTR_SP_ALL);
}
void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
u_register_t arg2, u_register_t arg3)
{
int i;
/* enable CSU NS access permission */
for (i = 0; i < 64; i++) {
mmio_write_32(IMX_CSU_BASE + i * 4, 0xffffffff);
}
#if DEBUG_CONSOLE
static console_uart_t console;
console_uart_register(IMX_BOOT_UART_BASE, IMX_BOOT_UART_CLK_IN_HZ,
IMX_CONSOLE_BAUDRATE, &console);
#endif
/*
* tell BL3-1 where the non-secure software image is located
* and the entry state information.
*/
bl33_image_ep_info.pc = PLAT_NS_IMAGE_OFFSET;
bl33_image_ep_info.spsr = get_spsr_for_bl33_entry();
SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
bl31_tz380_setup();
}
void bl31_plat_arch_setup(void)
{
mmap_add_region(BL31_RO_START, BL31_RO_START, (BL31_RO_END - BL31_RO_START),
MT_MEMORY | MT_RO | MT_SECURE);
mmap_add_region(BL31_RW_START, BL31_RW_START, (BL31_RW_END - BL31_RW_START),
MT_MEMORY | MT_RW | MT_SECURE);
mmap_add(imx_mmap);
#if USE_COHERENT_MEM
mmap_add_region(BL31_COHERENT_RAM_START, BL31_COHERENT_RAM_START,
BL31_COHERENT_RAM_END - BL31_COHERENT_RAM_START,
MT_DEVICE | MT_RW | MT_SECURE);
#endif
/* setup xlat table */
init_xlat_tables();
/* enable the MMU */
enable_mmu_el3(0);
}
void bl31_platform_setup(void)
{
/* init the GICv3 cpu and distributor interface */
plat_gic_driver_init();
plat_gic_init();
/* gpc init */
imx_gpc_init();
}
entry_point_info_t *bl31_plat_get_next_image_ep_info(unsigned int type)
{
if (type == NON_SECURE)
return &bl33_image_ep_info;
if (type == SECURE)
return &bl32_image_ep_info;
return NULL;
}
unsigned int plat_get_syscnt_freq2(void)
{
return COUNTER_FREQUENCY;
}
void bl31_plat_runtime_setup(void)
{
return;
}
/*
* Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <arch_helpers.h>
#include <debug.h>
#include <gpc.h>
#include <stdbool.h>
#include <plat_imx8.h>
#include <psci.h>
#include <mmio.h>
#define CORE_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL0])
#define CLUSTER_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL1])
#define SYSTEM_PWR_STATE(state) ((state)->pwr_domain_state[PLAT_MAX_PWR_LVL])
int imx_pwr_domain_on(u_register_t mpidr)
{
unsigned int core_id;
uint64_t base_addr = BL31_BASE;
core_id = MPIDR_AFFLVL0_VAL(mpidr);
/* set the secure entrypoint */
imx_set_cpu_secure_entry(core_id, base_addr);
/* power up the core */
imx_set_cpu_pwr_on(core_id);
return PSCI_E_SUCCESS;
}
void imx_pwr_domain_on_finish(const psci_power_state_t *target_state)
{
/* program the GIC per cpu dist and rdist interface */
plat_gic_pcpu_init();
/* enable the GICv3 cpu interface */
plat_gic_cpuif_enable();
}
void imx_pwr_domain_off(const psci_power_state_t *target_state)
{
uint64_t mpidr = read_mpidr_el1();
unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr);
/* disable the GIC cpu interface first */
plat_gic_cpuif_disable();
/* config the core for power down */
imx_set_cpu_pwr_off(core_id);
}
int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint)
{
/* The non-secure entrypoint should be in RAM space */
if (ns_entrypoint < PLAT_NS_IMAGE_OFFSET)
return PSCI_E_INVALID_PARAMS;
return PSCI_E_SUCCESS;
}
int imx_validate_power_state(unsigned int power_state,
psci_power_state_t *req_state)
{
int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
int pwr_type = psci_get_pstate_type(power_state);
int state_id = psci_get_pstate_id(power_state);
if (pwr_lvl > PLAT_MAX_PWR_LVL)
return PSCI_E_INVALID_PARAMS;
if (pwr_type == PSTATE_TYPE_STANDBY) {
CORE_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
}
if (pwr_type == PSTATE_TYPE_POWERDOWN && state_id == 0x33) {
CORE_PWR_STATE(req_state) = PLAT_MAX_OFF_STATE;
CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
}
return PSCI_E_SUCCESS;
}
void imx_cpu_standby(plat_local_state_t cpu_state)
{
dsb();
write_scr_el3(read_scr_el3() | SCR_FIQ_BIT);
isb();
wfi();
write_scr_el3(read_scr_el3() & (~SCR_FIQ_BIT));
isb();
}
void imx_domain_suspend(const psci_power_state_t *target_state)
{
uint64_t base_addr = BL31_BASE;
uint64_t mpidr = read_mpidr_el1();
unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr);
if (is_local_state_off(CORE_PWR_STATE(target_state))) {
/* disable the cpu interface */
plat_gic_cpuif_disable();
imx_set_cpu_secure_entry(core_id, base_addr);
imx_set_cpu_lpm(core_id, true);
} else {
dsb();
write_scr_el3(read_scr_el3() | SCR_FIQ_BIT);
isb();
}
if (is_local_state_off(CLUSTER_PWR_STATE(target_state)))
imx_set_cluster_powerdown(core_id, true);
else
imx_set_cluster_standby(true);
if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) {
imx_set_sys_lpm(true);
}
}
void imx_domain_suspend_finish(const psci_power_state_t *target_state)
{
uint64_t mpidr = read_mpidr_el1();
unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr);
/* check the system level status */
if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) {
imx_set_sys_lpm(false);
imx_clear_rbc_count();
}
/* check the cluster level power status */
if (is_local_state_off(CLUSTER_PWR_STATE(target_state)))
imx_set_cluster_powerdown(core_id, false);
else
imx_set_cluster_standby(false);
/* check the core level power status */
if (is_local_state_off(CORE_PWR_STATE(target_state))) {
/* clear the core lpm setting */
imx_set_cpu_lpm(core_id, false);
/* enable the gic cpu interface */
plat_gic_cpuif_enable();
} else {
write_scr_el3(read_scr_el3() & (~0x4));
isb();
}
}
void imx_get_sys_suspend_power_state(psci_power_state_t *req_state)
{
unsigned int i;
for (i = IMX_PWR_LVL0; i < PLAT_MAX_PWR_LVL; i++)
req_state->pwr_domain_state[i] = PLAT_STOP_OFF_STATE;
req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PLAT_MAX_RET_STATE;
}
void __dead2 imx_system_reset(void)
{
uintptr_t wdog_base = IMX_WDOG_BASE;
unsigned int val;
/* WDOG_B reset */
val = mmio_read_16(wdog_base);
#ifdef IMX_WDOG_B_RESET
val = (val & 0x00FF) | WDOG_WCR_WDZST | WDOG_WCR_WDE |
WDOG_WCR_WDT | WDOG_WCR_SRS;
#else
val = (val & 0x00FF) | WDOG_WCR_WDZST | WDOG_WCR_SRS;
#endif
mmio_write_16(wdog_base, val);
mmio_write_16(wdog_base + WDOG_WSR, 0x5555);
mmio_write_16(wdog_base + WDOG_WSR, 0xaaaa);
while (1)
;
}
void __dead2 imx_system_off(void)
{
mmio_write_32(IMX_SNVS_BASE + SNVS_LPCR, SNVS_LPCR_SRTC_ENV |
SNVS_LPCR_DP_EN | SNVS_LPCR_TOP);
while (1)
;
}
void __dead2 imx_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state)
{
if (is_local_state_off(CLUSTER_PWR_STATE(target_state)))
imx_set_rbc_count();
while (1)
wfi();
}
static const plat_psci_ops_t imx_plat_psci_ops = {
.pwr_domain_on = imx_pwr_domain_on,
.pwr_domain_on_finish = imx_pwr_domain_on_finish,
.pwr_domain_off = imx_pwr_domain_off,
.validate_ns_entrypoint = imx_validate_ns_entrypoint,
.validate_power_state = imx_validate_power_state,
.cpu_standby = imx_cpu_standby,
.pwr_domain_suspend = imx_domain_suspend,
.pwr_domain_suspend_finish = imx_domain_suspend_finish,
.pwr_domain_pwr_down_wfi = imx_pwr_domain_pwr_down_wfi,
.get_sys_suspend_power_state = imx_get_sys_suspend_power_state,
.system_reset = imx_system_reset,
.system_off = imx_system_off,
};
/* export the platform specific psci ops */
int plat_setup_psci_ops(uintptr_t sec_entrypoint,
const plat_psci_ops_t **psci_ops)
{
imx_mailbox_init(sec_entrypoint);
/* sec_entrypoint is used for warm reset */
*psci_ops = &imx_plat_psci_ops;
return 0;
}
/*
* Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#define PLATFORM_LINKER_FORMAT "elf64-littleaarch64"
#define PLATFORM_LINKER_ARCH aarch64
#define PLATFORM_STACK_SIZE 0x800
#define CACHE_WRITEBACK_GRANULE 64
#define PLAT_PRIMARY_CPU 0x0
#define PLATFORM_MAX_CPU_PER_CLUSTER 4
#define PLATFORM_CLUSTER_COUNT 1
#define PLATFORM_CLUSTER0_CORE_COUNT 4
#define PLATFORM_CLUSTER1_CORE_COUNT 0
#define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER0_CORE_COUNT)
#define IMX_PWR_LVL0 MPIDR_AFFLVL0
#define IMX_PWR_LVL1 MPIDR_AFFLVL1
#define IMX_PWR_LVL2 MPIDR_AFFLVL2
#define PWR_DOMAIN_AT_MAX_LVL U(1)
#define PLAT_MAX_PWR_LVL U(2)
#define PLAT_MAX_OFF_STATE U(4)
#define PLAT_MAX_RET_STATE U(1)
#define PLAT_WAIT_OFF_STATE U(2)
#define PLAT_STOP_OFF_STATE U(3)
#define BL31_BASE U(0x910000)
#define BL31_LIMIT U(0x920000)
#define BL32_BASE U(0xfe000000)
/* non-secure uboot base */
#define PLAT_NS_IMAGE_OFFSET U(0x40200000)
/* GICv3 base address */
#define PLAT_GICD_BASE U(0x38800000)
#define PLAT_GICR_BASE U(0x38880000)
#define PLAT_VIRT_ADDR_SPACE_SIZE (1ull << 32)
#define PLAT_PHY_ADDR_SPACE_SIZE (1ull << 32)
#define MAX_XLAT_TABLES 4
#define MAX_MMAP_REGIONS 14
#define HAB_RVT_BASE U(0x00000880) /* HAB_RVT for i.MX8MQ */
#define IMX_BOOT_UART_BASE U(0x30860000)
#define IMX_BOOT_UART_CLK_IN_HZ 25000000 /* Select 25Mhz oscillator */
#define PLAT_CRASH_UART_BASE IMX_BOOT_UART_BASE
#define PLAT_CRASH_UART_CLK_IN_HZ 25000000
#define IMX_CONSOLE_BAUDRATE 115200
#define IMX_AIPS_BASE U(0x30200000)
#define IMX_AIPS_SIZE U(0xC00000)
#define IMX_AIPS1_BASE U(0x30200000)
#define IMX_AIPS3_ARB_BASE U(0x30800000)
#define IMX_ANAMIX_BASE U(0x30360000)
#define IMX_CCM_BASE U(0x30380000)
#define IMX_SRC_BASE U(0x30390000)
#define IMX_GPC_BASE U(0x303a0000)
#define IMX_RDC_BASE U(0x303d0000)
#define IMX_CSU_BASE U(0x303e0000)
#define IMX_WDOG_BASE U(0x30280000)
#define IMX_SNVS_BASE U(0x30370000)
#define IMX_NOC_BASE U(0x32700000)
#define IMX_TZASC_BASE U(0x32F80000)
#define IMX_IOMUX_GPR_BASE U(0x30340000)
#define IMX_DDRC_BASE U(0x3d400000)
#define IMX_DDRPHY_BASE U(0x3c000000)
#define IMX_DDR_IPS_BASE U(0x3d000000)
#define IMX_ROM_BASE U(0x00000000)
#define AIPSTZ1_BASE U(0x301f0000)
#define AIPSTZ2_BASE U(0x305f0000)
#define AIPSTZ3_BASE U(0x309f0000)
#define AIPSTZ4_BASE U(0x32df0000)
#define GPV_BASE U(0x32000000)
#define GPV_SIZE U(0x800000)
#define IMX_GIC_BASE PLAT_GICD_BASE
#define IMX_GIC_SIZE U(0x200000)
#define WDOG_WSR U(0x2)
#define WDOG_WCR_WDZST BIT(0)
#define WDOG_WCR_WDBG BIT(1)
#define WDOG_WCR_WDE BIT(2)
#define WDOG_WCR_WDT BIT(3)
#define WDOG_WCR_SRS BIT(4)
#define WDOG_WCR_WDA BIT(5)
#define WDOG_WCR_SRE BIT(6)
#define WDOG_WCR_WDW BIT(7)
#define SRC_A53RCR0 U(0x4)
#define SRC_A53RCR1 U(0x8)
#define SRC_OTG1PHY_SCR U(0x20)
#define SRC_OTG2PHY_SCR U(0x24)
#define SRC_GPR1_OFFSET U(0x74)
#define SNVS_LPCR U(0x38)
#define SNVS_LPCR_SRTC_ENV BIT(0)
#define SNVS_LPCR_DP_EN BIT(5)
#define SNVS_LPCR_TOP BIT(6)
#define IOMUXC_GPR10 U(0x28)
#define GPR_TZASC_EN BIT(0)
#define GPR_TZASC_EN_LOCK BIT(16)
#define OCRAM_S_BASE U(0x00180000)
#define OCRAM_S_SIZE U(0x8000)
#define OCRAM_S_LIMIT (OCRAM_S_BASE + OCRAM_S_SIZE)
#define COUNTER_FREQUENCY 8000000 /* 8MHz */
#define DEBUG_CONSOLE 0
#define IMX_WDOG_B_RESET
#define PLAT_IMX8M 1
#
# Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
PLAT_INCLUDES := -Iplat/imx/common/include \
-Iplat/imx/imx8m/include \
-Iplat/imx/imx8m/imx8mq/include
IMX_GIC_SOURCES := drivers/arm/gic/v3/gicv3_helpers.c \
drivers/arm/gic/v3/arm_gicv3_common.c \
drivers/arm/gic/v3/gic500.c \
drivers/arm/gic/v3/gicv3_main.c \
drivers/arm/gic/common/gic_common.c \
plat/common/plat_gicv3.c \
plat/common/plat_psci_common.c \
plat/imx/common/plat_imx8_gic.c
BL31_SOURCES += plat/imx/common/imx8_helpers.S \
plat/imx/imx8m/imx8mq/imx8mq_bl31_setup.c \
plat/imx/imx8m/imx8mq/imx8mq_psci.c \
plat/imx/imx8m/imx8mq/gpc.c \
plat/imx/common/imx8_topology.c \
plat/imx/common/imx_uart_console.S \
lib/xlat_tables/aarch64/xlat_tables.c \
lib/xlat_tables/xlat_tables_common.c \
lib/cpus/aarch64/cortex_a53.S \
drivers/console/aarch64/console.S \
drivers/arm/tzc/tzc380.c \
${IMX_GIC_SOURCES}
USE_COHERENT_MEM := 1
RESET_TO_BL31 := 1
A53_DISABLE_NON_TEMPORAL_HINT := 0
MULTI_CONSOLE_API := 1
/*
* Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef IMX8M_GPC_H
#define IMX8M_GPC_H
#define LPCR_A53_BSC 0x0
#define LPCR_A53_BSC2 0x108
#define LPCR_A53_AD 0x4
#define LPCR_M4 0x8
#define SLPCR 0x14
#define MST_CPU_MAPPING 0x18
#define MLPCR 0x20
#define PGC_ACK_SEL_A53 0x24
#define IMR1_CORE0_A53 0x30
#define IMR1_CORE1_A53 0x40
#define IMR1_CORE2_A53 0x1C0
#define IMR1_CORE3_A53 0x1D0
#define IMR1_CORE0_M4 0x50
#define SLT0_CFG 0xB0
#define GPC_PU_PWRHSK 0x1FC
#define PGC_CPU_0_1_MAPPING 0xEC
#define CPU_PGC_UP_TRG 0xF0
#define PU_PGC_UP_TRG 0xF8
#define CPU_PGC_DN_TRG 0xFC
#define PU_PGC_DN_TRG 0x104
#define A53_CORE0_PGC 0x800
#define A53_PLAT_PGC 0x900
#define PGC_SCU_TIMING 0x910
#define MASK_DSM_TRIGGER_A53 BIT(31)
#define IRQ_SRC_A53_WUP BIT(30)
#define IRQ_SRC_C1 BIT(29)
#define IRQ_SRC_C0 BIT(28)
#define IRQ_SRC_C3 BIT(23)
#define IRQ_SRC_C2 BIT(22)
#define CPU_CLOCK_ON_LPM BIT(14)
#define MASTER0_LPM_HSK BIT(6)
#define L2PGE BIT(31)
#define EN_L2_WFI_PDN BIT(5)
#define EN_PLAT_PDN BIT(4)
#define SLPCR_EN_DSM BIT(31)
#define SLPCR_RBC_EN BIT(30)
#define SLPCR_A53_FASTWUP_STOP_MODE BIT(17)
#define SLPCR_A53_FASTWUP_WAIT_MODE BIT(16)
#define SLPCR_VSTBY BIT(2)
#define SLPCR_SBYOS BIT(1)
#define SLPCR_BYPASS_PMIC_READY BIT(0)
#define SLPCR_RBC_COUNT_SHIFT 24
#define A53_DUMMY_PDN_ACK BIT(15)
#define A53_DUMMY_PUP_ACK BIT(31)
#define A53_PLAT_PDN_ACK BIT(2)
#define A53_PLAT_PUP_ACK BIT(18)
#define SLT_PLAT_PDN BIT(8)
#define SLT_PLAT_PUP BIT(9)
/* helper macro */
#define A53_LPM_MASK U(0xF)
#define A53_LPM_WAIT U(0x5)
#define A53_LPM_STOP U(0xA)
#define DSM_MODE_MASK BIT(31)
#define A53_CORE_WUP_SRC(core_id) (1 << ((core_id) < 2 ? 28 + (core_id) : 22 + (core_id) - 2))
#define COREx_PGC_PCR(core_id) (0x800 + (core_id) * 0x40)
#define COREx_WFI_PDN(core_id) (1 << ((core_id) < 2 ? (core_id) * 2 : ((core_id) - 2) * 2 + 16))
#define COREx_IRQ_WUP(core_id) ((core_id) < 2 ? (1 << ((core_id) * 2 + 8)) : (1 << ((core_id) * 2 + 20)))
#define COREx_LPM_PUP(core_id) ((core_id) < 2 ? (1 << ((core_id) * 2 + 9)) : (1 << ((core_id) * 2 + 21)))
#define SLTx_CFG(n) ((SLT0_CFG + ((n) * 4)))
#define SLT_COREx_PUP(core_id) (0x2 << ((core_id) * 2))
/* function declare */
void imx_gpc_init(void);
void imx_set_cpu_secure_entry(unsigned int core_index, uintptr_t sec_entrypoint);
void imx_set_cpu_pwr_off(unsigned int core_index);
void imx_set_cpu_pwr_on(unsigned int core_index);
void imx_set_cpu_lpm(unsigned int core_index, bool pdn);
void imx_set_cluster_standby(bool retention);
void imx_set_cluster_powerdown(unsigned int last_core, uint8_t power_state);
void imx_set_sys_lpm(bool retention);
void imx_set_rbc_count(void);
void imx_clear_rbc_count(void);
#endif /*IMX8M_GPC_H */
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment