Files
2025-08-27 09:51:58 +01:00

571 lines
14 KiB
C

#include "typesdef.h"
#include "errno.h"
#include "osal/irq.h"
#include "devid.h"
#include "dev/vpp/hgvpp.h"
#include "osal/string.h"
struct hgvpp_hw
{
__IO uint32_t CON;
__IO uint32_t SIZE;
__IO uint32_t DLT;
__IO uint32_t DHT;
__IO uint32_t STA;
__IO uint32_t DMA_YADR;
__IO uint32_t DMA_UADR;
__IO uint32_t DMA_VADR;
__IO uint32_t DMA_YADR1;
__IO uint32_t DMA_UADR1;
__IO uint32_t DMA_VADR1;
__IO uint32_t IWM0_CON;
__IO uint32_t IWM0_SIZE;
__IO uint32_t IWM0_YUV;
__IO uint32_t IWM0_LADR;
__IO uint32_t IWM0_IDX0;
__IO uint32_t IWM0_IDX1;
__IO uint32_t IWM0_IDX2;
__IO uint32_t IWM1_CON;
__IO uint32_t IWM1_SIZE;
__IO uint32_t IWM1_YUV;
__IO uint32_t IWM1_LADR;
__IO uint32_t IPF_SADR;
__IO uint32_t MD_CON;
__IO uint32_t MD_WIN_CON0;
__IO uint32_t MD_WIN_CON1;
__IO uint32_t MD_BASE_ADDR;
__IO uint32_t ITP_YADR;
__IO uint32_t ITP_UADR;
__IO uint32_t ITP_VADR;
};
vpp_irq_hdl vppirq_vector_table[VPP_IRQ_NUM];
volatile uint32 vppirq_dev_table[VPP_IRQ_NUM];
static int32 hgvpp_ioctl(struct vpp_device *p_vpp, enum vpp_ioctl_cmd ioctl_cmd, uint32 param1, uint32 param2)
{
int32 ret_val = RET_OK;
uint32 w,h,num;
uint32 x_s,y_s,x_e,y_e;
//uint32 *size_array;
struct hgvpp *vpp_hw = (struct hgvpp*)p_vpp;
struct hgvpp_hw *hw = (struct hgvpp_hw *)vpp_hw->hw;
switch(ioctl_cmd){
case VPP_IOCTL_CMD_ITP_AUTO_CLOSE:
if(param1)
hw->CON |= BIT(30);
else
hw->CON &= ~BIT(30);
break;
case VPP_IOCTL_CMD_SET_TAKE_PHOTO_LINEBUF:
if(param1 < 8){
hw->CON &= ~(0x7<<17);
hw->CON |= (param1<<17);
}
break;
case VPP_IOCTL_CMD_DIS_UV_MODE:
if(param1)
hw->CON |= BIT(4);
else
hw->CON &= ~BIT(4);
break;
case VPP_IOCTL_CMD_SET_THRESHOLD:
hw->DLT = param1;
hw->DHT = param2;
break;
case VPP_IOCTL_CMD_SET_WATERMARK0_RC:
if(param1)
hw->IWM0_CON |= BIT(5);
else
hw->IWM0_CON &= ~BIT(5);
break;
case VPP_IOCTL_CMD_SET_WATERMARK1_RC:
if(param1)
hw->IWM1_CON |= BIT(5);
else
hw->IWM1_CON &= ~BIT(5);
break;
case VPP_IOCTL_CMD_SET_WATERMARK0_COLOR:
hw->IWM0_YUV = param1;
break;
case VPP_IOCTL_CMD_SET_WATERMARK1_COLOR:
hw->IWM1_YUV = param1;
break;
case VPP_IOCTL_CMD_SET_WATERMARK0_BMPADR:
hw->IWM0_LADR = param1;
break;
case VPP_IOCTL_CMD_SET_WATERMARK1_BMPADR:
hw->IWM1_LADR = param1;
break;
case VPP_IOCTL_CMD_SET_WATERMARK0_LOCATED:
hw->IWM0_CON &= ~(0xff<<16);
hw->IWM0_CON &= ~(0xff<<24);
hw->IWM0_CON |= (((param1&0Xff00)>>8)<<24);
hw->IWM0_CON |= ((param1&0Xff)<<16);
break;
case VPP_IOCTL_CMD_SET_WATERMARK1_LOCATED:
hw->IWM1_CON &= ~(0xff<<16);
hw->IWM1_CON &= ~(0xff<<24);
hw->IWM1_CON |= (((param1&0Xff00)>>8)<<24);
hw->IWM1_CON |= ((param1&0Xff)<<16);
break;
case VPP_IOCTL_CMD_SET_WATERMARK0_CONTRAST:
hw->IWM0_CON &= ~(0x7<<2);
hw->IWM0_CON |= (param1<<2);
break;
case VPP_IOCTL_CMD_SET_WATERMARK1_CONTRAST:
hw->IWM1_CON &= ~(0x7<<2);
hw->IWM1_CON |= (param1<<2);
break;
case VPP_IOCTL_CMD_SET_WATERMARK0_CHAR_SIZE_AND_NUM:
w = param1&0xff;
h = ((param1&0xff00)>>8)&0xff;
num = param2&0xff;
hw->IWM0_SIZE &= ~(0x1f<<0);
hw->IWM0_SIZE |= (num<<0);
hw->IWM0_SIZE &= ~(0x3f<<5);
hw->IWM0_SIZE |= (w<<5);
hw->IWM0_SIZE &= ~(0x3ff<<11);
hw->IWM0_SIZE |= ((w*num)<<11);
hw->IWM0_SIZE &= ~(0xff<<21);
hw->IWM0_SIZE |= (h<<21);
break;
case VPP_IOCTL_CMD_SET_WATERMARK0_CHAR_IDX:
if(param2 > 23)
return ret_val;
if(param2 < 8){
hw->IWM0_IDX0 &= ~(0xf<<(param2*4));
hw->IWM0_IDX0 |= (param1<<(param2*4));
}
else if(param2 < 16){
hw->IWM0_IDX1 &= ~(0xf<<((param2-8)*4));
hw->IWM0_IDX1 |= (param1<<((param2-8)*4));
}else{
hw->IWM0_IDX2 &= ~(0xf<<((param2-16)*4));
hw->IWM0_IDX2 |= (param1<<((param2-16)*4));
}
break;
case VPP_IOCTL_CMD_SET_WATERMARK1_PHOTO_SIZE:
w = param1&0xff;
h = ((param1&0xff00)>>8)&0xff;
hw->IWM1_SIZE &= ~(0xff<<11);
hw->IWM1_SIZE |= (w<<11);
hw->IWM1_SIZE &= ~(0xff<<21);
hw->IWM1_SIZE |= (h<<21);
break;
case VPP_IOCTL_CMD_SET_WATERMARK0_MODE:
if(param1)
hw->IWM0_CON |= BIT(1);
else
hw->IWM0_CON &= ~BIT(1);
break;
case VPP_IOCTL_CMD_SET_WATERMARK1_MODE:
if(param1)
hw->IWM1_CON |= BIT(1);
else
hw->IWM1_CON &= ~BIT(1);
break;
case VPP_IOCTL_CMD_SET_WATERMARK0_EN:
if(param1)
hw->IWM0_CON |= BIT(0);
else
hw->IWM0_CON &= ~BIT(0);
break;
case VPP_IOCTL_CMD_SET_WATERMARK1_EN:
if(param1)
hw->IWM1_CON |= BIT(0);
else
hw->IWM1_CON &= ~BIT(0);
break;
case VPP_IOCTL_CMD_SET_MOTION_DET_EN:
if(param1){
hw->MD_CON &= ~(0x1f<<18);
hw->MD_CON |= (BIT(23));
hw->MD_CON |= BIT(0);
}
else{
hw->MD_CON &= ~BIT(0);
}
break;
case VPP_IOCTL_CMD_SET_MOTION_CALBUF:
hw->MD_BASE_ADDR = param1;
break;
case VPP_IOCTL_CMD_SET_MOTION_RANGE:
x_s = param1&0xffff;
y_s = ((param1&0xffff0000)>>16)&0xffff;
x_e = param2&0xffff;
y_e = ((param2&0xffff0000)>>16)&0xffff;
//hw->MD_WIN_CON0 = param1;
//hw->MD_WIN_CON1 = param1;
hw->MD_WIN_CON0 = (x_s | (y_s<<16));
hw->MD_WIN_CON1 = ((x_e-1) | ((y_e-1)<<16));
break;
case VPP_IOCTL_CMD_SET_MOTION_BLK_THRESHOLD:
param1 = param1&0xff;
hw->MD_CON &= ~(0xff<<1);
hw->MD_CON |= (param1<<1);
break;
case VPP_IOCTL_CMD_SET_MOTION_FRAME_THRESHOLD:
param1 = param1&0x1ff;
hw->MD_CON &= ~(0x1ff<<9);
hw->MD_CON |= (param1<<9);
break;
case VPP_IOCTL_CMD_SET_IFP_ADDR:
hw->IPF_SADR = param1;
break;
case VPP_IOCTL_CMD_SET_IFP_EN:
if(param1)
hw->CON |= BIT(28);
else
hw->CON &= ~BIT(28);
break;
case VPP_IOCTL_CMD_SET_MODE:
if(param1)
hw->CON |= BIT(1);
else
hw->CON &= ~BIT(1);
break;
case VPP_IOCTL_CMD_SET_SIZE:
w = param1;
h = param2;
hw->SIZE = 0;
hw->SIZE |= (w<<0);
hw->SIZE |= (h<<11);
break;
case VPP_IOCTL_CMD_SET_YCBCR:
if(param1 > 3){
os_printf("set ycbcr error:%d\r\n",param1);
}
hw->CON &= ~(BIT(2)|BIT(3));
hw->CON |= param1<<2;
break;
case VPP_IOCTL_CMD_BUF0_CNT:
if(param1 > 16){
os_printf("set buf0 error:%d\r\n",param1);
}
hw->CON &= ~(0x0f<<7);
hw->CON |= (param1<<7);
break;
case VPP_IOCTL_CMD_BUF1_CNT:
if(param1 > 16){
os_printf("set buf1 error:%d\r\n",param1);
}
hw->CON &= ~(0x0f<<13);
hw->CON |= (param1<<13);
break;
case VPP_IOCTL_CMD_BUF1_EN:
if(param1)
hw->CON |= BIT(11);
else
hw->CON &= ~BIT(11);
break;
case VPP_IOCTL_CMD_BUF1_SHRINK:
if(param1)
hw->CON &= ~BIT(12); // 1/2
else
hw->CON |= BIT(12); // 1/3
break;
case VPP_IOCTL_CMD_INPUT_INTERFACE:
if(param1)
hw->CON |= BIT(5);
else
hw->CON &= ~BIT(5);
break;
case VPP_IOCTL_CMD_BUF0_Y_ADDR:
hw->DMA_YADR = param1;
break;
case VPP_IOCTL_CMD_BUF0_U_ADDR:
hw->DMA_UADR = param1;
break;
case VPP_IOCTL_CMD_BUF0_V_ADDR:
hw->DMA_VADR = param1;
break;
case VPP_IOCTL_CMD_BUF1_Y_ADDR:
hw->DMA_YADR1 = param1;
break;
case VPP_IOCTL_CMD_BUF1_U_ADDR:
hw->DMA_UADR1 = param1;
break;
case VPP_IOCTL_CMD_BUF1_V_ADDR:
hw->DMA_VADR1 = param1;
break;
case VPP_IOCTL_CMD_ITP_Y_ADDR:
hw->ITP_YADR = param1;
break;
case VPP_IOCTL_CMD_ITP_U_ADDR:
hw->ITP_UADR = param1;
break;
case VPP_IOCTL_CMD_ITP_V_ADDR:
hw->ITP_VADR = param1;
break;
case VPP_IOCTL_CMD_ITP_EN:
if(param1)
hw->CON |= BIT(29);
else
hw->CON &= ~BIT(29);
break;
default:
os_printf("NO VPP IOCTL:%d\r\n",ioctl_cmd);
ret_val = -ENOTSUPP;
break;
}
return ret_val;
}
void VPP_IRQHandler_action(void *p_vpp)
{
uint32 sta = 0;
uint8 loop;
struct hgvpp *vpp_hw = (struct hgvpp*)p_vpp;
struct hgvpp_hw *hw = (struct hgvpp_hw *)vpp_hw->hw;
sta = hw->STA;
for(loop = 0;loop < VPP_IRQ_NUM;loop++){
if(sta&BIT(loop)){
hw->STA = BIT(loop);
if(vppirq_vector_table[loop] != NULL)
vppirq_vector_table[loop] (loop,vppirq_dev_table[loop],0);
}
}
}
void irq_vpp_enable(struct vpp_device *p_vpp,uint8 mode,uint8 irq){
struct hgvpp *vpp_hw = (struct hgvpp*)p_vpp;
struct hgvpp_hw *hw = (struct hgvpp_hw *)vpp_hw->hw;
if(mode){
hw->CON |= BIT(irq+20);
}else{
hw->CON &= ~BIT(irq+20);
}
}
int32 vppirq_register(struct vpp_device *p_vpp,uint32 irq, vpp_irq_hdl isr, uint32 dev_id){
struct hgvpp *vpp_hw = (struct hgvpp*)p_vpp;
struct hgvpp_hw *hw = (struct hgvpp_hw *)vpp_hw->hw;
request_irq(vpp_hw->irq_num, VPP_IRQHandler_action, p_vpp);
irq_vpp_enable(p_vpp, 1, irq);
vppirq_vector_table[irq] = isr;
vppirq_dev_table[irq] = dev_id;
hw->STA |= BIT(irq);
os_printf("vppirq_register:%d %x %x\r\n",irq,(uint32)vppirq_vector_table[irq],(uint32)isr);
return 0;
}
int32 vppirq_unregister(struct vpp_device *p_vpp,uint32 irq){
struct hgvpp *vpp_hw = (struct hgvpp*)p_vpp;
struct hgvpp_hw *hw = (struct hgvpp_hw *)vpp_hw->hw;
irq_vpp_enable(p_vpp, 0, irq);
vppirq_vector_table[irq] = NULL;
vppirq_dev_table[irq] = 0;
hw->STA |= BIT(irq);
return 0;
}
static int32 hgvpp_open(struct vpp_device *p_vpp){
struct hgvpp *vpp_hw = (struct hgvpp*)p_vpp;
struct hgvpp_hw *hw = (struct hgvpp_hw *)vpp_hw->hw;
hw->CON |= BIT(0);
vpp_hw->opened = 1;
vpp_hw->dsleep = 0;
irq_enable(vpp_hw->irq_num);
return 0;
}
static int32 hgvpp_close(struct vpp_device *p_vpp){
struct hgvpp *vpp_hw = (struct hgvpp*)p_vpp;
struct hgvpp_hw *hw = (struct hgvpp_hw *)vpp_hw->hw;
hw->CON &= ~BIT(0);
vpp_hw->opened = 0;
vpp_hw->dsleep = 0;
irq_disable(vpp_hw->irq_num);
return 0;
}
int32 hgvpp_suspend(struct dev_obj *obj){
struct hgvpp *vpp_hw = (struct hgvpp*)obj;
struct hgvpp_hw *hw;
struct hgvpp_hw *hw_cfg;
//确保已经被打开并且休眠过,直接返回
if(!vpp_hw->opened || vpp_hw->dsleep)
{
return RET_OK;
}
vpp_hw->dsleep = 1;
vpp_hw->cfg_backup = (uint32 *)os_malloc(sizeof(struct hgvpp_hw));
hw_cfg = (struct hgvpp_hw*)vpp_hw->cfg_backup;
hw = (struct hgvpp_hw*)vpp_hw->hw;
hw_cfg->CON = hw->CON;
hw_cfg->SIZE = hw->SIZE;
hw_cfg->DLT = hw->DLT;
hw_cfg->DHT = hw->DHT;
hw_cfg->STA = hw->STA;
hw_cfg->DMA_YADR = hw->DMA_YADR;
hw_cfg->DMA_UADR = hw->DMA_UADR;
hw_cfg->DMA_VADR = hw->DMA_VADR;
hw_cfg->DMA_YADR1 = hw->DMA_YADR1;
hw_cfg->DMA_UADR1 = hw->DMA_UADR1;
hw_cfg->DMA_VADR1 = hw->DMA_VADR1;
hw_cfg->IWM0_CON = hw->IWM0_CON;
hw_cfg->IWM0_SIZE = hw->IWM0_SIZE;
hw_cfg->IWM0_YUV = hw->IWM0_YUV;
hw_cfg->IWM0_LADR = hw->IWM0_LADR;
hw_cfg->IWM0_IDX0 = hw->IWM0_IDX0;
hw_cfg->IWM0_IDX1 = hw->IWM0_IDX1;
hw_cfg->IWM0_IDX2 = hw->IWM0_IDX2;
hw_cfg->IWM1_CON = hw->IWM1_CON;
hw_cfg->IWM1_SIZE = hw->IWM1_SIZE;
hw_cfg->IWM1_YUV = hw->IWM1_YUV;
hw_cfg->IWM1_LADR = hw->IWM1_LADR;
hw_cfg->IPF_SADR = hw->IPF_SADR;
hw_cfg->MD_CON = hw->MD_CON;
hw_cfg->MD_WIN_CON0 = hw->MD_WIN_CON0;
hw_cfg->MD_WIN_CON1 = hw->MD_WIN_CON1;
hw_cfg->MD_BASE_ADDR = hw->MD_BASE_ADDR;
hw_cfg->ITP_YADR = hw->ITP_YADR;
hw_cfg->ITP_UADR = hw->ITP_UADR;
hw_cfg->ITP_VADR = hw->ITP_VADR;
irq_disable(vpp_hw->irq_num);
return 0;
}
int32 hgvpp_resume(struct dev_obj *obj){
struct hgvpp *vpp_hw = (struct hgvpp*)obj;
struct hgvpp_hw *hw;
struct hgvpp_hw *hw_cfg;
//如果已经被打开并且没有休眠过,直接返回
if(!vpp_hw->opened || !vpp_hw->dsleep)
{
return RET_OK;
}
vpp_hw->dsleep = 0;
hw_cfg = (struct hgvpp_hw*)vpp_hw->cfg_backup;
hw = (struct hgvpp_hw*)vpp_hw->hw;
hw->CON = hw_cfg->CON;
hw->SIZE = hw_cfg->SIZE;
hw->DLT = hw_cfg->DLT;
hw->DHT = hw_cfg->DHT;
hw->STA = hw_cfg->STA;
hw->DMA_YADR = hw_cfg->DMA_YADR;
hw->DMA_UADR = hw_cfg->DMA_UADR;
hw->DMA_VADR = hw_cfg->DMA_VADR;
hw->DMA_YADR1 = hw_cfg->DMA_YADR1;
hw->DMA_UADR1 = hw_cfg->DMA_UADR1;
hw->DMA_VADR1 = hw_cfg->DMA_VADR1;
hw->IWM0_CON = hw_cfg->IWM0_CON;
hw->IWM0_SIZE = hw_cfg->IWM0_SIZE;
hw->IWM0_YUV = hw_cfg->IWM0_YUV;
hw->IWM0_LADR = hw_cfg->IWM0_LADR;
hw->IWM0_IDX0 = hw_cfg->IWM0_IDX0;
hw->IWM0_IDX1 = hw_cfg->IWM0_IDX1;
hw->IWM0_IDX2 = hw_cfg->IWM0_IDX2;
hw->IWM1_CON = hw_cfg->IWM1_CON;
hw->IWM1_SIZE = hw_cfg->IWM1_SIZE;
hw->IWM1_YUV = hw_cfg->IWM1_YUV;
hw->IWM1_LADR = hw_cfg->IWM1_LADR;
hw->IPF_SADR = hw_cfg->IPF_SADR;
hw->MD_CON = hw_cfg->MD_CON;
hw->MD_WIN_CON0 = hw_cfg->MD_WIN_CON0;
hw->MD_WIN_CON1 = hw_cfg->MD_WIN_CON1;
hw->MD_BASE_ADDR = hw_cfg->MD_BASE_ADDR;
hw->ITP_YADR = hw_cfg->ITP_YADR;
hw->ITP_UADR = hw_cfg->ITP_UADR;
hw->ITP_VADR = hw_cfg->ITP_VADR;
irq_enable(vpp_hw->irq_num);
os_free(vpp_hw->cfg_backup);
return 0;
}
static const struct vpp_hal_ops dev_ops = {
.open = hgvpp_open,
.close = hgvpp_close,
.ioctl = hgvpp_ioctl,
.request_irq = vppirq_register,
.release_irq = vppirq_unregister,
#ifdef CONFIG_SLEEP
.ops.suspend = hgvpp_suspend,
.ops.resume = hgvpp_resume,
#endif
};
int32 hgvpp_attach(uint32 dev_id, struct hgvpp *vpp){
vpp->opened = 0;
vpp->use_dma = 0;
vpp->irq_hdl = NULL;
//memset(dvp->irq_hdl,0,sizeof(dvp->irq_hdl));
vpp->irq_data = 0;
//memset(dvp->irq_data,0,sizeof(dvp->irq_data));
vpp->dev.dev.ops = (const struct devobj_ops *)&dev_ops;
irq_disable(vpp->irq_num);
dev_register(dev_id, (struct dev_obj *)vpp);
return 0;
}