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