128b02e23SHaojian Zhuang /* 228b02e23SHaojian Zhuang * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. 328b02e23SHaojian Zhuang * 428b02e23SHaojian Zhuang * SPDX-License-Identifier: BSD-3-Clause 528b02e23SHaojian Zhuang */ 628b02e23SHaojian Zhuang 728b02e23SHaojian Zhuang #include <assert.h> 8*09d40e0eSAntonio Nino Diaz 928b02e23SHaojian Zhuang #include <platform_def.h> 1028b02e23SHaojian Zhuang 11*09d40e0eSAntonio Nino Diaz #include <arch_helpers.h> 12*09d40e0eSAntonio Nino Diaz #include <common/debug.h> 13*09d40e0eSAntonio Nino Diaz #include <lib/mmio.h> 14*09d40e0eSAntonio Nino Diaz #include <plat/common/platform.h> 15*09d40e0eSAntonio Nino Diaz 16*09d40e0eSAntonio Nino Diaz #include <hi3660.h> 17*09d40e0eSAntonio Nino Diaz #include <hisi_ipc.h> 1828b02e23SHaojian Zhuang #include "../../hikey960_private.h" 1928b02e23SHaojian Zhuang 2028b02e23SHaojian Zhuang #define IPC_MBX_SOURCE_REG(m) (IPC_BASE + ((m) << 6)) 2128b02e23SHaojian Zhuang #define IPC_MBX_DSET_REG(m) (IPC_BASE + ((m) << 6) + 0x04) 2228b02e23SHaojian Zhuang #define IPC_MBX_DCLEAR_REG(m) (IPC_BASE + ((m) << 6) + 0x08) 2328b02e23SHaojian Zhuang #define IPC_MBX_DSTATUS_REG(m) (IPC_BASE + ((m) << 6) + 0x0C) 2428b02e23SHaojian Zhuang #define IPC_MBX_MODE_REG(m) (IPC_BASE + ((m) << 6) + 0x10) 2528b02e23SHaojian Zhuang #define IPC_MBX_IMASK_REG(m) (IPC_BASE + ((m) << 6) + 0x14) 2628b02e23SHaojian Zhuang #define IPC_MBX_ICLR_REG(m) (IPC_BASE + ((m) << 6) + 0x18) 2728b02e23SHaojian Zhuang #define IPC_MBX_SEND_REG(m) (IPC_BASE + ((m) << 6) + 0x1C) 2828b02e23SHaojian Zhuang #define IPC_MBX_DATA_REG(m, d) (IPC_BASE + ((m) << 6) + 0x20 + \ 2928b02e23SHaojian Zhuang ((d) * 4)) 3028b02e23SHaojian Zhuang #define IPC_CPU_IMST_REG(m) (IPC_BASE + ((m) << 3)) 3128b02e23SHaojian Zhuang #define IPC_LOCK_REG (IPC_BASE + 0xA00) 3228b02e23SHaojian Zhuang #define IPC_ACK_BIT_SHIFT (1 << 7) 3328b02e23SHaojian Zhuang #define IPC_UNLOCK_VALUE (0x1ACCE551) 3428b02e23SHaojian Zhuang 3528b02e23SHaojian Zhuang /********************************************************* 3628b02e23SHaojian Zhuang *bit[31:24]:0~AP 3728b02e23SHaojian Zhuang *bit[23:16]:0x1~A15, 0x2~A7 3828b02e23SHaojian Zhuang *bit[15:8]:0~ON, 1~OFF 3928b02e23SHaojian Zhuang *bit[7:0]:0x3 cpu power mode 4028b02e23SHaojian Zhuang *********************************************************/ 4128b02e23SHaojian Zhuang #define IPC_CMD_TYPE(src_obj, cluster_obj, is_off, mode) \ 4228b02e23SHaojian Zhuang ((src_obj << 24) | (((cluster_obj) + 1) << 16) | (is_off << 8) | (mode)) 4328b02e23SHaojian Zhuang 4428b02e23SHaojian Zhuang /********************************************************* 4528b02e23SHaojian Zhuang *bit[15:8]:0~no idle, 1~idle 4628b02e23SHaojian Zhuang *bit[7:0]:cpux 4728b02e23SHaojian Zhuang *********************************************************/ 4828b02e23SHaojian Zhuang 4928b02e23SHaojian Zhuang #define IPC_CMD_PARA(is_idle, cpu) \ 5028b02e23SHaojian Zhuang ((is_idle << 8) | (cpu)) 5128b02e23SHaojian Zhuang 5228b02e23SHaojian Zhuang #define IPC_STATE_IDLE 0x10 5328b02e23SHaojian Zhuang 5428b02e23SHaojian Zhuang enum src_id { 5528b02e23SHaojian Zhuang SRC_IDLE = 0, 5628b02e23SHaojian Zhuang SRC_A15 = 1 << 0, 5728b02e23SHaojian Zhuang SRC_A7 = 1 << 1, 5828b02e23SHaojian Zhuang SRC_IOM3 = 1 << 2, 5928b02e23SHaojian Zhuang SRC_LPM3 = 1 << 3 6028b02e23SHaojian Zhuang }; 6128b02e23SHaojian Zhuang 6228b02e23SHaojian Zhuang /*lpm3's mailboxs are 13~17*/ 6328b02e23SHaojian Zhuang enum lpm3_mbox_id { 6428b02e23SHaojian Zhuang LPM3_MBX0 = 13, 6528b02e23SHaojian Zhuang LPM3_MBX1, 6628b02e23SHaojian Zhuang LPM3_MBX2, 6728b02e23SHaojian Zhuang LPM3_MBX3, 6828b02e23SHaojian Zhuang LPM3_MBX4, 6928b02e23SHaojian Zhuang }; 7028b02e23SHaojian Zhuang 7128b02e23SHaojian Zhuang static void cpu_relax(void) 7228b02e23SHaojian Zhuang { 7328b02e23SHaojian Zhuang volatile int i; 7428b02e23SHaojian Zhuang 7528b02e23SHaojian Zhuang for (i = 0; i < 10; i++) 7628b02e23SHaojian Zhuang nop(); 7728b02e23SHaojian Zhuang } 7828b02e23SHaojian Zhuang 7928b02e23SHaojian Zhuang static inline void 8028b02e23SHaojian Zhuang hisi_ipc_clear_ack(enum src_id source, enum lpm3_mbox_id mbox) 8128b02e23SHaojian Zhuang { 8228b02e23SHaojian Zhuang unsigned int int_status = 0; 8328b02e23SHaojian Zhuang 8428b02e23SHaojian Zhuang do { 8528b02e23SHaojian Zhuang int_status = mmio_read_32(IPC_MBX_MODE_REG(mbox)); 8628b02e23SHaojian Zhuang int_status &= 0xF0; 8728b02e23SHaojian Zhuang cpu_relax(); 8828b02e23SHaojian Zhuang } while (int_status != IPC_ACK_BIT_SHIFT); 8928b02e23SHaojian Zhuang 9028b02e23SHaojian Zhuang mmio_write_32(IPC_MBX_ICLR_REG(mbox), source); 9128b02e23SHaojian Zhuang } 9228b02e23SHaojian Zhuang 9328b02e23SHaojian Zhuang static void 9428b02e23SHaojian Zhuang hisi_ipc_send_cmd_with_ack(enum src_id source, enum lpm3_mbox_id mbox, 9528b02e23SHaojian Zhuang unsigned int cmdtype, unsigned int cmdpara) 9628b02e23SHaojian Zhuang { 9728b02e23SHaojian Zhuang unsigned int regval; 9828b02e23SHaojian Zhuang unsigned int mask; 9928b02e23SHaojian Zhuang unsigned int state; 10028b02e23SHaojian Zhuang 10128b02e23SHaojian Zhuang mmio_write_32(IPC_LOCK_REG, IPC_UNLOCK_VALUE); 10228b02e23SHaojian Zhuang /* wait for idle and occupy */ 10328b02e23SHaojian Zhuang do { 10428b02e23SHaojian Zhuang state = mmio_read_32(IPC_MBX_MODE_REG(mbox)); 10528b02e23SHaojian Zhuang if (state == IPC_STATE_IDLE) { 10628b02e23SHaojian Zhuang mmio_write_32(IPC_MBX_SOURCE_REG(mbox), source); 10728b02e23SHaojian Zhuang regval = mmio_read_32(IPC_MBX_SOURCE_REG(mbox)); 10828b02e23SHaojian Zhuang if (regval == source) 10928b02e23SHaojian Zhuang break; 11028b02e23SHaojian Zhuang } 11128b02e23SHaojian Zhuang cpu_relax(); 11228b02e23SHaojian Zhuang 11328b02e23SHaojian Zhuang } while (1); 11428b02e23SHaojian Zhuang 11528b02e23SHaojian Zhuang /* auto answer */ 11628b02e23SHaojian Zhuang mmio_write_32(IPC_MBX_MODE_REG(mbox), 0x1); 11728b02e23SHaojian Zhuang 11828b02e23SHaojian Zhuang mask = (~((int)source | SRC_LPM3) & 0x3F); 11928b02e23SHaojian Zhuang /* mask the other cpus */ 12028b02e23SHaojian Zhuang mmio_write_32(IPC_MBX_IMASK_REG(mbox), mask); 12128b02e23SHaojian Zhuang /* set data */ 12228b02e23SHaojian Zhuang mmio_write_32(IPC_MBX_DATA_REG(mbox, 0), cmdtype); 12328b02e23SHaojian Zhuang mmio_write_32(IPC_MBX_DATA_REG(mbox, 1), cmdpara); 12428b02e23SHaojian Zhuang /* send cmd */ 12528b02e23SHaojian Zhuang mmio_write_32(IPC_MBX_SEND_REG(mbox), source); 12628b02e23SHaojian Zhuang /* wait ack and clear */ 12728b02e23SHaojian Zhuang hisi_ipc_clear_ack(source, mbox); 12828b02e23SHaojian Zhuang 12928b02e23SHaojian Zhuang /* release mailbox */ 13028b02e23SHaojian Zhuang mmio_write_32(IPC_MBX_SOURCE_REG(mbox), source); 13128b02e23SHaojian Zhuang } 13228b02e23SHaojian Zhuang 13328b02e23SHaojian Zhuang void hisi_ipc_pm_on_off(unsigned int core, unsigned int cluster, 13428b02e23SHaojian Zhuang enum pm_mode mode) 13528b02e23SHaojian Zhuang { 13628b02e23SHaojian Zhuang unsigned int cmdtype = 0; 13728b02e23SHaojian Zhuang unsigned int cmdpara = 0; 13828b02e23SHaojian Zhuang enum src_id source = SRC_IDLE; 13928b02e23SHaojian Zhuang enum lpm3_mbox_id mailbox = (enum lpm3_mbox_id)(LPM3_MBX0 + core); 14028b02e23SHaojian Zhuang 14128b02e23SHaojian Zhuang cmdtype = IPC_CMD_TYPE(0, cluster, mode, 0x3); 14228b02e23SHaojian Zhuang cmdpara = IPC_CMD_PARA(0, core); 14328b02e23SHaojian Zhuang source = cluster ? SRC_A7 : SRC_A15; 14428b02e23SHaojian Zhuang hisi_ipc_send_cmd_with_ack(source, mailbox, cmdtype, cmdpara); 14528b02e23SHaojian Zhuang } 14628b02e23SHaojian Zhuang 14728b02e23SHaojian Zhuang void hisi_ipc_pm_suspend(unsigned int core, unsigned int cluster, 14828b02e23SHaojian Zhuang unsigned int affinity_level) 14928b02e23SHaojian Zhuang { 15028b02e23SHaojian Zhuang unsigned int cmdtype = 0; 15128b02e23SHaojian Zhuang unsigned int cmdpara = 0; 15228b02e23SHaojian Zhuang enum src_id source = SRC_IDLE; 15328b02e23SHaojian Zhuang enum lpm3_mbox_id mailbox = (enum lpm3_mbox_id)(LPM3_MBX0 + core); 15428b02e23SHaojian Zhuang 15528b02e23SHaojian Zhuang if (affinity_level == 0x3) 15628b02e23SHaojian Zhuang cmdtype = IPC_CMD_TYPE(0, -1, 0x1, 0x3 + affinity_level); 15728b02e23SHaojian Zhuang else 15828b02e23SHaojian Zhuang cmdtype = IPC_CMD_TYPE(0, cluster, 0x1, 0x3 + affinity_level); 15928b02e23SHaojian Zhuang 16028b02e23SHaojian Zhuang cmdpara = IPC_CMD_PARA(1, core); 16128b02e23SHaojian Zhuang source = cluster ? SRC_A7 : SRC_A15; 16228b02e23SHaojian Zhuang hisi_ipc_send_cmd_with_ack(source, mailbox, cmdtype, cmdpara); 16328b02e23SHaojian Zhuang } 16428b02e23SHaojian Zhuang 16528b02e23SHaojian Zhuang void hisi_ipc_psci_system_off(unsigned int core, unsigned int cluster) 16628b02e23SHaojian Zhuang { 16728b02e23SHaojian Zhuang unsigned int cmdtype = 0; 16828b02e23SHaojian Zhuang unsigned int cmdpara = 0; 16928b02e23SHaojian Zhuang enum src_id source = SRC_IDLE; 17028b02e23SHaojian Zhuang enum lpm3_mbox_id mailbox = (enum lpm3_mbox_id)(LPM3_MBX0 + core); 17128b02e23SHaojian Zhuang 17228b02e23SHaojian Zhuang cmdtype = IPC_CMD_TYPE(0, (0x10 - 1), 0x1, 0x0); 17328b02e23SHaojian Zhuang cmdpara = IPC_CMD_PARA(0, 0); 17428b02e23SHaojian Zhuang source = cluster ? SRC_A7 : SRC_A15; 17528b02e23SHaojian Zhuang hisi_ipc_send_cmd_with_ack(source, mailbox, cmdtype, cmdpara); 17628b02e23SHaojian Zhuang } 17728b02e23SHaojian Zhuang 17828b02e23SHaojian Zhuang void hisi_ipc_psci_system_reset(unsigned int core, unsigned int cluster, 17928b02e23SHaojian Zhuang unsigned int cmd_id) 18028b02e23SHaojian Zhuang { 18128b02e23SHaojian Zhuang unsigned int cmdtype = 0; 18228b02e23SHaojian Zhuang unsigned int cmdpara = 0; 18328b02e23SHaojian Zhuang enum src_id source = SRC_IDLE; 18428b02e23SHaojian Zhuang enum lpm3_mbox_id mailbox = (enum lpm3_mbox_id)(LPM3_MBX0 + core); 18528b02e23SHaojian Zhuang 18628b02e23SHaojian Zhuang cmdtype = IPC_CMD_TYPE(0, (0x10 - 1), 0x0, 0x0); 18728b02e23SHaojian Zhuang cmdpara = cmd_id; 18828b02e23SHaojian Zhuang source = cluster ? SRC_A7 : SRC_A15; 18928b02e23SHaojian Zhuang hisi_ipc_send_cmd_with_ack(source, mailbox, cmdtype, cmdpara); 19028b02e23SHaojian Zhuang } 19128b02e23SHaojian Zhuang 19228b02e23SHaojian Zhuang int hisi_ipc_init(void) 19328b02e23SHaojian Zhuang { 19428b02e23SHaojian Zhuang int ret = 0; 19528b02e23SHaojian Zhuang enum lpm3_mbox_id i = LPM3_MBX0; 19628b02e23SHaojian Zhuang 19728b02e23SHaojian Zhuang mmio_write_32(IPC_LOCK_REG, IPC_UNLOCK_VALUE); 19828b02e23SHaojian Zhuang for (i = LPM3_MBX0; i <= LPM3_MBX4; i++) { 19928b02e23SHaojian Zhuang mmio_write_32(IPC_MBX_MODE_REG(i), 1); 20028b02e23SHaojian Zhuang mmio_write_32(IPC_MBX_IMASK_REG(i), 20128b02e23SHaojian Zhuang ((int)SRC_IOM3 | (int)SRC_A15 | (int)SRC_A7)); 20228b02e23SHaojian Zhuang mmio_write_32(IPC_MBX_ICLR_REG(i), SRC_A7); 20328b02e23SHaojian Zhuang } 20428b02e23SHaojian Zhuang 20528b02e23SHaojian Zhuang return ret; 20628b02e23SHaojian Zhuang } 207