blob: 13ab51739e133e18e70ea1271ac228fe229c2f74 [file] [log] [blame]
/*******************************************************************************
* Copyright (C) Marvell International Ltd. and its affiliates
*
* Marvell GPL License Option
*
* If you received this File from Marvell, you may opt to use, redistribute and/or
* modify this File in accordance with the terms and conditions of the General
* Public License Version 2, June 1991 (the "GPL License"), a copy of which is
* available along with the File in the license.txt file or by writing to the Free
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
* on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
*
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
* WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
* DISCLAIMED. The GPL License provides additional details about this warranty
* disclaimer.
********************************************************************************/
#define _THINVPP_BCMBUF_C
#include "fastlogo.h"
#include "galois_io.h"
#include "avio.h"
#include "galois_io.h"
#include "maddr.h"
#include <linux/types.h>
#include <linux/delay.h> // for msleep()
#include <asm/cacheflush.h>
#include <asm/outercache.h>
#include <asm/io.h>
#if !LOGO_USE_SHM
static void inner_outer_flush_dcache_area(void *addr, size_t length)
{
phys_addr_t start, end;
__cpuc_flush_dcache_area(addr, length);
start = virt_to_phys(addr);
end = start + length;
// USE formal way
outer_clean_range(start, end);
}
#endif
/***************************************************************
* FUNCTION: allocate register programming buffer
* PARAMS: *buf - pointer to a register programming buffer
* : size - size of the buffer to allocate
* : - (should be a multiple of 4)
* RETURN: 1 - succeed
* 0 - failed to initialize a BCM buffer
****************************************************************/
#if LOGO_USE_SHM
int THINVPP_BCMBUF_Set(BCMBUF *pbcmbuf, void *addr, unsigned phys, int size)
{
if (size <= 0)
return (MV_THINVPP_EBADPARAM);
/* allocate memory for the buffer */
pbcmbuf->addr = (int)addr;
if(!pbcmbuf->addr)
return MV_THINVPP_ENOMEM;
pbcmbuf->phys = phys;
pbcmbuf->size = size;
pbcmbuf->head = (unsigned int *)((pbcmbuf->addr+0x1f)&(~0x01f));
if (pbcmbuf->head != (unsigned int *)pbcmbuf->addr)
pbcmbuf->size = size-64;
return MV_THINVPP_OK;
}
#else
int THINVPP_BCMBUF_Create(BCMBUF *pbcmbuf, int size)
{
if (size <= 0)
return (MV_THINVPP_EBADPARAM);
/* allocate memory for the buffer */
pbcmbuf->addr = (int)THINVPP_MALLOC(size);
if(!pbcmbuf->addr)
return MV_THINVPP_ENOMEM;
pbcmbuf->size = size;
pbcmbuf->head = (unsigned int *)((pbcmbuf->addr+0x1f)&(~0x01f));
if (pbcmbuf->head != (unsigned int *)pbcmbuf->addr)
pbcmbuf->size = size-64;
return MV_THINVPP_OK;
}
#endif
/***************************************************************
* FUNCTION: free register programming buffer
* PARAMS: *buf - pointer to a register programming buffer
* RETURN: 1 - succeed
* 0 - failed to initialize a BCM buffer
****************************************************************/
int THINVPP_BCMBUF_Destroy(BCMBUF *pbcmbuf)
{
/* allocate memory for the buffer */
if (!pbcmbuf->addr)
return (MV_THINVPP_EBADCALL);
#if !LOGO_USE_SHM
THINVPP_FREE((int *)(pbcmbuf->addr));
#endif
pbcmbuf->addr = 0;
pbcmbuf->head = NULL;
return MV_THINVPP_OK;
}
/***************************************************************
* FUNCTION: reset a register programming buffer
* PARAMS: *buf - pointer to a register programming buffer
* RETURN: 1 - succeed
* 0 - failed to initialize a BCM buffer
****************************************************************/
int THINVPP_BCMBUF_Reset(BCMBUF *pbcmbuf)
{
pbcmbuf->tail = pbcmbuf->head + (pbcmbuf->size/4);
/*set pointers to the head*/
pbcmbuf->writer = pbcmbuf->head;
pbcmbuf->dv1_head = pbcmbuf->head;
#if !LOGO_USE_SHM
pbcmbuf->dv3_head = pbcmbuf->dv1_head + (pbcmbuf->size/16)*3;
#endif
pbcmbuf->subID = -1; /* total */
return MV_THINVPP_OK;
}
/*********************************************************
* FUNCTION: Select sub register programming buffer
* PARAMS: *buf - pointer to the buffer descriptor
* subID - CPCB_1, CPCB_2, CPCB_3 or total
********************************************************/
void THINVPP_BCMBUF_Select(BCMBUF *pbcmbuf, int subID)
{
/* reset read/write pointer of the buffer */
if (subID == CPCB_1){
pbcmbuf->writer = pbcmbuf->dv1_head;
#if !LOGO_USE_SHM
} else if (subID == CPCB_3) {
pbcmbuf->writer = pbcmbuf->dv3_head;
} else {
pbcmbuf->writer = pbcmbuf->head;
#endif
}
pbcmbuf->subID = subID;
return;
}
#if !LOGO_USE_SHM
/*********************************************************
* FUNCTION: write register address (4 bytes) and value (4 bytes) to the buffer
* PARAMS: *buf - pointer to the buffer descriptor
* address - address of the register to be set
* value - the value to be written into the register
* RETURN: 1 - succeed
* 0 - register programming buffer is full
********************************************************/
int THINVPP_BCMBUF_Write(BCMBUF *pbcmbuf, unsigned int address, unsigned int value)
{
unsigned int *end;
/*if not enough space for storing another 8 bytes, wrap around happens*/
if (pbcmbuf->subID == CPCB_1)
end = pbcmbuf->dv3_head;
else
end = pbcmbuf->tail;
if(pbcmbuf->writer == end){
/*the buffer is full, no space for wrap around*/
return MV_THINVPP_EBCMBUFFULL;
}
/*save the data to the buffer*/
*pbcmbuf->writer = value;
pbcmbuf->writer ++;
*pbcmbuf->writer = address;
pbcmbuf->writer ++;
return MV_THINVPP_OK;
}
#endif
#if LOGO_USE_SHM
int THINVPP_CFGQ_Set(DHUB_CFGQ *cfgQ, void *addr, unsigned phys, int size)
{
if (size <= 0)
return (MV_THINVPP_EBADPARAM);
/* allocate memory for the buffer */
cfgQ->base_addr = (int)addr;
if(!cfgQ->base_addr)
return MV_THINVPP_ENOMEM;
cfgQ->phys = phys;
cfgQ->addr = (int *)((cfgQ->base_addr+0x1f)&(~0x01f));
cfgQ->len = 0;
return MV_THINVPP_OK;
}
#else
int THINVPP_CFGQ_Create(DHUB_CFGQ *cfgQ, int size)
{
if (size <= 0)
return (MV_THINVPP_EBADPARAM);
/* allocate memory for the buffer */
cfgQ->base_addr = (int)THINVPP_MALLOC(size);
if(!cfgQ->base_addr)
return MV_THINVPP_ENOMEM;
cfgQ->addr = (int *)((cfgQ->base_addr+0x1f)&(~0x01f));
cfgQ->len = 0;
return MV_THINVPP_OK;
}
#endif
int THINVPP_CFGQ_Destroy(DHUB_CFGQ *cfgQ)
{
int i;
if (!cfgQ->base_addr )
return (MV_THINVPP_EBADCALL);
for(i=0; i<cfgQ->len; i++);
{
//Dummy register: system timer couter1 divider, not in use!
*(cfgQ->addr+i*2) = 0;
*(cfgQ->addr+i*2+1) = 0xf7f60000 + (VOP_HDMI_SEL<<2);
}
#if !LOGO_USE_SHM
THINVPP_FREE((int *)(cfgQ->base_addr));
#endif
cfgQ->base_addr = 0;
cfgQ->addr = 0;
return MV_THINVPP_OK;
}
/*******************************************************************************
* FUNCTION: commit cfgQ which contains BCM DHUB programming info to interrupt service routine
* PARAMS: *cfgQ - cfgQ
* cpcbID - cpcb ID which this cmdQ belongs to
* intrType - interrupt type which this cmdQ belongs to: 0 - VBI, 1 - VDE
* NOTE: this API is only called from VBI/VDE ISR.
*******************************************************************************/
int THINVPP_BCMDHUB_CFGQ_Commit(DHUB_CFGQ *cfgQ, int cpcbID)
{
unsigned int sched_qid;
unsigned int bcm_sched_cmd[2];
static int bcm_count = 0;
bcm_count++;
if (cfgQ->len <= 0)
return MV_THINVPP_EBADPARAM;
if (cpcbID == CPCB_1)
sched_qid = BCM_SCHED_Q0;
else if (cpcbID == CPCB_2)
sched_qid = BCM_SCHED_Q1;
else
sched_qid = BCM_SCHED_Q2;
{
//check BCM Q status before use
int sched_stat;
BCM_SCHED_GetEmptySts(sched_qid, &sched_stat);
if (sched_stat == 0)
{
printk("****************[VPP fastlogo]ERROR! Q%d SCHED QUEUE OVERFLOW!!!!*************\n", sched_qid);
printk("[VPP fastlogo] BCM Q fulless status: %X\n", MV_MEMIO32_READ(MEMMAP_AVIO_BCM_REG_BASE+RA_AVIO_BCM_FULL_STS));
return MV_THINVPP_EIOFAIL;
}
}
#if LOGO_USE_SHM
dhub_channel_generate_cmd(&(VPP_dhubHandle.dhub), soc->avioDhubChMap_vpp_BCM_R, cfgQ->phys, (int)cfgQ->len*8, 0, 0, 0, 1, bcm_sched_cmd);
#else
inner_outer_flush_dcache_area(cfgQ->addr, cfgQ->len*8);
dhub_channel_generate_cmd(&(VPP_dhubHandle.dhub), soc->avioDhubChMap_vpp_BCM_R, (int)virt_to_phys(cfgQ->addr), (int)cfgQ->len*8, 0, 0, 0, 1, bcm_sched_cmd);
#endif
while( !BCM_SCHED_PushCmd(sched_qid, bcm_sched_cmd, NULL));
return MV_THINVPP_OK;
}
/*********************************************************************
* FUNCTION: send a BCM BUF info to a BCM cfgQ
* PARAMS: *pbcmbuf - pointer to the BCMBUF
* *cfgQ - target BCM cfgQ
* NOTE: this API is only called from VBI/VDE ISR.
********************************************************************/
int THINVPP_BCMBUF_To_CFGQ(BCMBUF *pbcmbuf, DHUB_CFGQ *cfgQ)
{
int size;
unsigned int bcm_sched_cmd[2];
unsigned int *start;
#if LOGO_USE_SHM
start = pbcmbuf->dv1_head;
#else
if (pbcmbuf->subID == CPCB_1)
start = pbcmbuf->dv1_head;
else if (pbcmbuf->subID == CPCB_3)
start = pbcmbuf->dv3_head;
else
start = pbcmbuf->head;
#endif
size = (int)pbcmbuf->writer-(int)start;
if (size <= 0)
return MV_THINVPP_EBADPARAM;
#if LOGO_USE_SHM
dhub_channel_generate_cmd(&(VPP_dhubHandle.dhub), soc->avioDhubChMap_vpp_BCM_R, pbcmbuf->phys, size, 0, 0, 0, 1, bcm_sched_cmd);
#else
inner_outer_flush_dcache_area(start, size);
dhub_channel_generate_cmd(&(VPP_dhubHandle.dhub), soc->avioDhubChMap_vpp_BCM_R, (int)virt_to_phys(start), size, 0, 0, 0, 1, bcm_sched_cmd);
#endif
while( !BCM_SCHED_PushCmd(BCM_SCHED_Q13, bcm_sched_cmd, cfgQ->addr + cfgQ->len*2));
cfgQ->len += 2;
return MV_THINVPP_OK;
}
/*********************************************************************
* FUNCTION: send a BCM cfgQ info to a BCM cfgQ
* PARAMS: src_cfgQ - pointer to the source BCM cfgQ
* *cfgQ - target BCM cfgQ
* NOTE: this API is only called from VBI/VDE ISR.
********************************************************************/
void THINVPP_CFGQ_To_CFGQ(DHUB_CFGQ *src_cfgQ, DHUB_CFGQ *cfgQ)
{
unsigned int bcm_sched_cmd[2];
if (src_cfgQ->len <= 0)
return;
#if LOGO_USE_SHM
dhub_channel_generate_cmd(&(VPP_dhubHandle.dhub), soc->avioDhubChMap_vpp_BCM_R, src_cfgQ->phys, (int)src_cfgQ->len*8, 0, 0, 0, 1, bcm_sched_cmd);
#else
inner_outer_flush_dcache_area(src_cfgQ->addr, src_cfgQ->len*8);
dhub_channel_generate_cmd(&(VPP_dhubHandle.dhub), soc->avioDhubChMap_vpp_BCM_R, (int)virt_to_phys(src_cfgQ->addr), (int)src_cfgQ->len*8, 0, 0, 0, 1, bcm_sched_cmd);
#endif
while( !BCM_SCHED_PushCmd(BCM_SCHED_Q13, bcm_sched_cmd, cfgQ->addr + cfgQ->len*2));
cfgQ->len += 2;
}