aboutsummaryrefslogtreecommitdiff
path: root/plat/hisilicon/poplar/plat_pm.c
blob: eccb0b0d8cc864d31bbc5d57f71a6eec1d5fb514 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
/*
 * Copyright (c) 2017-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 <context.h>
#include <context_mgmt.h>
#include <debug.h>
#include <mmio.h>
#include <platform.h>
#include <platform_def.h>
#include <psci.h>
#include "hi3798cv200.h"
#include "plat_private.h"

#define REG_PERI_CPU_RVBARADDR		0xF8A80034
#define REG_PERI_CPU_AARCH_MODE		0xF8A80030

#define REG_CPU_LP_CPU_SW_BEGIN		10
#define CPU_REG_COREPO_SRST		12
#define CPU_REG_CORE_SRST		8

static void poplar_cpu_standby(plat_local_state_t cpu_state)
{
	dsb();
	wfi();
}

static int poplar_pwr_domain_on(u_register_t mpidr)
{
	unsigned int cpu = plat_core_pos_by_mpidr(mpidr);
	unsigned int regval, regval_bak;

	/* Select 400MHz before start slave cores */
	regval_bak = mmio_read_32((uintptr_t)(REG_BASE_CRG + REG_CPU_LP));
	mmio_write_32((uintptr_t)(REG_BASE_CRG + REG_CPU_LP), 0x206);
	mmio_write_32((uintptr_t)(REG_BASE_CRG + REG_CPU_LP), 0x606);

	/* Clear the slave cpu arm_por_srst_req reset */
	regval = mmio_read_32((uintptr_t)(REG_BASE_CRG + REG_CPU_RST));
	regval &= ~(1 << (cpu + CPU_REG_COREPO_SRST));
	mmio_write_32((uintptr_t)(REG_BASE_CRG + REG_CPU_RST), regval);

	/* Clear the slave cpu reset */
	regval = mmio_read_32((uintptr_t)(REG_BASE_CRG + REG_CPU_RST));
	regval &= ~(1 << (cpu + CPU_REG_CORE_SRST));
	mmio_write_32((uintptr_t)(REG_BASE_CRG + REG_CPU_RST), regval);

	/* Restore cpu frequency */
	regval = regval_bak & (~(1 << REG_CPU_LP_CPU_SW_BEGIN));
	mmio_write_32((uintptr_t)(REG_BASE_CRG + REG_CPU_LP), regval);
	mmio_write_32((uintptr_t)(REG_BASE_CRG + REG_CPU_LP), regval_bak);

	return PSCI_E_SUCCESS;
}

static void poplar_pwr_domain_off(const psci_power_state_t *target_state)
{
	assert(0);
}

static void poplar_pwr_domain_suspend(const psci_power_state_t *target_state)
{
	assert(0);
}

static void poplar_pwr_domain_on_finish(const psci_power_state_t *target_state)
{
	assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] ==
					PLAT_MAX_OFF_STATE);

	/* Enable the gic cpu interface */
	poplar_gic_pcpu_init();

	/* Program the gic per-cpu distributor or re-distributor interface */
	poplar_gic_cpuif_enable();
}

static void poplar_pwr_domain_suspend_finish(
		const psci_power_state_t *target_state)
{
	assert(0);
}

static void __dead2 poplar_system_off(void)
{
	ERROR("Poplar System Off: operation not handled.\n");
	panic();
}

static void __dead2 poplar_system_reset(void)
{
	mmio_write_32((uintptr_t)(HISI_WDG0_BASE + 0xc00), 0x1ACCE551);
	mmio_write_32((uintptr_t)(HISI_WDG0_BASE + 0x0),   0x00000100);
	mmio_write_32((uintptr_t)(HISI_WDG0_BASE + 0x8),   0x00000003);

	wfi();
	ERROR("Poplar System Reset: operation not handled.\n");
	panic();
}

static int32_t poplar_validate_power_state(unsigned int power_state,
					   psci_power_state_t *req_state)
{
	VERBOSE("%s: power_state: 0x%x\n", __func__, power_state);

	int pstate = psci_get_pstate_type(power_state);

	assert(req_state);

	/* Sanity check the requested state */
	if (pstate == PSTATE_TYPE_STANDBY)
		req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE;
	else
		req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_OFF_STATE;

	/* We expect the 'state id' to be zero */
	if (psci_get_pstate_id(power_state))
		return PSCI_E_INVALID_PARAMS;

	return PSCI_E_SUCCESS;
}

static int poplar_validate_ns_entrypoint(uintptr_t entrypoint)
{
	/*
	 * Check if the non secure entrypoint lies within the non
	 * secure DRAM.
	 */
	if ((entrypoint >= DDR_BASE) && (entrypoint < (DDR_BASE + DDR_SIZE)))
		return PSCI_E_SUCCESS;

	return PSCI_E_INVALID_ADDRESS;
}

static void poplar_get_sys_suspend_power_state(psci_power_state_t *req_state)
{
	int i;

	for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++)
		req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
}

static const plat_psci_ops_t poplar_plat_psci_ops = {
	.cpu_standby			= poplar_cpu_standby,
	.pwr_domain_on			= poplar_pwr_domain_on,
	.pwr_domain_off			= poplar_pwr_domain_off,
	.pwr_domain_suspend		= poplar_pwr_domain_suspend,
	.pwr_domain_on_finish		= poplar_pwr_domain_on_finish,
	.pwr_domain_suspend_finish	= poplar_pwr_domain_suspend_finish,
	.system_off			= poplar_system_off,
	.system_reset			= poplar_system_reset,
	.validate_power_state		= poplar_validate_power_state,
	.validate_ns_entrypoint		= poplar_validate_ns_entrypoint,
	.get_sys_suspend_power_state	= poplar_get_sys_suspend_power_state,
};

int plat_setup_psci_ops(uintptr_t sec_entrypoint,
			const plat_psci_ops_t **psci_ops)
{
	*psci_ops = &poplar_plat_psci_ops;

	mmio_write_32((uintptr_t)REG_PERI_CPU_AARCH_MODE, 0xF);
	mmio_write_32((uintptr_t)REG_PERI_CPU_RVBARADDR, sec_entrypoint);
	return 0;
}