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