blob: 3f23f686eaf5e3c31692ad715267e263d4c0b907 [file] [log] [blame]
Jacky Bai4d93d1d2020-07-02 14:39:58 +08001/*
2 * Copyright 2021-2024 NXP
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <stdbool.h>
8
9#include <arch.h>
10#include <arch_helpers.h>
11#include <common/debug.h>
12#include <drivers/arm/gicv3.h>
13#include <lib/mmio.h>
14#include <lib/psci/psci.h>
15
16#include <plat_imx8.h>
17
18static uintptr_t secure_entrypoint;
19
20#define CORE_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL0])
21#define CLUSTER_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL1])
22#define SYSTEM_PWR_STATE(state) ((state)->pwr_domain_state[PLAT_MAX_PWR_LVL])
23
24#define RVBARADDRx(c) (IMX_SIM1_BASE + 0x5c + 0x4 * (c))
25#define WKPUx(c) (IMX_SIM1_BASE + 0x3c + 0x4 * (c))
26#define AD_COREx_LPMODE(c) (IMX_CMC1_BASE + 0x50 + 0x4 * (c))
27
28static int imx_pwr_set_cpu_entry(unsigned int cpu, unsigned int entry)
29{
30 mmio_write_32(RVBARADDRx(cpu), entry);
31
32 /* set update bit */
33 mmio_write_32(IMX_SIM1_BASE + 0x8, mmio_read_32(IMX_SIM1_BASE + 0x8) | BIT_32(24 + cpu));
34 /* wait for ack */
35 while (!(mmio_read_32(IMX_SIM1_BASE + 0x8) & BIT_32(26 + cpu))) {
36 }
37
38 /* clear update bit */
39 mmio_write_32(IMX_SIM1_BASE + 0x8, mmio_read_32(IMX_SIM1_BASE + 0x8) & ~BIT_32(24 + cpu));
40 /* clear ack bit */
41 mmio_write_32(IMX_SIM1_BASE + 0x8, mmio_read_32(IMX_SIM1_BASE + 0x8) | BIT_32(26 + cpu));
42
43 return 0;
44}
45
46int imx_pwr_domain_on(u_register_t mpidr)
47{
48 unsigned int cpu = MPIDR_AFFLVL0_VAL(mpidr);
49
50 imx_pwr_set_cpu_entry(cpu, secure_entrypoint);
51
52 mmio_write_32(IMX_CMC1_BASE + 0x18, 0x3f);
53 mmio_write_32(IMX_CMC1_BASE + 0x50 + 0x4 * cpu, 0);
54
55 /* enable wku wakeup for idle */
56 mmio_write_32(IMX_SIM1_BASE + 0x3c + 0x4 * cpu, 0xffffffff);
57
58 return PSCI_E_SUCCESS;
59}
60
61void imx_pwr_domain_on_finish(const psci_power_state_t *target_state)
62{
63 imx_pwr_set_cpu_entry(0, IMX_ROM_ENTRY);
64 plat_gic_pcpu_init();
65 plat_gic_cpuif_enable();
66}
67
68int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint)
69{
70 return PSCI_E_SUCCESS;
71}
72
73void imx_pwr_domain_off(const psci_power_state_t *target_state)
74{
75 unsigned int cpu = MPIDR_AFFLVL0_VAL(read_mpidr_el1());
76
77 plat_gic_cpuif_disable();
78
79 /* disable wakeup */
80 mmio_write_32(WKPUx(cpu), 0);
81
82 mmio_write_32(AD_COREx_LPMODE(cpu), 0x3);
83}
84
85void __dead2 imx8ulp_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state)
86{
87 while (1) {
88 wfi();
89 }
90}
91
92void __dead2 imx8ulp_system_reset(void)
93{
94 imx_pwr_set_cpu_entry(0, IMX_ROM_ENTRY);
95
96 /* Write invalid command to WDOG CNT to trigger reset */
97 mmio_write_32(IMX_WDOG3_BASE + 0x4, 0x12345678);
98
99 while (true) {
100 wfi();
101 }
102}
103
104static const plat_psci_ops_t imx_plat_psci_ops = {
105 .pwr_domain_on = imx_pwr_domain_on,
106 .pwr_domain_on_finish = imx_pwr_domain_on_finish,
107 .validate_ns_entrypoint = imx_validate_ns_entrypoint,
108 .system_reset = imx8ulp_system_reset,
109 .pwr_domain_off = imx_pwr_domain_off,
110 .pwr_domain_pwr_down_wfi = imx8ulp_pwr_domain_pwr_down_wfi,
111};
112
113int plat_setup_psci_ops(uintptr_t sec_entrypoint,
114 const plat_psci_ops_t **psci_ops)
115{
116 secure_entrypoint = sec_entrypoint;
117 imx_pwr_set_cpu_entry(0, sec_entrypoint);
118 *psci_ops = &imx_plat_psci_ops;
119
120 mmio_write_32(IMX_CMC1_BASE + 0x18, 0x3f);
121 mmio_write_32(IMX_SIM1_BASE + 0x3c, 0xffffffff);
122
123 return 0;
124}