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