/* * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2018 NXP. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * The full GNU General Public License is included in this distribution * in the file called LICENSE.GPL. * * BSD LICENSE * * Copyright(c) 2018 NXP. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of Intel Corporation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "vpu_encoder_rpc.h" void rpc_init_shared_memory_encoder(struct shared_addr *This, unsigned long long base_phy_addr, void *base_virt_addr, u_int32 total_size, u32 *actual_size) { pENC_RPC_HOST_IFACE pSharedInterface; unsigned int phy_addr; unsigned int i; unsigned int temp_addr; BUFFER_DESCRIPTOR_TYPE *pSharedCmdBufDescPtr; BUFFER_DESCRIPTOR_TYPE *pSharedMsgBufDescPtr; pMEDIA_ENC_API_CONTROL_INTERFACE pEncCtrlInterface; This->shared_mem_phy = base_phy_addr; This->shared_mem_vir = base_virt_addr; This->base_offset = (unsigned long long)(base_virt_addr - base_phy_addr); pSharedInterface = (pENC_RPC_HOST_IFACE)This->shared_mem_vir; This->pSharedInterface = pSharedInterface; pSharedInterface->FwExecBaseAddr = base_phy_addr; pSharedInterface->FwExecAreaSize = total_size; pSharedCmdBufDescPtr = (BUFFER_DESCRIPTOR_TYPE *)&pSharedInterface->StreamCmdBufferDesc; pSharedMsgBufDescPtr = (BUFFER_DESCRIPTOR_TYPE *)&pSharedInterface->StreamMsgBufferDesc; phy_addr = base_phy_addr + sizeof(ENC_RPC_HOST_IFACE); This->cmd_mem_phy = phy_addr; This->cmd_mem_vir = This->shared_mem_vir + sizeof(ENC_RPC_HOST_IFACE); pSharedCmdBufDescPtr->wptr = phy_addr; pSharedCmdBufDescPtr->rptr = pSharedCmdBufDescPtr->wptr; pSharedCmdBufDescPtr->start = pSharedCmdBufDescPtr->wptr; pSharedCmdBufDescPtr->end = pSharedCmdBufDescPtr->start + CMD_SIZE; phy_addr += CMD_SIZE; This->msg_mem_phy = phy_addr; This->msg_mem_vir = This->cmd_mem_vir + CMD_SIZE; pSharedMsgBufDescPtr->wptr = phy_addr; pSharedMsgBufDescPtr->rptr = pSharedMsgBufDescPtr->wptr; pSharedMsgBufDescPtr->start = pSharedMsgBufDescPtr->wptr; pSharedMsgBufDescPtr->end = pSharedMsgBufDescPtr->start + MSG_SIZE; phy_addr += MSG_SIZE; for (i = 0; i < VID_API_NUM_STREAMS; i++) { pSharedInterface->pEncCtrlInterface[i] = phy_addr; phy_addr += sizeof(MEDIA_ENC_API_CONTROL_INTERFACE); } for (i = 0; i < VID_API_NUM_STREAMS; i++) { temp_addr = pSharedInterface->pEncCtrlInterface[i]; pEncCtrlInterface = (pMEDIA_ENC_API_CONTROL_INTERFACE)(temp_addr + This->base_offset); pEncCtrlInterface->pEncYUVBufferDesc = phy_addr; phy_addr += sizeof(MEDIAIP_ENC_YUV_BUFFER_DESC); pEncCtrlInterface->pEncStreamBufferDesc = phy_addr; phy_addr += sizeof(BUFFER_DESCRIPTOR_TYPE); pEncCtrlInterface->pEncExpertModeParam = phy_addr; phy_addr += sizeof(MEDIAIP_ENC_EXPERT_MODE_PARAM); pEncCtrlInterface->pEncParam = phy_addr; phy_addr += sizeof(MEDIAIP_ENC_PARAM); pEncCtrlInterface->pEncMemPool = phy_addr; phy_addr += sizeof(MEDIAIP_ENC_MEM_POOL); pEncCtrlInterface->pEncEncodingStatus = phy_addr; phy_addr += sizeof(ENC_ENCODING_STATUS); pEncCtrlInterface->pEncDSAStatus = phy_addr; phy_addr += sizeof(ENC_DSA_STATUS_t); } if (actual_size) *actual_size = phy_addr - base_phy_addr; } void rpc_restore_shared_memory_encoder(struct shared_addr *This, unsigned long long base_phy_addr, void *base_virt_addr) { pENC_RPC_HOST_IFACE pSharedInterface; unsigned int phy_addr; This->shared_mem_phy = base_phy_addr; This->shared_mem_vir = base_virt_addr; This->base_offset = (unsigned long long)(base_virt_addr - base_phy_addr); pSharedInterface = (pENC_RPC_HOST_IFACE)This->shared_mem_vir; This->pSharedInterface = pSharedInterface; phy_addr = base_phy_addr + sizeof(ENC_RPC_HOST_IFACE); This->cmd_mem_phy = phy_addr; This->cmd_mem_vir = This->shared_mem_vir + sizeof(ENC_RPC_HOST_IFACE); phy_addr += CMD_SIZE; This->msg_mem_phy = phy_addr; This->msg_mem_vir = This->cmd_mem_vir + CMD_SIZE; } void rpc_set_system_cfg_value_encoder(void *Interface, u_int32 regs_base, u_int32 core_id) { pENC_RPC_HOST_IFACE pSharedInterface; MEDIAIP_FW_SYSTEM_CONFIG *pSystemCfg; pSharedInterface = (pENC_RPC_HOST_IFACE)Interface; pSystemCfg = &pSharedInterface->sSystemCfg; pSystemCfg->uNumWindsors = 1; pSystemCfg->uWindsorIrqPin[0x0][0x0] = 0x4; // PAL_IRQ_WINDSOR_LOW pSystemCfg->uWindsorIrqPin[0x0][0x1] = 0x5; // PAL_IRQ_WINDSOR_HI pSystemCfg->uMaloneBaseAddress[0] = (unsigned int)(regs_base + 0x180000); if (core_id == 0) pSystemCfg->uWindsorBaseAddress[0] = (unsigned int)(regs_base + 0x800000); else pSystemCfg->uWindsorBaseAddress[0] = (unsigned int)(regs_base + 0xa00000); pSystemCfg->uMaloneBaseAddress[0x1] = 0x0; pSystemCfg->uHifOffset[0x0] = 0x1C000; pSystemCfg->uHifOffset[0x1] = 0x0; pSystemCfg->uDPVBaseAddr = 0x0; pSystemCfg->uDPVIrqPin = 0x0; pSystemCfg->uPixIfBaseAddr = (unsigned int)(regs_base + 0x180000 + 0x20000); pSystemCfg->uFSLCacheBaseAddr[0] = (unsigned int)(regs_base + 0x60000); pSystemCfg->uFSLCacheBaseAddr[1] = (unsigned int)(regs_base + 0x68000); } u_int32 rpc_MediaIPFW_Video_buffer_space_check_encoder(BUFFER_DESCRIPTOR_TYPE *pBufDesc, BOOL bFull, u_int32 uSize, u_int32 *puUpdateAddress) { u_int32 uPtr1; u_int32 uPtr2; u_int32 start; u_int32 end; u_int32 uTemp; /* bFull is FALSE when send message, write data */ /* bFull is TRUE when process commands, read data */ uPtr1 = (bFull) ? pBufDesc->rptr : pBufDesc->wptr; uPtr2 = (bFull) ? pBufDesc->wptr : pBufDesc->rptr; if (uPtr1 == uPtr2) { if (bFull) /* No data at all to read */ return 0; else { /* wrt pointer equal to read pointer thus the */ /* buffer is completely empty for further writes */ start = pBufDesc->start; end = pBufDesc->end; /* The address to be returned in this case is for */ /* the updated write pointer. */ uTemp = uPtr1 + uSize; if (uTemp >= end) uTemp -= (end - start); *puUpdateAddress = uTemp; return (end - start); } } else if (uPtr1 < uPtr2) { /* return updated rd pointer address */ /* In this case if size was too big - we expect the */ /* external ftn to compare the size against the */ /* space returned. */ *puUpdateAddress = uPtr1 + uSize; return (uPtr2 - uPtr1); } /* We know the system has looped!! */ start = pBufDesc->start; end = pBufDesc->end; uTemp = uPtr1 + uSize; if (uTemp >= end) uTemp -= (end - start); *puUpdateAddress = uTemp; return ((end - uPtr1) + (uPtr2 - start)); } static void rpc_update_cmd_buffer_ptr_encoder(BUFFER_DESCRIPTOR_TYPE *pCmdDesc) { u_int32 uWritePtr; /*avoid sw reset fail*/ mb(); uWritePtr = pCmdDesc->wptr + 4; if (uWritePtr >= pCmdDesc->end) uWritePtr = pCmdDesc->start; pCmdDesc->wptr = uWritePtr; } void rpc_send_cmd_buf_encoder(struct shared_addr *This, u_int32 idx, u_int32 cmdid, u_int32 cmdnum, u_int32 *local_cmddata) { pENC_RPC_HOST_IFACE pSharedInterface = (pENC_RPC_HOST_IFACE)This->shared_mem_vir; BUFFER_DESCRIPTOR_TYPE *pCmdDesc = &pSharedInterface->StreamCmdBufferDesc; u_int32 *cmddata; u_int32 i; u_int32 *cmdword = (u_int32 *)(This->cmd_mem_vir+pCmdDesc->wptr - pCmdDesc->start); u_int32 uIgnore; u_int32 uSpace; uSpace = rpc_MediaIPFW_Video_buffer_space_check_encoder(pCmdDesc, FALSE, 0, &uIgnore); if (uSpace < ((cmdnum + 1) << 2) + 16) { pr_err("[VPU WINDSOR] CmdBuf is no space for [%d] %d\n", idx, cmdid); return; } *cmdword = 0; *cmdword |= ((idx & 0x000000ff) << 24); *cmdword |= ((cmdnum & 0x000000ff) << 16); *cmdword |= ((cmdid & 0x00003fff) << 0); rpc_update_cmd_buffer_ptr_encoder(pCmdDesc); for (i = 0; i < cmdnum; i++) { cmddata = (u_int32 *)(This->cmd_mem_vir+pCmdDesc->wptr - pCmdDesc->start); *cmddata = local_cmddata[i]; rpc_update_cmd_buffer_ptr_encoder(pCmdDesc); } } u_int32 rpc_MediaIPFW_Video_message_check_encoder(struct shared_addr *This) { u_int32 uSpace; u_int32 uIgnore; pENC_RPC_HOST_IFACE pSharedInterface = (pENC_RPC_HOST_IFACE)This->shared_mem_vir; BUFFER_DESCRIPTOR_TYPE *pMsgDesc = &pSharedInterface->StreamMsgBufferDesc; u_int32 msgword; u_int32 msgnum; uSpace = rpc_MediaIPFW_Video_buffer_space_check_encoder(pMsgDesc, TRUE, 0, &uIgnore); uSpace = (uSpace >> 2); if (uSpace) { /* get current msgword word */ msgword = *((u_int32 *)(This->msg_mem_vir+pMsgDesc->rptr - pMsgDesc->start)); /* Find the number of additional words */ msgnum = ((msgword & 0x00ff0000) >> 16); /* * * Check the number of message words against * * 1) a limit - some sort of maximum or at least * * the size of the SW buffer the message is read into * * 2) The space reported (where space is write ptr - read ptr in 32bit words) * * It must be less than space (as opposed to <=) because * * the message itself is not included in msgword */ if (msgnum < VID_API_MESSAGE_LIMIT) { if (msgnum < uSpace) return API_MSG_AVAILABLE; else return API_MSG_INCOMPLETE; } else return API_MSG_BUFFER_ERROR; } return API_MSG_UNAVAILABLE; } static void rpc_update_msg_buffer_ptr_encoder(BUFFER_DESCRIPTOR_TYPE *pMsgDesc) { u_int32 uReadPtr; uReadPtr = pMsgDesc->rptr + 4; if (uReadPtr >= pMsgDesc->end) uReadPtr = pMsgDesc->start; pMsgDesc->rptr = uReadPtr; } u32 rpc_read_msg_u32(struct shared_addr *shared_mem) { u32 msgword; u32 *ptr = NULL; pENC_RPC_HOST_IFACE iface = NULL; BUFFER_DESCRIPTOR_TYPE *msg_buf = NULL; if (!shared_mem) return 0; iface = shared_mem->pSharedInterface; msg_buf = &iface->StreamMsgBufferDesc; ptr = shared_mem->msg_mem_vir + msg_buf->rptr - msg_buf->start; rpc_update_msg_buffer_ptr_encoder(msg_buf); msgword = *ptr; return msgword; } int rpc_read_msg_array(struct shared_addr *shared_mem, u32 *buf, u32 number) { int i; u32 val; if (!shared_mem) return -EINVAL; for (i = 0; i < number; i++) { val = rpc_read_msg_u32(shared_mem); if (buf) buf[i] = val; } return 0; } int rpc_get_msg_header(struct shared_addr *shared_mem, struct msg_header *msg) { u32 msgword; if (!shared_mem || !msg) return -EINVAL; msgword = rpc_read_msg_u32(shared_mem); msg->idx = ((msgword & 0xff000000) >> 24); msg->msgnum = ((msgword & 0x00ff0000) >> 16); msg->msgid = ((msgword & 0x00003fff) >> 0); return 0; } static void *phy_to_virt(u_int32 src, unsigned long long offset) { void *result; result = (void *)(src + offset); return result; } #define GET_CTRL_INTERFACE_MEMBER(shared_mem, index, name, member) \ do {\ pENC_RPC_HOST_IFACE iface = shared_mem->pSharedInterface; \ pMEDIA_ENC_API_CONTROL_INTERFACE ctrl_interface =\ phy_to_virt(iface->pEncCtrlInterface[index],\ shared_mem->base_offset);\ name = phy_to_virt(ctrl_interface->member,\ shared_mem->base_offset);\ } while (0) pMEDIAIP_ENC_YUV_BUFFER_DESC rpc_get_yuv_buffer_desc( struct shared_addr *shared_mem, int index) { pMEDIAIP_ENC_YUV_BUFFER_DESC desc = NULL; GET_CTRL_INTERFACE_MEMBER(shared_mem, index, desc, pEncYUVBufferDesc); return desc; } pBUFFER_DESCRIPTOR_TYPE rpc_get_stream_buffer_desc( struct shared_addr *shared_mem, int index) { pBUFFER_DESCRIPTOR_TYPE desc = NULL; GET_CTRL_INTERFACE_MEMBER(shared_mem, index, desc, pEncStreamBufferDesc); return desc; } pMEDIAIP_ENC_EXPERT_MODE_PARAM rpc_get_expert_mode_param( struct shared_addr *shared_mem, int index) { pMEDIAIP_ENC_EXPERT_MODE_PARAM param = NULL; GET_CTRL_INTERFACE_MEMBER(shared_mem, index, param, pEncExpertModeParam); return param; } pMEDIAIP_ENC_PARAM rpc_get_enc_param( struct shared_addr *shared_mem, int index) { pMEDIAIP_ENC_PARAM param = NULL; GET_CTRL_INTERFACE_MEMBER(shared_mem, index, param, pEncParam); return param; } pMEDIAIP_ENC_MEM_POOL rpc_get_mem_pool( struct shared_addr *shared_mem, int index) { pMEDIAIP_ENC_MEM_POOL pool = NULL; GET_CTRL_INTERFACE_MEMBER(shared_mem, index, pool, pEncMemPool); return pool; } pENC_ENCODING_STATUS rpc_get_encoding_status( struct shared_addr *shared_mem, int index) { pENC_ENCODING_STATUS encoding_status = NULL; GET_CTRL_INTERFACE_MEMBER(shared_mem, index, encoding_status, pEncEncodingStatus); return encoding_status; } pENC_DSA_STATUS_t rpc_get_dsa_status(struct shared_addr *shared_mem, int index) { pENC_DSA_STATUS_t dsa_status = NULL; GET_CTRL_INTERFACE_MEMBER(shared_mem, index, dsa_status, pEncDSAStatus); return dsa_status; } void rpc_set_print_buffer(struct shared_addr *shared_mem, unsigned long print_phy_addr, u32 size) { pENC_RPC_HOST_IFACE pSharedInterface; pBUFFER_DESCRIPTOR_TYPE debugBufDesc; pSharedInterface = shared_mem->pSharedInterface; debugBufDesc = &pSharedInterface->DebugBufferDesc; debugBufDesc->start = print_phy_addr; debugBufDesc->end = debugBufDesc->start + size; debugBufDesc->wptr = debugBufDesc->rptr = debugBufDesc->start; }