Home | History | Annotate | Download | only in ipc
      1 /*
      2  * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
      3  *
      4  * SPDX-License-Identifier: BSD-3-Clause
      5  */
      6 
      7 #include <arch_helpers.h>
      8 #include <assert.h>
      9 #include <debug.h>
     10 #include <hi3660.h>
     11 #include <hisi_ipc.h>
     12 #include <mmio.h>
     13 #include <platform.h>
     14 #include <platform_def.h>
     15 
     16 #include "../../hikey960_private.h"
     17 
     18 #define IPC_MBX_SOURCE_REG(m)		(IPC_BASE + ((m) << 6))
     19 #define IPC_MBX_DSET_REG(m)		(IPC_BASE + ((m) << 6) + 0x04)
     20 #define IPC_MBX_DCLEAR_REG(m)		(IPC_BASE + ((m) << 6) + 0x08)
     21 #define IPC_MBX_DSTATUS_REG(m)		(IPC_BASE + ((m) << 6) + 0x0C)
     22 #define IPC_MBX_MODE_REG(m)		(IPC_BASE + ((m) << 6) + 0x10)
     23 #define IPC_MBX_IMASK_REG(m)		(IPC_BASE + ((m) << 6) + 0x14)
     24 #define IPC_MBX_ICLR_REG(m)		(IPC_BASE + ((m) << 6) + 0x18)
     25 #define IPC_MBX_SEND_REG(m)		(IPC_BASE + ((m) << 6) + 0x1C)
     26 #define IPC_MBX_DATA_REG(m, d)		(IPC_BASE + ((m) << 6) + 0x20 + \
     27 					 ((d) * 4))
     28 #define IPC_CPU_IMST_REG(m)		(IPC_BASE + ((m) << 3))
     29 #define IPC_LOCK_REG			(IPC_BASE + 0xA00)
     30 #define IPC_ACK_BIT_SHIFT		(1 << 7)
     31 #define IPC_UNLOCK_VALUE		(0x1ACCE551)
     32 
     33 /*********************************************************
     34  *bit[31:24]:0~AP
     35  *bit[23:16]:0x1~A15, 0x2~A7
     36  *bit[15:8]:0~ON, 1~OFF
     37  *bit[7:0]:0x3 cpu power mode
     38  *********************************************************/
     39 #define IPC_CMD_TYPE(src_obj, cluster_obj, is_off, mode) \
     40 	((src_obj << 24) | (((cluster_obj) + 1) << 16) | (is_off << 8) | (mode))
     41 
     42 /*********************************************************
     43  *bit[15:8]:0~no idle, 1~idle
     44  *bit[7:0]:cpux
     45  *********************************************************/
     46 
     47 #define IPC_CMD_PARA(is_idle, cpu) \
     48 	((is_idle << 8) | (cpu))
     49 
     50 #define IPC_STATE_IDLE			0x10
     51 
     52 enum src_id {
     53 	SRC_IDLE = 0,
     54 	SRC_A15 = 1 << 0,
     55 	SRC_A7 = 1 << 1,
     56 	SRC_IOM3 = 1 << 2,
     57 	SRC_LPM3 = 1 << 3
     58 };
     59 
     60 /*lpm3's mailboxs are 13~17*/
     61 enum lpm3_mbox_id {
     62 	LPM3_MBX0 = 13,
     63 	LPM3_MBX1,
     64 	LPM3_MBX2,
     65 	LPM3_MBX3,
     66 	LPM3_MBX4,
     67 };
     68 
     69 static void cpu_relax(void)
     70 {
     71 	volatile int i;
     72 
     73 	for (i = 0; i < 10; i++)
     74 		nop();
     75 }
     76 
     77 static inline void
     78 hisi_ipc_clear_ack(enum src_id source, enum lpm3_mbox_id mbox)
     79 {
     80 	unsigned int int_status = 0;
     81 
     82 	do {
     83 		int_status = mmio_read_32(IPC_MBX_MODE_REG(mbox));
     84 		int_status &= 0xF0;
     85 		cpu_relax();
     86 	} while (int_status != IPC_ACK_BIT_SHIFT);
     87 
     88 	mmio_write_32(IPC_MBX_ICLR_REG(mbox), source);
     89 }
     90 
     91 static void
     92 hisi_ipc_send_cmd_with_ack(enum src_id source, enum lpm3_mbox_id mbox,
     93 			   unsigned int cmdtype, unsigned int cmdpara)
     94 {
     95 	unsigned int regval;
     96 	unsigned int mask;
     97 	unsigned int state;
     98 
     99 	mmio_write_32(IPC_LOCK_REG, IPC_UNLOCK_VALUE);
    100 	/* wait for idle and occupy */
    101 	do {
    102 		state = mmio_read_32(IPC_MBX_MODE_REG(mbox));
    103 		if (state == IPC_STATE_IDLE) {
    104 			mmio_write_32(IPC_MBX_SOURCE_REG(mbox), source);
    105 			regval = mmio_read_32(IPC_MBX_SOURCE_REG(mbox));
    106 			if (regval == source)
    107 				break;
    108 		}
    109 		cpu_relax();
    110 
    111 	} while (1);
    112 
    113 	/* auto answer */
    114 	mmio_write_32(IPC_MBX_MODE_REG(mbox), 0x1);
    115 
    116 	mask = (~((int)source | SRC_LPM3) & 0x3F);
    117 	/* mask the other cpus */
    118 	mmio_write_32(IPC_MBX_IMASK_REG(mbox), mask);
    119 	/* set data */
    120 	mmio_write_32(IPC_MBX_DATA_REG(mbox, 0), cmdtype);
    121 	mmio_write_32(IPC_MBX_DATA_REG(mbox, 1), cmdpara);
    122 	/* send cmd */
    123 	mmio_write_32(IPC_MBX_SEND_REG(mbox), source);
    124 	/* wait ack and clear */
    125 	hisi_ipc_clear_ack(source, mbox);
    126 
    127 	/* release mailbox */
    128 	mmio_write_32(IPC_MBX_SOURCE_REG(mbox), source);
    129 }
    130 
    131 void hisi_ipc_pm_on_off(unsigned int core, unsigned int cluster,
    132 			enum pm_mode mode)
    133 {
    134 	unsigned int cmdtype = 0;
    135 	unsigned int cmdpara = 0;
    136 	enum src_id source = SRC_IDLE;
    137 	enum lpm3_mbox_id mailbox = (enum lpm3_mbox_id)(LPM3_MBX0 + core);
    138 
    139 	cmdtype = IPC_CMD_TYPE(0, cluster, mode, 0x3);
    140 	cmdpara = IPC_CMD_PARA(0, core);
    141 	source = cluster ? SRC_A7 : SRC_A15;
    142 	hisi_ipc_send_cmd_with_ack(source, mailbox, cmdtype, cmdpara);
    143 }
    144 
    145 void hisi_ipc_pm_suspend(unsigned int core, unsigned int cluster,
    146 			 unsigned int affinity_level)
    147 {
    148 	unsigned int cmdtype = 0;
    149 	unsigned int cmdpara = 0;
    150 	enum src_id source = SRC_IDLE;
    151 	enum lpm3_mbox_id mailbox = (enum lpm3_mbox_id)(LPM3_MBX0 + core);
    152 
    153 	if (affinity_level == 0x3)
    154 		cmdtype = IPC_CMD_TYPE(0, -1, 0x1, 0x3 + affinity_level);
    155 	else
    156 		cmdtype = IPC_CMD_TYPE(0, cluster, 0x1, 0x3 + affinity_level);
    157 
    158 	cmdpara = IPC_CMD_PARA(1, core);
    159 	source = cluster ? SRC_A7 : SRC_A15;
    160 	hisi_ipc_send_cmd_with_ack(source, mailbox, cmdtype, cmdpara);
    161 }
    162 
    163 void hisi_ipc_psci_system_off(unsigned int core, unsigned int cluster)
    164 {
    165 	unsigned int cmdtype = 0;
    166 	unsigned int cmdpara = 0;
    167 	enum src_id source = SRC_IDLE;
    168 	enum lpm3_mbox_id mailbox = (enum lpm3_mbox_id)(LPM3_MBX0 + core);
    169 
    170 	cmdtype = IPC_CMD_TYPE(0, (0x10 - 1), 0x1, 0x0);
    171 	cmdpara = IPC_CMD_PARA(0, 0);
    172 	source = cluster ? SRC_A7 : SRC_A15;
    173 	hisi_ipc_send_cmd_with_ack(source, mailbox, cmdtype, cmdpara);
    174 }
    175 
    176 void hisi_ipc_psci_system_reset(unsigned int core, unsigned int cluster,
    177 				unsigned int cmd_id)
    178 {
    179 	unsigned int cmdtype = 0;
    180 	unsigned int cmdpara = 0;
    181 	enum src_id source = SRC_IDLE;
    182 	enum lpm3_mbox_id mailbox = (enum lpm3_mbox_id)(LPM3_MBX0 + core);
    183 
    184 	cmdtype = IPC_CMD_TYPE(0, (0x10 - 1), 0x0, 0x0);
    185 	cmdpara = cmd_id;
    186 	source = cluster ? SRC_A7 : SRC_A15;
    187 	hisi_ipc_send_cmd_with_ack(source, mailbox, cmdtype, cmdpara);
    188 }
    189 
    190 int hisi_ipc_init(void)
    191 {
    192 	int ret = 0;
    193 	enum lpm3_mbox_id  i = LPM3_MBX0;
    194 
    195 	mmio_write_32(IPC_LOCK_REG, IPC_UNLOCK_VALUE);
    196 	for (i = LPM3_MBX0; i <= LPM3_MBX4; i++) {
    197 		mmio_write_32(IPC_MBX_MODE_REG(i), 1);
    198 		mmio_write_32(IPC_MBX_IMASK_REG(i),
    199 			      ((int)SRC_IOM3 | (int)SRC_A15 | (int)SRC_A7));
    200 		mmio_write_32(IPC_MBX_ICLR_REG(i), SRC_A7);
    201 	}
    202 
    203 	return ret;
    204 }
    205