ls1043_psci.c 4.17 KB
Newer Older
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
/*
 * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <arch_helpers.h>
#include <debug.h>
#include <errno.h>
#include <assert.h>
#include <platform.h>
#include <psci.h>
#include <mmio.h>
#include <sys/endian.h>
#include <gicv2.h>
#include <delay_timer.h>
#include "platform_def.h"

#define LS_SCFG_BASE			0x01570000
/* register to store warm boot entry, big endian, higher 32bit */
#define LS_SCFG_SCRATCHRW0_OFFSET	     0x600
/* register to store warm boot entry, big endian, lower 32bit */
#define LS_SCFG_SCRATCHRW1_OFFSET	     0x604
#define LS_SCFG_COREBCR_OFFSET		     0x680

#define LS_DCFG_BASE			0x01EE0000
#define LS_DCFG_RSTCR_OFFSET		     0x0B0
#define LS_DCFG_RSTRQMR1_OFFSET		     0x0C0
#define LS_DCFG_BRR_OFFSET		     0x0E4

#define LS_SCFG_CORE0_SFT_RST_OFFSET		0x130
#define LS_SCFG_CORE1_SFT_RST_OFFSET		0x134
#define LS_SCFG_CORE2_SFT_RST_OFFSET		0x138
#define LS_SCFG_CORE3_SFT_RST_OFFSET		0x13C

#define LS_SCFG_CORESRENCR_OFFSET		0x204

#define LS_SCFG_RVBAR0_0_OFFSET			0x220
#define LS_SCFG_RVBAR0_1_OFFSET			0x224

#define LS_SCFG_RVBAR1_0_OFFSET			0x228
#define LS_SCFG_RVBAR1_1_OFFSET			0x22C

#define LS_SCFG_RVBAR2_0_OFFSET			0x230
#define LS_SCFG_RVBAR2_1_OFFSET			0x234

#define LS_SCFG_RVBAR3_0_OFFSET			0x238
#define LS_SCFG_RVBAR3_1_OFFSET			0x23C

/* the entry for core warm boot */
static uintptr_t warmboot_entry;

/* warm reset single core */
static void ls1043_reset_core(int core_pos)
{
	assert(core_pos >= 0 && core_pos < PLATFORM_CORE_COUNT);

	/* set 0 in RVBAR, boot from bootrom at 0x0 */
	mmio_write_32(LS_SCFG_BASE + LS_SCFG_RVBAR0_0_OFFSET + core_pos * 8,
		      0);
	mmio_write_32(LS_SCFG_BASE + LS_SCFG_RVBAR0_1_OFFSET + core_pos * 8,
		      0);

	dsb();
	/* enable core soft reset */
	mmio_write_32(LS_SCFG_BASE + LS_SCFG_CORESRENCR_OFFSET,
		      htobe32(1 << 31));
	dsb();
	isb();
	/* reset core */
	mmio_write_32(LS_SCFG_BASE + LS_SCFG_CORE0_SFT_RST_OFFSET +
			core_pos * 4, htobe32(1 << 31));
	mdelay(10);
}

static void __dead2 ls1043_system_reset(void)
{
	/* clear reset request mask bits */
	mmio_write_32(LS_DCFG_BASE + LS_DCFG_RSTRQMR1_OFFSET, 0);

	/* set reset request bit */
	mmio_write_32(LS_DCFG_BASE + LS_DCFG_RSTCR_OFFSET,
		      htobe32((uint32_t)0x2));

	/* system will reset; if fail, enter wfi */
	dsb();
	isb();
	wfi();

	panic();
}


static int ls1043_pwr_domain_on(u_register_t mpidr)
{
	int core_pos = plat_core_pos_by_mpidr(mpidr);
97
	uint32_t core_mask, brr;
98
99

	assert(core_pos >= 0 && core_pos < PLATFORM_CORE_COUNT);
100
	core_mask = 1 << core_pos;
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

	/* set warm boot entry */
	mmio_write_32(LS_SCFG_BASE + LS_SCFG_SCRATCHRW0_OFFSET,
		htobe32((uint32_t)(warmboot_entry >> 32)));

	mmio_write_32(LS_SCFG_BASE + LS_SCFG_SCRATCHRW1_OFFSET,
		htobe32((uint32_t)warmboot_entry));

	dsb();

	brr = be32toh(mmio_read_32(LS_DCFG_BASE + LS_DCFG_BRR_OFFSET));
	if (brr & core_mask) {
		/* core has been released, must reset it to restart */
		ls1043_reset_core(core_pos);

		/* set bit in core boot control register to enable boot */
		mmio_write_32(LS_SCFG_BASE + LS_SCFG_COREBCR_OFFSET,
			htobe32(core_mask));

	} else {
		/* set bit in core boot control register to enable boot */
		mmio_write_32(LS_SCFG_BASE + LS_SCFG_COREBCR_OFFSET,
			htobe32(core_mask));

		/* release core */
		mmio_write_32(LS_DCFG_BASE + LS_DCFG_BRR_OFFSET,
			      htobe32(brr | core_mask));
	}

	mdelay(20);

	/* wake core in case it is in wfe */
	dsb();
	isb();
	sev();

	return PSCI_E_SUCCESS;
}

static void ls1043_pwr_domain_on_finish(const psci_power_state_t *target_state)
{
	/* Per cpu gic distributor setup */
	gicv2_pcpu_distif_init();

	/* Enable the gic CPU interface */
	gicv2_cpuif_enable();
}

static void ls1043_pwr_domain_off(const psci_power_state_t *target_state)
{
	/* Disable the gic CPU interface */
	gicv2_cpuif_disable();
}

static plat_psci_ops_t ls1043_psci_pm_ops = {
	.system_reset = ls1043_system_reset,
	.pwr_domain_on = ls1043_pwr_domain_on,
	.pwr_domain_on_finish = ls1043_pwr_domain_on_finish,
	.pwr_domain_off = ls1043_pwr_domain_off,
};

int plat_setup_psci_ops(uintptr_t sec_entrypoint,
			const plat_psci_ops_t **psci_ops)
{
	warmboot_entry = sec_entrypoint;
	*psci_ops = &ls1043_psci_pm_ops;
	return 0;
}