768 lines
23 KiB
C
768 lines
23 KiB
C
|
||
#include "scale_msi.h"
|
||
#include "dev/vpp/hgvpp.h"
|
||
#include "lib/video/vpp/vpp_dev.h"
|
||
#include "dev/scale/hgscale.h"
|
||
#include "lib/heap/av_heap.h"
|
||
#include "lib/heap/av_psram_heap.h"
|
||
|
||
// data申请空间函数
|
||
#define STREAM_MALLOC av_psram_malloc
|
||
#define STREAM_FREE av_psram_free
|
||
#define STREAM_ZALLOC av_psram_zalloc
|
||
|
||
// 结构体申请空间函数
|
||
#define STREAM_LIBC_MALLOC av_malloc
|
||
#define STREAM_LIBC_FREE av_free
|
||
#define STREAM_LIBC_ZALLOC av_zalloc
|
||
struct scale3_yuv_arg_s
|
||
{
|
||
struct yuv_arg_s yuv_arg;
|
||
uint16_t ow,oh;
|
||
uint16_t ox,oy;
|
||
uint8_t tx_type; //0~3 :video 4:error fb
|
||
};
|
||
|
||
//暂时这里去控制scale3从哪个buf过来
|
||
//请配合VPP那边配置
|
||
#define SCALE3_YUVBUF_0_1 SCALE3_FROM_VPPBF
|
||
|
||
extern uint8 *yuvbuf;
|
||
extern uint8 *yuvbuf1;
|
||
#if SCALE3_YUVBUF_0_1 == 0
|
||
#define SCALE3_LINE_BUF yuvbuf
|
||
#define SCALE3_YUVBUF_Y_OFF_LINE ((VPP_BUF0_MODE == VPP_MODE_2N) ? (VPP_BUF0_LINEBUF_NUM * 2) : (VPP_BUF0_LINEBUF_NUM * 2 + 16))
|
||
#elif SCALE3_YUVBUF_0_1 == 1
|
||
#define SCALE3_LINE_BUF yuvbuf1
|
||
#define SCALE3_YUVBUF_Y_OFF_LINE ((VPP_BUF1_MODE == VPP_MODE_2N) ? (VPP_BUF1_LINEBUF_NUM * 2) : (VPP_BUF1_LINEBUF_NUM * 2 + 16))
|
||
#endif
|
||
|
||
|
||
// 暂定这个scale3是在存在dvp的时候使用,所以用宏隔离
|
||
// 实际scale3还有另一种模式不需要dvp那边启动的
|
||
|
||
|
||
// 这里可能采用信号量的形式,通知到线程去处理数据
|
||
|
||
struct scale_msg_t scale3_msg[3] = {
|
||
//ISP_VIDEO_0
|
||
{
|
||
.ow = 320,
|
||
.oh = 180,
|
||
.x = 0,
|
||
.y = 0,
|
||
.video_only = 0,
|
||
},
|
||
//ISP_VIDEO_1
|
||
{
|
||
.ow = 320,
|
||
.oh = 180,
|
||
.x = 320,
|
||
.y = 0,
|
||
.video_only = 0,
|
||
},
|
||
//ISP_VIDEO_2
|
||
{
|
||
.ow = 320,
|
||
.oh = 180,
|
||
.x = 0,
|
||
.y = 180,
|
||
.video_only = 0,
|
||
},
|
||
};
|
||
|
||
|
||
|
||
|
||
static int32_t scale3_vpp_done_func(uint32 irq_data){
|
||
struct scale3_msi_s *scale3 = (struct scale3_msi_s *)irq_data;
|
||
struct framebuff *fb = NULL;
|
||
uint8_t *p_buf;
|
||
uint16_t xm,ym;
|
||
uint16_t videow,videoh;
|
||
uint8_t sennum = 0;
|
||
struct scale3_yuv_arg_s *arg;
|
||
uint8_t errfb;
|
||
|
||
if (SCALE3_YUVBUF_0_1 == 0)
|
||
{
|
||
extern uint8_t get_vpp_w_h(uint16_t *w, uint16_t *h);
|
||
get_vpp_w_h(&videow, &videoh);
|
||
}
|
||
else if (SCALE3_YUVBUF_0_1 == 1)
|
||
{
|
||
extern uint8_t get_vpp1_w_h(uint16_t *w, uint16_t *h);
|
||
get_vpp1_w_h(&videow, &videoh);
|
||
}
|
||
// static uint32_t scaler_cnt;
|
||
//判断序号,有可能双镜头
|
||
// scale3->seq++;
|
||
if(scale3->txpool_type == 1){
|
||
fb = fbpool_get(&scale3->tx_pool0, 0, scale3->msi);
|
||
}else{
|
||
if(video_msg.video_type_cur == ISP_VIDEO_0){
|
||
if(video_msg.video_num == 2){
|
||
fb = fbpool_get(&scale3->tx_pool1, 0, scale3->msi);
|
||
}else{
|
||
if(video_msg.video_type_last == ISP_VIDEO_1){
|
||
fb = fbpool_get(&scale3->tx_pool2, 0, scale3->msi);
|
||
}else{
|
||
fb = fbpool_get(&scale3->tx_pool1, 0, scale3->msi);
|
||
}
|
||
}
|
||
}
|
||
|
||
if(video_msg.video_type_cur == ISP_VIDEO_1){
|
||
fb = fbpool_get(&scale3->tx_pool0, 0, scale3->msi);
|
||
}
|
||
|
||
if(video_msg.video_type_cur == ISP_VIDEO_2){
|
||
fb = fbpool_get(&scale3->tx_pool0, 0, scale3->msi);
|
||
}
|
||
}
|
||
|
||
errfb = 0;
|
||
if(fb == NULL){
|
||
fb = fbpool_get(&scale3->tx_poolerr, 0, scale3->msi);
|
||
errfb = 1;
|
||
}
|
||
if(video_msg.video_num == 1){
|
||
sennum = 0;
|
||
}else if(video_msg.video_num == 2){
|
||
if(video_msg.video_type_cur == ISP_VIDEO_0){
|
||
sennum = 1;
|
||
}else{
|
||
sennum = 0;
|
||
}
|
||
}else{
|
||
if((video_msg.video_type_cur == ISP_VIDEO_1)||(video_msg.video_type_cur == ISP_VIDEO_2)){
|
||
sennum = 0;
|
||
}else if(video_msg.video_type_last == ISP_VIDEO_1){
|
||
sennum = 2;
|
||
}else if(video_msg.video_type_last == ISP_VIDEO_2){
|
||
sennum = 1;
|
||
}
|
||
}
|
||
|
||
|
||
arg = (struct scale3_yuv_arg_s*)fb->priv;
|
||
if(errfb){
|
||
scale3->ow = 128;//ow;
|
||
scale3->oh = 96;//oh;
|
||
xm = 0;
|
||
ym = 0;
|
||
}else{
|
||
if(fb->len != (scale3_msg[sennum].ow * scale3_msg[sennum].oh * 3)/2 ){
|
||
scale3->ow = arg->ow;
|
||
scale3->oh = arg->oh;
|
||
|
||
xm = arg->ox;
|
||
ym = arg->oy;
|
||
}else{
|
||
scale3->ow = scale3_msg[sennum].ow;//ow;
|
||
scale3->oh = scale3_msg[sennum].oh;//oh;
|
||
xm = scale3_msg[sennum].x;
|
||
ym = scale3_msg[sennum].y;
|
||
}
|
||
}
|
||
scale3->iw = videow;//scale3_msg[sennum].iw;//iw;
|
||
scale3->ih = videoh;//scale3_msg[sennum].ih;//ih;
|
||
arg->yuv_arg.x = xm;//scale3_msg[sennum].x;
|
||
arg->yuv_arg.y = ym;//scale3_msg[sennum].y;
|
||
arg->yuv_arg.video_only = scale3_msg[sennum].video_only;
|
||
arg->yuv_arg.y_size = scale3->ow*scale3->oh;
|
||
arg->yuv_arg.out_w = scale3->ow;
|
||
arg->yuv_arg.out_h = scale3->oh;
|
||
|
||
// 暂时用同样的iw ih ow oh
|
||
scale_set_in_out_size(scale3->scale_dev, scale3->iw, scale3->ih, scale3->ow, scale3->oh);
|
||
scale_set_step(scale3->scale_dev, scale3->iw, scale3->ih, scale3->ow, scale3->oh);
|
||
scale_set_in_yaddr(scale3->scale_dev, (uint32)scale3->scaler3buf);
|
||
scale_set_in_uaddr(scale3->scale_dev, (uint32)scale3->scaler3buf + scale3->iw * SCALE3_YUVBUF_Y_OFF_LINE);
|
||
scale_set_in_vaddr(scale3->scale_dev, (uint32)scale3->scaler3buf + scale3->iw * SCALE3_YUVBUF_Y_OFF_LINE + scale3->iw * SCALE3_YUVBUF_Y_OFF_LINE/4);
|
||
|
||
// _os_printf("M(%x %x)",fb,fb->data);
|
||
fb->len = scale3->ow * scale3->oh * 3 / 2;
|
||
// 配置新的空间地址
|
||
p_buf = (uint8_t *)fb->data;
|
||
scale_set_out_yaddr(scale3->scale_dev, (uint32)p_buf);
|
||
scale_set_out_uaddr(scale3->scale_dev, (uint32)p_buf + scale3->ow * scale3->oh);
|
||
scale_set_out_vaddr(scale3->scale_dev, (uint32)p_buf + scale3->ow * scale3->oh + scale3->ow * scale3->oh / 4);
|
||
|
||
if(errfb){
|
||
msi_delete_fb(NULL, fb);
|
||
return 0;
|
||
}
|
||
|
||
arg = (struct scale3_yuv_arg_s *)scale3->now_fb->priv;
|
||
scale3->now_fb->stype = FSTYPE_YUV_P0+video_msg.video_type_cur;
|
||
|
||
// 发送now_data,发送失败也要返回
|
||
|
||
if(arg->tx_type == video_msg.video_type_cur){
|
||
if (os_msgq_put(&scale3->msgq, (uint32_t)scale3->now_fb, 0))
|
||
{
|
||
// 正常不能中断del,但是这个模块是内部,只要del没有一些等待信号量操作,问题不大
|
||
msi_delete_fb(NULL, scale3->now_fb);
|
||
scale3->now_fb = NULL;
|
||
//return 0;
|
||
}
|
||
}else{
|
||
msi_delete_fb(NULL, scale3->now_fb);
|
||
}
|
||
|
||
|
||
scale3->now_fb = fb;
|
||
// os_printf("%s:%d\n",__FUNCTION__,__LINE__);
|
||
return 0;
|
||
|
||
|
||
}
|
||
|
||
static int32_t scale3_stream_done(uint32 irq_flag, uint32 irq_data, uint32 param1)
|
||
{
|
||
//*(volatile uint32_t*)0x400e0124 |= (1<<14);
|
||
//*(volatile uint32_t*)0x400e0124 &= ~(1<<14);
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int32_t scale3_stream_ov(uint32 irq_flag, uint32 irq_data, uint32 param1)
|
||
{
|
||
os_printf("%s:%d\n", __FUNCTION__, __LINE__);
|
||
return 0;
|
||
}
|
||
|
||
|
||
static int32 scale3_stream_work(struct os_work *work)
|
||
{
|
||
int32_t ret;
|
||
struct scale3_msi_s *scale3 = (struct scale3_msi_s *)work;
|
||
struct framebuff *fb;
|
||
struct scale3_yuv_arg_s *arg;
|
||
int32_t err = -1;
|
||
fb = (struct framebuff *)os_msgq_get2(&scale3->msgq, 0, &err);
|
||
// 没有数据
|
||
if (err)
|
||
{
|
||
goto scale3_stream_work_end;
|
||
}
|
||
|
||
arg = (struct scale3_yuv_arg_s*)fb->priv;
|
||
arg->yuv_arg.dispcnt++;
|
||
fb->mtype = F_YUV;
|
||
//_os_printf("P(%d x:%d y:%d)",fb->stype,arg->yuv_arg.x,arg->yuv_arg.y);
|
||
//os_printf("scale3 fb:%X type:%d x:%d y:%d w:%d h:%d\r\n",fb,fb->stype,arg->yuv_arg.x,arg->yuv_arg.y,arg->yuv_arg.out_w,arg->yuv_arg.out_h);
|
||
if(arg->tx_type == 4){
|
||
fbpool_put(&scale3->tx_poolerr, fb);
|
||
}else{
|
||
//_os_printf("<S %08x>",fb->data);
|
||
ret = msi_output_fb(scale3->msi, fb);
|
||
}
|
||
|
||
scale3_stream_work_end:
|
||
// 过1ms就去轮询一遍,实际如果用信号量,可以改成任务形式,等待信号量,可以节约cpu(实际cache影响可能更大,cpu占用很少)
|
||
// 由于workqueue没有支持等待信号量,只能通过1ms轮询一下
|
||
os_run_work_delay(work, 1);
|
||
return 0;
|
||
}
|
||
|
||
|
||
|
||
|
||
static int32_t scale3_msi_action(struct msi *msi, uint32_t cmd_id, uint32_t param1, uint32_t param2)
|
||
{
|
||
int32_t ret = RET_OK;
|
||
uint32 ie;
|
||
struct scale3_msi_s *scale3 = (struct scale3_msi_s *)msi->priv;
|
||
struct scale3_yuv_arg_s *arg;
|
||
switch (cmd_id)
|
||
{
|
||
|
||
// 这里msi已经被删除,那么就要考虑tx_pool的资源释放了
|
||
// 能进来这里,就是代表所有fb都已经用完了
|
||
case MSI_CMD_POST_DESTROY:
|
||
{
|
||
|
||
struct framebuff *fb;
|
||
// 释放资源fb资源文件
|
||
int temp_video_num = scale3->init_txpool_num;
|
||
for(int init_txpool_num = 0; init_txpool_num < temp_video_num ; init_txpool_num++) {
|
||
while (1)
|
||
{
|
||
fb = fbpool_get(&scale3->tx_pool0 + init_txpool_num, 0, NULL);
|
||
if (!fb)
|
||
{
|
||
break;
|
||
}
|
||
if(fb->data)
|
||
{
|
||
//os_printf("D(%x %x)\n",fb,fb->data);
|
||
STREAM_FREE(fb->data);
|
||
fb->data = NULL;
|
||
}
|
||
// 预分配空间释放
|
||
if (fb->priv)
|
||
{
|
||
//os_printf("D(%x %x)\n",fb,fb->priv);
|
||
STREAM_LIBC_FREE(fb->priv);
|
||
fb->priv = NULL;
|
||
}
|
||
}
|
||
fbpool_destroy(&scale3->tx_pool0 + init_txpool_num);
|
||
}
|
||
|
||
while (1)
|
||
{
|
||
fb = fbpool_get(&scale3->tx_poolerr, 0, NULL);
|
||
if (!fb)
|
||
{
|
||
break;
|
||
}
|
||
if(fb->data)
|
||
{
|
||
//os_printf("E(%x %x)\n",fb,fb->data);
|
||
STREAM_FREE(fb->data);
|
||
fb->data = NULL;
|
||
}
|
||
// 预分配空间释放
|
||
if (fb->priv)
|
||
{
|
||
//os_printf("E(%x %x)\n",fb,fb->priv);
|
||
STREAM_LIBC_FREE(fb->priv);
|
||
fb->priv = NULL;
|
||
}
|
||
}
|
||
fbpool_destroy(&scale3->tx_poolerr);
|
||
STREAM_LIBC_FREE(scale3);
|
||
msi->priv = NULL;
|
||
}
|
||
break;
|
||
|
||
// 停止硬件,移除没有必要的资源(但是fb的资源不能现在删除,这个时候fb可能外部还在调用)
|
||
case MSI_CMD_PRE_DESTROY:
|
||
{
|
||
os_work_cancle2(&scale3->work, 1);
|
||
scale_close(scale3->scale_dev);
|
||
// os_printf("%s:%d MSI_CMD_PRE_DESTROY\n", __FUNCTION__, __LINE__);
|
||
|
||
// 移除信号量里面的数据
|
||
struct framebuff *fb = NULL;
|
||
int32_t err = 0;
|
||
while (!err)
|
||
{
|
||
fb = (struct framebuff *)os_msgq_get2(&scale3->msgq, 0, &err);
|
||
if (fb)
|
||
{
|
||
msi_delete_fb(NULL, fb);
|
||
}
|
||
fb = NULL;
|
||
}
|
||
|
||
vppdone_func_unregister(SCALER3_DONE);
|
||
|
||
if (scale3->msgq.hdl) {
|
||
os_msgq_del(&scale3->msgq);
|
||
}
|
||
|
||
fb = scale3->now_fb;
|
||
if (scale3->now_fb)
|
||
{
|
||
msi_delete_fb(NULL, scale3->now_fb);
|
||
scale3->now_fb = NULL;
|
||
}
|
||
}
|
||
break;
|
||
// 接收,判断是类型是否可以支持压缩
|
||
case MSI_CMD_TRANS_FB:
|
||
{
|
||
}
|
||
break;
|
||
// 预先分配的,默认不需要释放fb->data,除非是MSI_CMD_DESTROY后,就要释放
|
||
case MSI_CMD_FREE_FB:
|
||
{
|
||
struct framebuff *fb = (struct framebuff *)param1;
|
||
uint8_t type = 0;
|
||
arg = (struct scale3_yuv_arg_s*)fb->priv;
|
||
if(arg->tx_type == 0){
|
||
type = 0;
|
||
}else if(arg->tx_type == 1){
|
||
type = 1;
|
||
}else if(arg->tx_type == 2){
|
||
type = 2;
|
||
}else{
|
||
type = 4;
|
||
}
|
||
|
||
if (fb->data && (type < 4))
|
||
{
|
||
ie = disable_irq();
|
||
if(fb->len != (scale3_msg[type].ow * scale3_msg[type].oh * 3) / 2){
|
||
STREAM_FREE(fb->data); //释放之前的空间
|
||
fb->data = (uint8_t *)STREAM_MALLOC((scale3_msg[type].ow * scale3_msg[type].oh * 3) / 2); //申请到新的大空间
|
||
sys_dcache_invalid_range((void *)fb->data, (scale3_msg[type].ow * scale3_msg[type].oh * 3) / 2);
|
||
fb->len = (scale3_msg[type].ow * scale3_msg[type].oh * 3) / 2;
|
||
arg->ow = scale3_msg[type].ow;
|
||
arg->oh = scale3_msg[type].oh;
|
||
arg->ox = scale3_msg[type].x;
|
||
arg->oy = scale3_msg[type].y;
|
||
}
|
||
enable_irq(ie);
|
||
}
|
||
//这里要更改一下,看put到哪里去
|
||
if(type == 0){
|
||
fbpool_put(&scale3->tx_pool0, fb);
|
||
}else if(type == 1){
|
||
fbpool_put(&scale3->tx_pool1, fb);
|
||
}else if(type == 2){
|
||
fbpool_put(&scale3->tx_pool2, fb);
|
||
}else{
|
||
fbpool_put(&scale3->tx_poolerr, fb);
|
||
}
|
||
// 不需要内核去释放fb
|
||
ret = RET_OK + 1;
|
||
}
|
||
break;
|
||
|
||
case MSI_CMD_SCALE3:
|
||
{
|
||
uint32_t cmd_self = (uint32_t)param1;
|
||
//uint32_t arg = param2;
|
||
// 自定义命令
|
||
switch (cmd_self)
|
||
{
|
||
case MSI_SCALE3_START:
|
||
{
|
||
//注意,这里需要根据vpp那边配置来决定用哪个
|
||
//注意line buf的数量
|
||
uint8_t video_type = 0;
|
||
uint8_t *p_buf;
|
||
uint16_t videow,videoh;
|
||
struct fbpool * tx_pool;
|
||
struct framebuff *fb;
|
||
|
||
scale3->scaler3buf = SCALE3_LINE_BUF;
|
||
os_msgq_init(&scale3->msgq, MAX_SCALE3_TX);
|
||
|
||
OS_WORK_INIT(&scale3->work, scale3_stream_work, 0);
|
||
os_run_work_delay(&scale3->work, 1);
|
||
|
||
if(video_msg.video_num == 1){
|
||
video_type = ISP_VIDEO_0;
|
||
}else if(video_msg.video_num == 2){
|
||
video_type = video_msg.video_type_last; //
|
||
}else{
|
||
if((video_msg.video_type_cur == ISP_VIDEO_1)||(video_msg.video_type_cur == ISP_VIDEO_2)){
|
||
video_type = ISP_VIDEO_0;
|
||
}else if(video_msg.video_type_last == ISP_VIDEO_1){
|
||
video_type = ISP_VIDEO_2;
|
||
}else if(video_msg.video_type_last == ISP_VIDEO_2){
|
||
video_type = ISP_VIDEO_1;
|
||
}
|
||
}
|
||
|
||
if (SCALE3_YUVBUF_0_1 == 0)
|
||
{
|
||
extern uint8_t get_vpp_w_h(uint16_t *w, uint16_t *h);
|
||
get_vpp_w_h(&videow, &videoh);
|
||
}
|
||
else if (SCALE3_YUVBUF_0_1 == 1)
|
||
{
|
||
extern uint8_t get_vpp1_w_h(uint16_t *w, uint16_t *h);
|
||
get_vpp1_w_h(&videow, &videoh);
|
||
}
|
||
|
||
scale_set_start_addr(scale3->scale_dev, 0, 0);
|
||
// 暂时固定,如果遇到需要动态修改的,可以通过参数之类来切换
|
||
scale_set_dma_to_memory(scale3->scale_dev, 1);
|
||
scale_set_data_from_vpp(scale3->scale_dev, 1);
|
||
scale_set_line_buf_num(scale3->scale_dev, SCALE3_YUVBUF_Y_OFF_LINE);
|
||
|
||
|
||
scale3->ow = scale3_msg[video_type].ow;//ow;
|
||
scale3->oh = scale3_msg[video_type].oh;//oh;
|
||
scale3->iw = videow;//scale3_msg[video_type].iw;//iw;
|
||
scale3->ih = videoh;//scale3_msg[video_type].ih;//ih;
|
||
|
||
|
||
// 暂时用同样的iw ih ow oh
|
||
scale_set_in_out_size(scale3->scale_dev, scale3->iw, scale3->ih, scale3->ow, scale3->oh);
|
||
scale_set_step(scale3->scale_dev, scale3->iw, scale3->ih, scale3->ow, scale3->oh);
|
||
scale_set_in_yaddr(scale3->scale_dev, (uint32)scale3->scaler3buf);
|
||
scale_set_in_uaddr(scale3->scale_dev, (uint32)scale3->scaler3buf + scale3->iw * SCALE3_YUVBUF_Y_OFF_LINE);
|
||
scale_set_in_vaddr(scale3->scale_dev, (uint32)scale3->scaler3buf + scale3->iw * SCALE3_YUVBUF_Y_OFF_LINE + scale3->iw * SCALE3_YUVBUF_Y_OFF_LINE/4);
|
||
|
||
// 这里分配一下scale3的空间,通过标准接口去分配吧,理论这里一定能获取到,这里就不判断异常情况了
|
||
|
||
// 正常应该要获取到fb
|
||
if(scale3->txpool_type == 1){
|
||
fb = fbpool_get(&scale3->tx_pool0, 0, scale3->msi);
|
||
}else{
|
||
if(video_type == ISP_VIDEO_0){
|
||
tx_pool = &scale3->tx_pool0;
|
||
}else if(video_type == ISP_VIDEO_1){
|
||
tx_pool = &scale3->tx_pool1;
|
||
}else{
|
||
tx_pool = &scale3->tx_pool2;
|
||
}
|
||
fb = fbpool_get(tx_pool, 0, scale3->msi);
|
||
}
|
||
arg = (struct scale3_yuv_arg_s*)fb->priv;
|
||
arg->yuv_arg.x = scale3_msg[video_type].x;
|
||
arg->yuv_arg.y = scale3_msg[video_type].y;
|
||
//os_printf("arg w:%d arg h:%d\r\n",arg->yuv_arg.out_w,arg->yuv_arg.out_h);
|
||
|
||
p_buf = fb->data;
|
||
scale3->now_fb = fb;
|
||
|
||
scale_set_out_yaddr(scale3->scale_dev, (uint32)p_buf);
|
||
scale_set_out_uaddr(scale3->scale_dev, (uint32)p_buf + scale3->ow * scale3->oh);
|
||
scale_set_out_vaddr(scale3->scale_dev, (uint32)p_buf + scale3->ow * scale3->oh + scale3->ow * scale3->oh / 4);
|
||
scale_request_irq(scale3->scale_dev, FRAME_END, scale3_stream_done, (uint32)scale3);
|
||
scale_request_irq(scale3->scale_dev, INBUF_OV, scale3_stream_ov, (uint32)scale3);
|
||
scale_open(scale3->scale_dev);
|
||
// 由于硬件需要vpp参与,所以这里会耦合了其他硬件模块
|
||
struct vpp_device *vpp_dev;
|
||
vpp_dev = (struct vpp_device *)dev_get(HG_VPP_DEVID);
|
||
vpp_open(vpp_dev);
|
||
|
||
vppdone_func_register(SCALER3_DONE,scale3_vpp_done_func,(uint32)scale3);
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
extern scale3_kick_fn scale3_kick_func;
|
||
int32_t scaler3_kick_start(){
|
||
struct msi *msi = msi_find(S_PREVIEW_SCALE3, 0);
|
||
msi_do_cmd(msi, MSI_CMD_SCALE3, MSI_SCALE3_START, 0);
|
||
msi_put(msi);
|
||
scale3_kick_func = NULL;
|
||
return 0;
|
||
}
|
||
|
||
|
||
// 参数分别是vpp的图像iw和ih,要scale的ow和oh,如果和屏有关,可以传入屏幕的宽高
|
||
struct msi *scale3_msi(const char *name)
|
||
{
|
||
struct msi *msi = msi_new(name, 0, NULL);
|
||
|
||
if(msi == NULL){
|
||
return NULL;
|
||
}
|
||
|
||
struct scale3_msi_s *scale3 = (struct scale3_msi_s *)msi->priv;
|
||
struct scale_msg_t *scale_msg[3];
|
||
uint8_t *fbuf;
|
||
|
||
scale_msg[0] = &scale3_msg[0];
|
||
scale_msg[1] = &scale3_msg[1];
|
||
scale_msg[2] = &scale3_msg[2];
|
||
|
||
if (!scale3)
|
||
{
|
||
// os_printf("%s:%d new success\n", __FUNCTION__, __LINE__);
|
||
scale3 = (struct scale3_msi_s *)STREAM_LIBC_ZALLOC(sizeof(struct scale3_msi_s));
|
||
msi->action = scale3_msi_action;
|
||
msi->priv = (void *)scale3;
|
||
scale3->msi = msi;
|
||
scale3->scale_dev = (struct scale_device *)dev_get(HG_SCALE3_DEVID);
|
||
scale3->txpool_type = 0;
|
||
|
||
int temp_video_num = video_msg.video_num;
|
||
scale3->init_txpool_num = temp_video_num;
|
||
|
||
for(int init_txpool_num = 0; init_txpool_num < temp_video_num ; init_txpool_num++) {
|
||
int fbpool_init_size = 0;
|
||
|
||
//if (SCALE3_YUVBUF_0_1 == 0)
|
||
//{
|
||
// extern uint8_t get_vpp_w_h(uint16_t *w, uint16_t *h);
|
||
//get_vpp_w_h(&scale_msg[init_txpool_num]->iw, &scale_msg[init_txpool_num]->ih);
|
||
//}
|
||
//else if (SCALE3_YUVBUF_0_1 == 1)
|
||
//{
|
||
// extern uint8_t get_vpp1_w_h(uint16_t *w, uint16_t *h);
|
||
//get_vpp1_w_h(&scale_msg[init_txpool_num]->iw, &scale_msg[init_txpool_num]->ih);
|
||
//}
|
||
|
||
switch (init_txpool_num)
|
||
{
|
||
/* txpool0 */
|
||
case 0:
|
||
{
|
||
fbpool_init_size = 2;
|
||
if (temp_video_num == 1) {
|
||
fbpool_init_size++;
|
||
scale3->txpool_type = 1;
|
||
}
|
||
}
|
||
break;
|
||
|
||
/* txpool1 */
|
||
case 1:
|
||
{
|
||
fbpool_init_size = 2;
|
||
if(temp_video_num > 2)
|
||
fbpool_init_size--;
|
||
}
|
||
break;
|
||
|
||
/* txpool2 */
|
||
case 2:
|
||
{
|
||
fbpool_init_size = 1;
|
||
}
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
os_printf("scale3 init txpool num:%d size:%d txpool0:0x%x txpool1:0x%x txpool2:0x%x\r\n",init_txpool_num,fbpool_init_size, &scale3->tx_pool0 + 0, &scale3->tx_pool0 + 1, &scale3->tx_pool0 + 2);
|
||
fbpool_init(&scale3->tx_pool0 + init_txpool_num, fbpool_init_size);
|
||
for(int i = 0; i < fbpool_init_size; i++) {
|
||
struct scale3_yuv_arg_s *yuv_priv = (struct scale3_yuv_arg_s *)STREAM_LIBC_ZALLOC(sizeof(struct scale3_yuv_arg_s));
|
||
struct yuv_arg_s *yuv = (struct yuv_arg_s *)yuv_priv;
|
||
scale3->ow = scale_msg[init_txpool_num]->ow;
|
||
scale3->oh = scale_msg[init_txpool_num]->oh;
|
||
yuv->y_size = scale3->ow * scale3->oh;
|
||
yuv->uv_off = 0;
|
||
yuv->y_off = 0;
|
||
yuv->out_w = scale3->ow;
|
||
yuv->out_h = scale3->oh;
|
||
yuv->del = &scale3->del;
|
||
|
||
yuv_priv->tx_type = init_txpool_num;
|
||
yuv_priv->ow = scale3->ow;
|
||
yuv_priv->oh = scale3->oh;
|
||
|
||
fbuf = (uint8_t *)STREAM_MALLOC(scale3->ow * scale3->oh * 3 / 2);
|
||
FBPOOL_SET_INFO(&scale3->tx_pool0 + init_txpool_num, i, fbuf, scale3->ow * scale3->oh * 3 / 2, (void *)yuv);
|
||
}
|
||
|
||
}
|
||
|
||
fbpool_init(&scale3->tx_poolerr, 1);
|
||
struct scale3_yuv_arg_s * yuv_priv = (struct scale3_yuv_arg_s *)STREAM_LIBC_ZALLOC(sizeof(struct scale3_yuv_arg_s));
|
||
struct yuv_arg_s *yuv = (struct yuv_arg_s *)yuv_priv;
|
||
yuv->y_size = 128 * 96;
|
||
yuv->uv_off = 0;
|
||
yuv->y_off = 0;
|
||
yuv->out_w = 128;
|
||
yuv->out_h = 96;
|
||
yuv->del = &scale3->del;
|
||
scale3->ow = 128;
|
||
scale3->oh = 96;
|
||
yuv_priv->tx_type = 4;
|
||
fbuf = (uint8_t *)STREAM_MALLOC(128 * 96 * 3 / 2);
|
||
FBPOOL_SET_INFO(&scale3->tx_poolerr, 0, fbuf, 128 * 96 * 3 / 2, (void *)yuv);
|
||
|
||
msi->enable = 1;
|
||
|
||
scale3_kick_func = scaler3_kick_start;
|
||
|
||
}
|
||
os_printf("%s:%d\tmsi:%X\n", __FUNCTION__, __LINE__, msi);
|
||
return msi;
|
||
}
|
||
|
||
|
||
|
||
static int32_t const_scale3_msi_action(struct msi *msi, uint32_t cmd_id, uint32_t param1, uint32_t param2)
|
||
{
|
||
int32_t ret = RET_OK;
|
||
struct const_scale3_msi_s *scale3 = (struct const_scale3_msi_s *)msi->priv;
|
||
switch (cmd_id)
|
||
{
|
||
|
||
// 这里msi已经被删除,那么就要考虑tx_pool的资源释放了
|
||
// 能进来这里,就是代表所有fb都已经用完了
|
||
case MSI_CMD_POST_DESTROY:
|
||
{
|
||
STREAM_LIBC_FREE(scale3);
|
||
}
|
||
break;
|
||
|
||
// 停止硬件,移除没有必要的资源(但是fb的资源不能现在删除,这个时候fb可能外部还在调用)
|
||
case MSI_CMD_PRE_DESTROY:
|
||
{
|
||
|
||
}
|
||
break;
|
||
|
||
|
||
default:
|
||
break;
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
static int32_t const_scale3_stream_done(uint32 irq_flag, uint32 irq_data, uint32 param1)
|
||
{
|
||
_os_printf("CO");
|
||
return 0;
|
||
}
|
||
|
||
void scale3_output_size_local_change(uint8_t id,uint8_t show_only,uint16 x,uint16 y,uint16 w,uint16 h){
|
||
uint32 ie;
|
||
ie = disable_irq();
|
||
scale3_msg[id].x = x;
|
||
scale3_msg[id].y = y;
|
||
scale3_msg[id].ow = w;
|
||
scale3_msg[id].oh = h;
|
||
scale3_msg[id].video_only = show_only;
|
||
enable_irq(ie);
|
||
}
|
||
|
||
//固定空间,由外部给空间,不再采用流的方式
|
||
//buf需要给够空间,根据ow和oh来计算
|
||
struct msi *scale3_msi_const_buf(const char *name, uint8_t *buf,uint16_t iw, uint16_t ih, uint16_t ow, uint16_t oh)
|
||
{
|
||
uint8_t isnew;
|
||
struct msi *msi = msi_new(name, 0, &isnew);
|
||
if (isnew)
|
||
{
|
||
struct scale_device *scale_dev = (struct scale_device *)dev_get(HG_SCALE3_DEVID);
|
||
os_printf("%s:%d new success\n", __FUNCTION__, __LINE__);
|
||
struct const_scale3_msi_s *scale3 = (struct const_scale3_msi_s *)STREAM_LIBC_ZALLOC(sizeof(struct const_scale3_msi_s));
|
||
scale3->scale_dev = scale_dev;
|
||
msi->priv = (void *)scale3;
|
||
msi->action = const_scale3_msi_action;
|
||
msi->enable = 0;
|
||
|
||
// 暂时用同样的iw ih ow oh
|
||
scale_set_in_out_size(scale_dev, iw, ih, ow, oh);
|
||
scale_set_step(scale_dev, iw, ih, ow, oh);
|
||
scale_set_start_addr(scale_dev, 0, 0);
|
||
// 暂时固定,如果遇到需要动态修改的,可以通过参数之类来切换
|
||
scale_set_dma_to_memory(scale_dev, 1);
|
||
scale_set_data_from_vpp(scale_dev, 1);
|
||
scale_set_line_buf_num(scale_dev, 28);
|
||
scale_set_in_yaddr(scale_dev, (uint32)yuvbuf);
|
||
scale_set_in_uaddr(scale_dev, (uint32)yuvbuf + iw * 28);
|
||
scale_set_in_vaddr(scale_dev, (uint32)yuvbuf + iw * 28 + iw * 28/4);
|
||
|
||
|
||
|
||
scale_set_out_yaddr(scale_dev, (uint32)buf);
|
||
scale_set_out_uaddr(scale_dev, (uint32)buf + ow * oh);
|
||
scale_set_out_vaddr(scale_dev, (uint32)buf + ow * oh + ow * oh / 4);
|
||
scale_request_irq(scale_dev, FRAME_END, const_scale3_stream_done, (uint32)scale3);
|
||
scale_request_irq(scale_dev, INBUF_OV, scale3_stream_ov, (uint32)scale3);
|
||
scale_open(scale_dev);
|
||
// 由于硬件需要vpp参与,所以这里会耦合了其他硬件模块
|
||
struct vpp_device *vpp_dev;
|
||
vpp_dev = (struct vpp_device *)dev_get(HG_VPP_DEVID);
|
||
vpp_open(vpp_dev);
|
||
|
||
}
|
||
os_printf("%s:%d\tmsi:%X\n", __FUNCTION__, __LINE__, msi);
|
||
return msi;
|
||
}
|