mss_pm_ipc.c 2.08 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
/*
 * Copyright (C) 2018 Marvell International Ltd.
 *
 * SPDX-License-Identifier:     BSD-3-Clause
 * https://spdx.org/licenses
 */

#include <debug.h>
#include <mmio.h>
#include <psci.h>
#include <string.h>

#include <mss_pm_ipc.h>

/*
 * SISR is 32 bit interrupt register representing 32 interrupts
 *
 * +======+=============+=============+
 * + Bits + 31          + 30 - 00     +
 * +======+=============+=============+
 * + Desc + MSS Msg Int + Reserved    +
 * +======+=============+=============+
 */
#define MSS_SISR		(MVEBU_REGS_BASE + 0x5800D0)
#define MSS_SISTR		(MVEBU_REGS_BASE + 0x5800D8)

#define MSS_MSG_INT_MASK	(0x80000000)
#define MSS_TIMER_BASE		(MVEBU_REGS_BASE_MASK + 0x580110)
#define MSS_TRIGGER_TIMEOUT	(1000)

/*****************************************************************************
 * mss_pm_ipc_msg_send
 *
 * DESCRIPTION: create and transmit IPC message
 *****************************************************************************
 */
int mss_pm_ipc_msg_send(unsigned int channel_id, unsigned int msg_id,
			const psci_power_state_t *target_state)
{
	/* Transmit IPC message */
#ifndef DISABLE_CLUSTER_LEVEL
	mv_pm_ipc_msg_tx(channel_id, msg_id,
			 (unsigned int)target_state->pwr_domain_state[
					MPIDR_AFFLVL1]);
#else
	mv_pm_ipc_msg_tx(channel_id, msg_id, 0);
#endif

	return 0;
}

/*****************************************************************************
 * mss_pm_ipc_msg_trigger
 *
 * DESCRIPTION: Trigger IPC message interrupt to MSS
 *****************************************************************************
 */
int mss_pm_ipc_msg_trigger(void)
{
	unsigned int timeout;
	unsigned int t_end;
	unsigned int t_start = mmio_read_32(MSS_TIMER_BASE);

	mmio_write_32(MSS_SISR, MSS_MSG_INT_MASK);

	do {
		/* wait while SCP process incoming interrupt */
		if (mmio_read_32(MSS_SISTR) != MSS_MSG_INT_MASK)
			break;

		/* check timeout */
		t_end = mmio_read_32(MSS_TIMER_BASE);

		timeout = ((t_start > t_end) ?
			   (t_start - t_end) : (t_end - t_start));
		if (timeout > MSS_TRIGGER_TIMEOUT) {
			ERROR("PM MSG Trigger Timeout\n");
			break;
		}

	} while (1);

	return 0;
}