1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (C) 2018 Marvell International Ltd. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu * https://spdx.org/licenses 6*91f16700Schasinglulu */ 7*91f16700Schasinglulu 8*91f16700Schasinglulu #include <string.h> 9*91f16700Schasinglulu 10*91f16700Schasinglulu #include <common/debug.h> 11*91f16700Schasinglulu #include <lib/mmio.h> 12*91f16700Schasinglulu 13*91f16700Schasinglulu #include <plat_marvell.h> 14*91f16700Schasinglulu #include <mss_ipc_drv.h> 15*91f16700Schasinglulu 16*91f16700Schasinglulu #define IPC_MSG_BASE_MASK MVEBU_REGS_BASE_MASK 17*91f16700Schasinglulu 18*91f16700Schasinglulu #define IPC_CH_NUM_OF_MSG (16) 19*91f16700Schasinglulu #define IPC_CH_MSG_IDX (-1) 20*91f16700Schasinglulu 21*91f16700Schasinglulu unsigned long mv_pm_ipc_msg_base; 22*91f16700Schasinglulu unsigned int mv_pm_ipc_queue_size; 23*91f16700Schasinglulu 24*91f16700Schasinglulu unsigned int msg_sync; 25*91f16700Schasinglulu int msg_index = IPC_CH_MSG_IDX; 26*91f16700Schasinglulu 27*91f16700Schasinglulu /****************************************************************************** 28*91f16700Schasinglulu * mss_pm_ipc_init 29*91f16700Schasinglulu * 30*91f16700Schasinglulu * DESCRIPTION: Initialize PM IPC infrastructure 31*91f16700Schasinglulu ****************************************************************************** 32*91f16700Schasinglulu */ 33*91f16700Schasinglulu int mv_pm_ipc_init(unsigned long ipc_control_addr) 34*91f16700Schasinglulu { 35*91f16700Schasinglulu struct mss_pm_ipc_ctrl *ipc_control = 36*91f16700Schasinglulu (struct mss_pm_ipc_ctrl *)ipc_control_addr; 37*91f16700Schasinglulu 38*91f16700Schasinglulu /* Initialize PM IPC control block */ 39*91f16700Schasinglulu mv_pm_ipc_msg_base = ipc_control->msg_base_address | 40*91f16700Schasinglulu IPC_MSG_BASE_MASK; 41*91f16700Schasinglulu mv_pm_ipc_queue_size = ipc_control->queue_size; 42*91f16700Schasinglulu 43*91f16700Schasinglulu return 0; 44*91f16700Schasinglulu } 45*91f16700Schasinglulu 46*91f16700Schasinglulu /****************************************************************************** 47*91f16700Schasinglulu * mv_pm_ipc_queue_addr_get 48*91f16700Schasinglulu * 49*91f16700Schasinglulu * DESCRIPTION: Returns the IPC queue address 50*91f16700Schasinglulu ****************************************************************************** 51*91f16700Schasinglulu */ 52*91f16700Schasinglulu unsigned int mv_pm_ipc_queue_addr_get(void) 53*91f16700Schasinglulu { 54*91f16700Schasinglulu unsigned int addr; 55*91f16700Schasinglulu 56*91f16700Schasinglulu inv_dcache_range((uint64_t)&msg_index, sizeof(msg_index)); 57*91f16700Schasinglulu msg_index = msg_index + 1; 58*91f16700Schasinglulu if (msg_index >= IPC_CH_NUM_OF_MSG) 59*91f16700Schasinglulu msg_index = 0; 60*91f16700Schasinglulu 61*91f16700Schasinglulu addr = (unsigned int)(mv_pm_ipc_msg_base + 62*91f16700Schasinglulu (msg_index * mv_pm_ipc_queue_size)); 63*91f16700Schasinglulu 64*91f16700Schasinglulu flush_dcache_range((uint64_t)&msg_index, sizeof(msg_index)); 65*91f16700Schasinglulu 66*91f16700Schasinglulu return addr; 67*91f16700Schasinglulu } 68*91f16700Schasinglulu 69*91f16700Schasinglulu /****************************************************************************** 70*91f16700Schasinglulu * mv_pm_ipc_msg_rx 71*91f16700Schasinglulu * 72*91f16700Schasinglulu * DESCRIPTION: Retrieve message from IPC channel 73*91f16700Schasinglulu ****************************************************************************** 74*91f16700Schasinglulu */ 75*91f16700Schasinglulu int mv_pm_ipc_msg_rx(unsigned int channel_id, struct mss_pm_ipc_msg *msg) 76*91f16700Schasinglulu { 77*91f16700Schasinglulu unsigned int addr = mv_pm_ipc_queue_addr_get(); 78*91f16700Schasinglulu 79*91f16700Schasinglulu msg->msg_reply = mmio_read_32(addr + IPC_MSG_REPLY_LOC); 80*91f16700Schasinglulu 81*91f16700Schasinglulu return 0; 82*91f16700Schasinglulu } 83*91f16700Schasinglulu 84*91f16700Schasinglulu /****************************************************************************** 85*91f16700Schasinglulu * mv_pm_ipc_msg_tx 86*91f16700Schasinglulu * 87*91f16700Schasinglulu * DESCRIPTION: Send message via IPC channel 88*91f16700Schasinglulu ****************************************************************************** 89*91f16700Schasinglulu */ 90*91f16700Schasinglulu int mv_pm_ipc_msg_tx(unsigned int channel_id, unsigned int msg_id, 91*91f16700Schasinglulu unsigned int cluster_power_state) 92*91f16700Schasinglulu { 93*91f16700Schasinglulu unsigned int addr = mv_pm_ipc_queue_addr_get(); 94*91f16700Schasinglulu 95*91f16700Schasinglulu /* Validate the entry for message placed by the host is free */ 96*91f16700Schasinglulu if (mmio_read_32(addr + IPC_MSG_STATE_LOC) == IPC_MSG_FREE) { 97*91f16700Schasinglulu inv_dcache_range((uint64_t)&msg_sync, sizeof(msg_sync)); 98*91f16700Schasinglulu msg_sync = msg_sync + 1; 99*91f16700Schasinglulu flush_dcache_range((uint64_t)&msg_sync, sizeof(msg_sync)); 100*91f16700Schasinglulu 101*91f16700Schasinglulu mmio_write_32(addr + IPC_MSG_SYNC_ID_LOC, msg_sync); 102*91f16700Schasinglulu mmio_write_32(addr + IPC_MSG_ID_LOC, msg_id); 103*91f16700Schasinglulu mmio_write_32(addr + IPC_MSG_CPU_ID_LOC, channel_id); 104*91f16700Schasinglulu mmio_write_32(addr + IPC_MSG_POWER_STATE_LOC, 105*91f16700Schasinglulu cluster_power_state); 106*91f16700Schasinglulu mmio_write_32(addr + IPC_MSG_STATE_LOC, IPC_MSG_OCCUPY); 107*91f16700Schasinglulu 108*91f16700Schasinglulu } else { 109*91f16700Schasinglulu ERROR("%s: FAILED\n", __func__); 110*91f16700Schasinglulu } 111*91f16700Schasinglulu 112*91f16700Schasinglulu return 0; 113*91f16700Schasinglulu } 114