xref: /rk3399_ARM-atf/plat/mediatek/mt8183/drivers/sspm/sspm.c (revision 420c26b33a29c8328a1806ccb2f5a5885041fdfc)
19fc34bbdSkenny liang /*
29fc34bbdSkenny liang  * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
39fc34bbdSkenny liang  *
49fc34bbdSkenny liang  * SPDX-License-Identifier: BSD-3-Clause
59fc34bbdSkenny liang  */
69fc34bbdSkenny liang #include <arch_helpers.h>
79fc34bbdSkenny liang #include <common/debug.h>
89fc34bbdSkenny liang #include <drivers/delay_timer.h>
99fc34bbdSkenny liang #include <errno.h>
109fc34bbdSkenny liang #include <lib/mmio.h>
119fc34bbdSkenny liang #include <sspm.h>
129fc34bbdSkenny liang 
139fc34bbdSkenny liang static void memcpy_to_sspm(uint32_t dst, uint32_t *src, uint32_t len)
149fc34bbdSkenny liang {
159fc34bbdSkenny liang 	while (len--) {
169fc34bbdSkenny liang 		mmio_write_32(dst, *src);
179fc34bbdSkenny liang 		dst += sizeof(uint32_t);
189fc34bbdSkenny liang 		src++;
199fc34bbdSkenny liang 	}
209fc34bbdSkenny liang }
219fc34bbdSkenny liang 
229fc34bbdSkenny liang static void memcpy_from_sspm(uint32_t *dst, uint32_t src, uint32_t len)
239fc34bbdSkenny liang {
249fc34bbdSkenny liang 	while (len--) {
259fc34bbdSkenny liang 		*dst = mmio_read_32(src);
269fc34bbdSkenny liang 		dst++;
279fc34bbdSkenny liang 		src += sizeof(uint32_t);
289fc34bbdSkenny liang 	}
299fc34bbdSkenny liang }
309fc34bbdSkenny liang 
319fc34bbdSkenny liang int sspm_mbox_read(uint32_t slot, uint32_t *data, uint32_t len)
329fc34bbdSkenny liang {
339fc34bbdSkenny liang 	if (slot >= 32)	{
349fc34bbdSkenny liang 		ERROR("%s:slot = %d\n", __func__, slot);
359fc34bbdSkenny liang 		return -EINVAL;
369fc34bbdSkenny liang 	}
379fc34bbdSkenny liang 
389fc34bbdSkenny liang 	if (data)
399fc34bbdSkenny liang 		memcpy_from_sspm(data,
409fc34bbdSkenny liang 				 MBOX3_BASE + slot * 4,
419fc34bbdSkenny liang 				 len);
429fc34bbdSkenny liang 
439fc34bbdSkenny liang 	return 0;
449fc34bbdSkenny liang }
459fc34bbdSkenny liang 
469fc34bbdSkenny liang int sspm_mbox_write(uint32_t slot, uint32_t *data, uint32_t len)
479fc34bbdSkenny liang {
489fc34bbdSkenny liang 	if (slot >= 32) {
499fc34bbdSkenny liang 		ERROR("%s:slot = %d\n", __func__, slot);
509fc34bbdSkenny liang 		return -EINVAL;
519fc34bbdSkenny liang 	}
529fc34bbdSkenny liang 
539fc34bbdSkenny liang 	if (data)
549fc34bbdSkenny liang 		memcpy_to_sspm(MBOX3_BASE + slot * 4,
559fc34bbdSkenny liang 			       data,
569fc34bbdSkenny liang 			       len);
579fc34bbdSkenny liang 
589fc34bbdSkenny liang 	return 0;
599fc34bbdSkenny liang }
609fc34bbdSkenny liang 
619fc34bbdSkenny liang static int sspm_ipi_check_ack(uint32_t id)
629fc34bbdSkenny liang {
639fc34bbdSkenny liang 	int ret = 0;
649fc34bbdSkenny liang 
659fc34bbdSkenny liang 	if (id == IPI_ID_PLATFORM) {
669fc34bbdSkenny liang 		if ((mmio_read_32(MBOX0_BASE + MBOX_IN_IRQ_OFS) & 0x1) == 0x1)
679fc34bbdSkenny liang 			ret = -EINPROGRESS;
689fc34bbdSkenny liang 	} else if (id == IPI_ID_SUSPEND) {
699fc34bbdSkenny liang 		if ((mmio_read_32(MBOX1_BASE + MBOX_IN_IRQ_OFS) & 0x2) == 0x2)
709fc34bbdSkenny liang 			ret = -EINPROGRESS;
719fc34bbdSkenny liang 	} else {
729fc34bbdSkenny liang 		ERROR("%s: id = %d\n", __func__, id);
739fc34bbdSkenny liang 		ret = -EINVAL;
749fc34bbdSkenny liang 	}
759fc34bbdSkenny liang 
769fc34bbdSkenny liang 	return ret;
779fc34bbdSkenny liang }
789fc34bbdSkenny liang 
799fc34bbdSkenny liang int sspm_ipi_send_non_blocking(uint32_t id, uint32_t *data)
809fc34bbdSkenny liang {
819fc34bbdSkenny liang 	int ret = 0;
829fc34bbdSkenny liang 
839fc34bbdSkenny liang 	ret = sspm_ipi_check_ack(id);
849fc34bbdSkenny liang 	if (ret)
859fc34bbdSkenny liang 		return ret;
869fc34bbdSkenny liang 
879fc34bbdSkenny liang 	if (id == IPI_ID_PLATFORM) {
889fc34bbdSkenny liang 		memcpy_to_sspm(MBOX0_BASE + PINR_OFFSET_PLATFORM * 4,
899fc34bbdSkenny liang 			       data,
909fc34bbdSkenny liang 			       PINR_SIZE_PLATFORM);
919fc34bbdSkenny liang 		dsb();
929fc34bbdSkenny liang 		mmio_write_32(MBOX0_BASE + MBOX_OUT_IRQ_OFS, 0x1);
939fc34bbdSkenny liang 	} else if (id == IPI_ID_SUSPEND) {
949fc34bbdSkenny liang 		memcpy_to_sspm(MBOX1_BASE + PINR_OFFSET_SUSPEND * 4,
959fc34bbdSkenny liang 			       data,
969fc34bbdSkenny liang 			       PINR_SIZE_SUSPEND);
979fc34bbdSkenny liang 		dsb();
989fc34bbdSkenny liang 		mmio_write_32(MBOX1_BASE + MBOX_OUT_IRQ_OFS,
999fc34bbdSkenny liang 			      0x2);
1009fc34bbdSkenny liang 	}
1019fc34bbdSkenny liang 
1029fc34bbdSkenny liang 	return 0;
1039fc34bbdSkenny liang }
1049fc34bbdSkenny liang 
1059fc34bbdSkenny liang int sspm_ipi_recv_non_blocking(uint32_t id, uint32_t *data, uint32_t len)
1069fc34bbdSkenny liang {
1079fc34bbdSkenny liang 	int ret = 0;
1089fc34bbdSkenny liang 
1099fc34bbdSkenny liang 	ret = sspm_ipi_check_ack(id);
1109fc34bbdSkenny liang 	if (ret == -EINPROGRESS) {
1119fc34bbdSkenny liang 		if (id == IPI_ID_PLATFORM) {
1129fc34bbdSkenny liang 			memcpy_from_sspm(data,
1139fc34bbdSkenny liang 					 MBOX0_BASE + PINR_OFFSET_PLATFORM * 4,
1149fc34bbdSkenny liang 					 len);
1159fc34bbdSkenny liang 			dsb();
1169fc34bbdSkenny liang 			/* clear interrupt bit*/
1179fc34bbdSkenny liang 			mmio_write_32(MBOX0_BASE + MBOX_IN_IRQ_OFS,
1189fc34bbdSkenny liang 				      0x1);
1199fc34bbdSkenny liang 			ret = 0;
1209fc34bbdSkenny liang 		} else if (id == IPI_ID_SUSPEND) {
1219fc34bbdSkenny liang 			memcpy_from_sspm(data,
1229fc34bbdSkenny liang 					 MBOX1_BASE + PINR_OFFSET_SUSPEND * 4,
1239fc34bbdSkenny liang 					 len);
1249fc34bbdSkenny liang 			dsb();
1259fc34bbdSkenny liang 			/* clear interrupt bit*/
1269fc34bbdSkenny liang 			mmio_write_32(MBOX1_BASE + MBOX_IN_IRQ_OFS,
1279fc34bbdSkenny liang 				      0x2);
1289fc34bbdSkenny liang 			ret = 0;
1299fc34bbdSkenny liang 		}
1309fc34bbdSkenny liang 	} else if (ret == 0) {
1319fc34bbdSkenny liang 		ret = -EBUSY;
1329fc34bbdSkenny liang 	}
1339fc34bbdSkenny liang 
1349fc34bbdSkenny liang 	return ret;
1359fc34bbdSkenny liang }
1369fc34bbdSkenny liang 
1379fc34bbdSkenny liang int sspm_alive_show(void)
1389fc34bbdSkenny liang {
1399fc34bbdSkenny liang 	uint32_t ipi_data, count;
1409fc34bbdSkenny liang 	int ret = 0;
1419fc34bbdSkenny liang 
1429fc34bbdSkenny liang 	count = 5;
1439fc34bbdSkenny liang 	ipi_data = 0xdead;
1449fc34bbdSkenny liang 
1459fc34bbdSkenny liang 	if (sspm_ipi_send_non_blocking(IPI_ID_PLATFORM, &ipi_data) != 0) {
1469fc34bbdSkenny liang 		ERROR("sspm init send fail! ret=%d\n", ret);
1479fc34bbdSkenny liang 		return -1;
1489fc34bbdSkenny liang 	}
1499fc34bbdSkenny liang 
1509fc34bbdSkenny liang 	while (sspm_ipi_recv_non_blocking(IPI_ID_PLATFORM,
1519fc34bbdSkenny liang 					  &ipi_data,
152*420c26b3STinghan Shen 					  sizeof(ipi_data) / sizeof(uint32_t))
1539fc34bbdSkenny liang 					  && count) {
1549fc34bbdSkenny liang 		mdelay(100);
1559fc34bbdSkenny liang 		count--;
1569fc34bbdSkenny liang 	}
1579fc34bbdSkenny liang 
1589fc34bbdSkenny liang 	return (ipi_data == 1) ? 0 : -1;
1599fc34bbdSkenny liang }
160