xref: /rk3399_ARM-atf/plat/hisilicon/hikey960/drivers/ipc/hisi_ipc.c (revision 9a207532f8216bf83fed0891fed9ed0bc72ca450)
128b02e23SHaojian Zhuang /*
228b02e23SHaojian Zhuang  * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
328b02e23SHaojian Zhuang  *
428b02e23SHaojian Zhuang  * SPDX-License-Identifier: BSD-3-Clause
528b02e23SHaojian Zhuang  */
628b02e23SHaojian Zhuang 
728b02e23SHaojian Zhuang #include <assert.h>
8*09d40e0eSAntonio Nino Diaz 
928b02e23SHaojian Zhuang #include <platform_def.h>
1028b02e23SHaojian Zhuang 
11*09d40e0eSAntonio Nino Diaz #include <arch_helpers.h>
12*09d40e0eSAntonio Nino Diaz #include <common/debug.h>
13*09d40e0eSAntonio Nino Diaz #include <lib/mmio.h>
14*09d40e0eSAntonio Nino Diaz #include <plat/common/platform.h>
15*09d40e0eSAntonio Nino Diaz 
16*09d40e0eSAntonio Nino Diaz #include <hi3660.h>
17*09d40e0eSAntonio Nino Diaz #include <hisi_ipc.h>
1828b02e23SHaojian Zhuang #include "../../hikey960_private.h"
1928b02e23SHaojian Zhuang 
2028b02e23SHaojian Zhuang #define IPC_MBX_SOURCE_REG(m)		(IPC_BASE + ((m) << 6))
2128b02e23SHaojian Zhuang #define IPC_MBX_DSET_REG(m)		(IPC_BASE + ((m) << 6) + 0x04)
2228b02e23SHaojian Zhuang #define IPC_MBX_DCLEAR_REG(m)		(IPC_BASE + ((m) << 6) + 0x08)
2328b02e23SHaojian Zhuang #define IPC_MBX_DSTATUS_REG(m)		(IPC_BASE + ((m) << 6) + 0x0C)
2428b02e23SHaojian Zhuang #define IPC_MBX_MODE_REG(m)		(IPC_BASE + ((m) << 6) + 0x10)
2528b02e23SHaojian Zhuang #define IPC_MBX_IMASK_REG(m)		(IPC_BASE + ((m) << 6) + 0x14)
2628b02e23SHaojian Zhuang #define IPC_MBX_ICLR_REG(m)		(IPC_BASE + ((m) << 6) + 0x18)
2728b02e23SHaojian Zhuang #define IPC_MBX_SEND_REG(m)		(IPC_BASE + ((m) << 6) + 0x1C)
2828b02e23SHaojian Zhuang #define IPC_MBX_DATA_REG(m, d)		(IPC_BASE + ((m) << 6) + 0x20 + \
2928b02e23SHaojian Zhuang 					 ((d) * 4))
3028b02e23SHaojian Zhuang #define IPC_CPU_IMST_REG(m)		(IPC_BASE + ((m) << 3))
3128b02e23SHaojian Zhuang #define IPC_LOCK_REG			(IPC_BASE + 0xA00)
3228b02e23SHaojian Zhuang #define IPC_ACK_BIT_SHIFT		(1 << 7)
3328b02e23SHaojian Zhuang #define IPC_UNLOCK_VALUE		(0x1ACCE551)
3428b02e23SHaojian Zhuang 
3528b02e23SHaojian Zhuang /*********************************************************
3628b02e23SHaojian Zhuang  *bit[31:24]:0~AP
3728b02e23SHaojian Zhuang  *bit[23:16]:0x1~A15, 0x2~A7
3828b02e23SHaojian Zhuang  *bit[15:8]:0~ON, 1~OFF
3928b02e23SHaojian Zhuang  *bit[7:0]:0x3 cpu power mode
4028b02e23SHaojian Zhuang  *********************************************************/
4128b02e23SHaojian Zhuang #define IPC_CMD_TYPE(src_obj, cluster_obj, is_off, mode) \
4228b02e23SHaojian Zhuang 	((src_obj << 24) | (((cluster_obj) + 1) << 16) | (is_off << 8) | (mode))
4328b02e23SHaojian Zhuang 
4428b02e23SHaojian Zhuang /*********************************************************
4528b02e23SHaojian Zhuang  *bit[15:8]:0~no idle, 1~idle
4628b02e23SHaojian Zhuang  *bit[7:0]:cpux
4728b02e23SHaojian Zhuang  *********************************************************/
4828b02e23SHaojian Zhuang 
4928b02e23SHaojian Zhuang #define IPC_CMD_PARA(is_idle, cpu) \
5028b02e23SHaojian Zhuang 	((is_idle << 8) | (cpu))
5128b02e23SHaojian Zhuang 
5228b02e23SHaojian Zhuang #define IPC_STATE_IDLE			0x10
5328b02e23SHaojian Zhuang 
5428b02e23SHaojian Zhuang enum src_id {
5528b02e23SHaojian Zhuang 	SRC_IDLE = 0,
5628b02e23SHaojian Zhuang 	SRC_A15 = 1 << 0,
5728b02e23SHaojian Zhuang 	SRC_A7 = 1 << 1,
5828b02e23SHaojian Zhuang 	SRC_IOM3 = 1 << 2,
5928b02e23SHaojian Zhuang 	SRC_LPM3 = 1 << 3
6028b02e23SHaojian Zhuang };
6128b02e23SHaojian Zhuang 
6228b02e23SHaojian Zhuang /*lpm3's mailboxs are 13~17*/
6328b02e23SHaojian Zhuang enum lpm3_mbox_id {
6428b02e23SHaojian Zhuang 	LPM3_MBX0 = 13,
6528b02e23SHaojian Zhuang 	LPM3_MBX1,
6628b02e23SHaojian Zhuang 	LPM3_MBX2,
6728b02e23SHaojian Zhuang 	LPM3_MBX3,
6828b02e23SHaojian Zhuang 	LPM3_MBX4,
6928b02e23SHaojian Zhuang };
7028b02e23SHaojian Zhuang 
cpu_relax(void)7128b02e23SHaojian Zhuang static void cpu_relax(void)
7228b02e23SHaojian Zhuang {
7328b02e23SHaojian Zhuang 	volatile int i;
7428b02e23SHaojian Zhuang 
7528b02e23SHaojian Zhuang 	for (i = 0; i < 10; i++)
7628b02e23SHaojian Zhuang 		nop();
7728b02e23SHaojian Zhuang }
7828b02e23SHaojian Zhuang 
7928b02e23SHaojian Zhuang static inline void
hisi_ipc_clear_ack(enum src_id source,enum lpm3_mbox_id mbox)8028b02e23SHaojian Zhuang hisi_ipc_clear_ack(enum src_id source, enum lpm3_mbox_id mbox)
8128b02e23SHaojian Zhuang {
8228b02e23SHaojian Zhuang 	unsigned int int_status = 0;
8328b02e23SHaojian Zhuang 
8428b02e23SHaojian Zhuang 	do {
8528b02e23SHaojian Zhuang 		int_status = mmio_read_32(IPC_MBX_MODE_REG(mbox));
8628b02e23SHaojian Zhuang 		int_status &= 0xF0;
8728b02e23SHaojian Zhuang 		cpu_relax();
8828b02e23SHaojian Zhuang 	} while (int_status != IPC_ACK_BIT_SHIFT);
8928b02e23SHaojian Zhuang 
9028b02e23SHaojian Zhuang 	mmio_write_32(IPC_MBX_ICLR_REG(mbox), source);
9128b02e23SHaojian Zhuang }
9228b02e23SHaojian Zhuang 
9328b02e23SHaojian Zhuang static void
hisi_ipc_send_cmd_with_ack(enum src_id source,enum lpm3_mbox_id mbox,unsigned int cmdtype,unsigned int cmdpara)9428b02e23SHaojian Zhuang hisi_ipc_send_cmd_with_ack(enum src_id source, enum lpm3_mbox_id mbox,
9528b02e23SHaojian Zhuang 			   unsigned int cmdtype, unsigned int cmdpara)
9628b02e23SHaojian Zhuang {
9728b02e23SHaojian Zhuang 	unsigned int regval;
9828b02e23SHaojian Zhuang 	unsigned int mask;
9928b02e23SHaojian Zhuang 	unsigned int state;
10028b02e23SHaojian Zhuang 
10128b02e23SHaojian Zhuang 	mmio_write_32(IPC_LOCK_REG, IPC_UNLOCK_VALUE);
10228b02e23SHaojian Zhuang 	/* wait for idle and occupy */
10328b02e23SHaojian Zhuang 	do {
10428b02e23SHaojian Zhuang 		state = mmio_read_32(IPC_MBX_MODE_REG(mbox));
10528b02e23SHaojian Zhuang 		if (state == IPC_STATE_IDLE) {
10628b02e23SHaojian Zhuang 			mmio_write_32(IPC_MBX_SOURCE_REG(mbox), source);
10728b02e23SHaojian Zhuang 			regval = mmio_read_32(IPC_MBX_SOURCE_REG(mbox));
10828b02e23SHaojian Zhuang 			if (regval == source)
10928b02e23SHaojian Zhuang 				break;
11028b02e23SHaojian Zhuang 		}
11128b02e23SHaojian Zhuang 		cpu_relax();
11228b02e23SHaojian Zhuang 
11328b02e23SHaojian Zhuang 	} while (1);
11428b02e23SHaojian Zhuang 
11528b02e23SHaojian Zhuang 	/* auto answer */
11628b02e23SHaojian Zhuang 	mmio_write_32(IPC_MBX_MODE_REG(mbox), 0x1);
11728b02e23SHaojian Zhuang 
11828b02e23SHaojian Zhuang 	mask = (~((int)source | SRC_LPM3) & 0x3F);
11928b02e23SHaojian Zhuang 	/* mask the other cpus */
12028b02e23SHaojian Zhuang 	mmio_write_32(IPC_MBX_IMASK_REG(mbox), mask);
12128b02e23SHaojian Zhuang 	/* set data */
12228b02e23SHaojian Zhuang 	mmio_write_32(IPC_MBX_DATA_REG(mbox, 0), cmdtype);
12328b02e23SHaojian Zhuang 	mmio_write_32(IPC_MBX_DATA_REG(mbox, 1), cmdpara);
12428b02e23SHaojian Zhuang 	/* send cmd */
12528b02e23SHaojian Zhuang 	mmio_write_32(IPC_MBX_SEND_REG(mbox), source);
12628b02e23SHaojian Zhuang 	/* wait ack and clear */
12728b02e23SHaojian Zhuang 	hisi_ipc_clear_ack(source, mbox);
12828b02e23SHaojian Zhuang 
12928b02e23SHaojian Zhuang 	/* release mailbox */
13028b02e23SHaojian Zhuang 	mmio_write_32(IPC_MBX_SOURCE_REG(mbox), source);
13128b02e23SHaojian Zhuang }
13228b02e23SHaojian Zhuang 
hisi_ipc_pm_on_off(unsigned int core,unsigned int cluster,enum pm_mode mode)13328b02e23SHaojian Zhuang void hisi_ipc_pm_on_off(unsigned int core, unsigned int cluster,
13428b02e23SHaojian Zhuang 			enum pm_mode mode)
13528b02e23SHaojian Zhuang {
13628b02e23SHaojian Zhuang 	unsigned int cmdtype = 0;
13728b02e23SHaojian Zhuang 	unsigned int cmdpara = 0;
13828b02e23SHaojian Zhuang 	enum src_id source = SRC_IDLE;
13928b02e23SHaojian Zhuang 	enum lpm3_mbox_id mailbox = (enum lpm3_mbox_id)(LPM3_MBX0 + core);
14028b02e23SHaojian Zhuang 
14128b02e23SHaojian Zhuang 	cmdtype = IPC_CMD_TYPE(0, cluster, mode, 0x3);
14228b02e23SHaojian Zhuang 	cmdpara = IPC_CMD_PARA(0, core);
14328b02e23SHaojian Zhuang 	source = cluster ? SRC_A7 : SRC_A15;
14428b02e23SHaojian Zhuang 	hisi_ipc_send_cmd_with_ack(source, mailbox, cmdtype, cmdpara);
14528b02e23SHaojian Zhuang }
14628b02e23SHaojian Zhuang 
hisi_ipc_pm_suspend(unsigned int core,unsigned int cluster,unsigned int affinity_level)14728b02e23SHaojian Zhuang void hisi_ipc_pm_suspend(unsigned int core, unsigned int cluster,
14828b02e23SHaojian Zhuang 			 unsigned int affinity_level)
14928b02e23SHaojian Zhuang {
15028b02e23SHaojian Zhuang 	unsigned int cmdtype = 0;
15128b02e23SHaojian Zhuang 	unsigned int cmdpara = 0;
15228b02e23SHaojian Zhuang 	enum src_id source = SRC_IDLE;
15328b02e23SHaojian Zhuang 	enum lpm3_mbox_id mailbox = (enum lpm3_mbox_id)(LPM3_MBX0 + core);
15428b02e23SHaojian Zhuang 
15528b02e23SHaojian Zhuang 	if (affinity_level == 0x3)
15628b02e23SHaojian Zhuang 		cmdtype = IPC_CMD_TYPE(0, -1, 0x1, 0x3 + affinity_level);
15728b02e23SHaojian Zhuang 	else
15828b02e23SHaojian Zhuang 		cmdtype = IPC_CMD_TYPE(0, cluster, 0x1, 0x3 + affinity_level);
15928b02e23SHaojian Zhuang 
16028b02e23SHaojian Zhuang 	cmdpara = IPC_CMD_PARA(1, core);
16128b02e23SHaojian Zhuang 	source = cluster ? SRC_A7 : SRC_A15;
16228b02e23SHaojian Zhuang 	hisi_ipc_send_cmd_with_ack(source, mailbox, cmdtype, cmdpara);
16328b02e23SHaojian Zhuang }
16428b02e23SHaojian Zhuang 
hisi_ipc_psci_system_off(unsigned int core,unsigned int cluster)16528b02e23SHaojian Zhuang void hisi_ipc_psci_system_off(unsigned int core, unsigned int cluster)
16628b02e23SHaojian Zhuang {
16728b02e23SHaojian Zhuang 	unsigned int cmdtype = 0;
16828b02e23SHaojian Zhuang 	unsigned int cmdpara = 0;
16928b02e23SHaojian Zhuang 	enum src_id source = SRC_IDLE;
17028b02e23SHaojian Zhuang 	enum lpm3_mbox_id mailbox = (enum lpm3_mbox_id)(LPM3_MBX0 + core);
17128b02e23SHaojian Zhuang 
17228b02e23SHaojian Zhuang 	cmdtype = IPC_CMD_TYPE(0, (0x10 - 1), 0x1, 0x0);
17328b02e23SHaojian Zhuang 	cmdpara = IPC_CMD_PARA(0, 0);
17428b02e23SHaojian Zhuang 	source = cluster ? SRC_A7 : SRC_A15;
17528b02e23SHaojian Zhuang 	hisi_ipc_send_cmd_with_ack(source, mailbox, cmdtype, cmdpara);
17628b02e23SHaojian Zhuang }
17728b02e23SHaojian Zhuang 
hisi_ipc_psci_system_reset(unsigned int core,unsigned int cluster,unsigned int cmd_id)17828b02e23SHaojian Zhuang void hisi_ipc_psci_system_reset(unsigned int core, unsigned int cluster,
17928b02e23SHaojian Zhuang 				unsigned int cmd_id)
18028b02e23SHaojian Zhuang {
18128b02e23SHaojian Zhuang 	unsigned int cmdtype = 0;
18228b02e23SHaojian Zhuang 	unsigned int cmdpara = 0;
18328b02e23SHaojian Zhuang 	enum src_id source = SRC_IDLE;
18428b02e23SHaojian Zhuang 	enum lpm3_mbox_id mailbox = (enum lpm3_mbox_id)(LPM3_MBX0 + core);
18528b02e23SHaojian Zhuang 
18628b02e23SHaojian Zhuang 	cmdtype = IPC_CMD_TYPE(0, (0x10 - 1), 0x0, 0x0);
18728b02e23SHaojian Zhuang 	cmdpara = cmd_id;
18828b02e23SHaojian Zhuang 	source = cluster ? SRC_A7 : SRC_A15;
18928b02e23SHaojian Zhuang 	hisi_ipc_send_cmd_with_ack(source, mailbox, cmdtype, cmdpara);
19028b02e23SHaojian Zhuang }
19128b02e23SHaojian Zhuang 
hisi_ipc_init(void)19228b02e23SHaojian Zhuang int hisi_ipc_init(void)
19328b02e23SHaojian Zhuang {
19428b02e23SHaojian Zhuang 	int ret = 0;
19528b02e23SHaojian Zhuang 	enum lpm3_mbox_id  i = LPM3_MBX0;
19628b02e23SHaojian Zhuang 
19728b02e23SHaojian Zhuang 	mmio_write_32(IPC_LOCK_REG, IPC_UNLOCK_VALUE);
19828b02e23SHaojian Zhuang 	for (i = LPM3_MBX0; i <= LPM3_MBX4; i++) {
19928b02e23SHaojian Zhuang 		mmio_write_32(IPC_MBX_MODE_REG(i), 1);
20028b02e23SHaojian Zhuang 		mmio_write_32(IPC_MBX_IMASK_REG(i),
20128b02e23SHaojian Zhuang 			      ((int)SRC_IOM3 | (int)SRC_A15 | (int)SRC_A7));
20228b02e23SHaojian Zhuang 		mmio_write_32(IPC_MBX_ICLR_REG(i), SRC_A7);
20328b02e23SHaojian Zhuang 	}
20428b02e23SHaojian Zhuang 
20528b02e23SHaojian Zhuang 	return ret;
20628b02e23SHaojian Zhuang }
207