sdk-hwV1.3/lichee/rtos-hal/hal/source/vin/vin_vipp/sunxi_scaler.c

634 lines
21 KiB
C
Raw Normal View History

2024-05-07 10:09:20 +00:00
/*
* sunxi_scaler.c for scaler and osd v4l2 subdev
*
* Copyright (c) 2017 by Allwinnertech Co., Ltd. http://www.allwinnertech.com
*
* Authors: Zhao Wei <zhaowei@allwinnertech.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <hal_mem.h>
#include <hal_interrupt.h>
#include "../vin.h"
#include "../platform/platform_cfg.h"
#include "sunxi_scaler.h"
#include "../vin_video/vin_core.h"
struct scaler_dev *global_scaler[VIN_MAX_SCALER];
bool scaler_probe_flag[VIN_MAX_SCALER];
#define VIPP_ISR_EN
#define ALIGN_4B(x) (((x) + (3)) & ~(3))
#define ALIGN_2B(x) (((x) + (1)) & ~(1))
#define MIN_IN_WIDTH 192
#define MIN_IN_HEIGHT 128
#define MAX_IN_WIDTH 4224
#define MAX_IN_HEIGHT 4224
#define MIN_OUT_WIDTH 16
#define MIN_OUT_HEIGHT 10
#define MAX_OUT_WIDTH 4224
#define MAX_OUT_HEIGHT 4224
#define MIN_RATIO 256
#define MAX_RATIO 4096
static int __scaler_w_shift(int x_ratio, int y_ratio)
{
int m, n;
int sum_weight = 0;
int weight_shift;
int xr = (x_ratio >> 8) + 1;
int yr = (y_ratio >> 8) + 1;
int weight_shift_bak = 0;
weight_shift = -9;
for (weight_shift = 17; weight_shift > 0; weight_shift--) {
sum_weight = 0;
for (m = 0; m <= xr; m++) {
for (n = 0; n <= yr; n++) {
sum_weight += (y_ratio - abs((n << 8) - (yr << 7)))*
(x_ratio - abs((m << 8) - (yr << 7))) >> (weight_shift + 8);
}
}
if (sum_weight > 0 && sum_weight < 256)
weight_shift_bak = weight_shift;
if (sum_weight > 255 && sum_weight < 486)
break;
}
if (weight_shift == 0)
weight_shift = weight_shift_bak;
return weight_shift;
}
static void __scaler_calc_ratios(unsigned int id, struct v4l2_rect *input,
struct scaler_para *para)
{
unsigned int width;
unsigned int height;
unsigned int r_min;
global_video[id].o_width = clamp(global_video[id].o_width, MIN_IN_WIDTH, input->width);
global_video[id].o_height =
clamp(global_video[id].o_height, MIN_IN_HEIGHT, input->height);
para->xratio = 256 * input->width / global_video[id].o_width;
para->yratio = 256 * input->height / global_video[id].o_height;
para->xratio = clamp(para->xratio, MIN_RATIO, MAX_RATIO);
para->yratio = clamp(para->yratio, MIN_RATIO, MAX_RATIO);
r_min = min(para->xratio, para->yratio);
if (para->xratio == para->yratio) {
width = min(ALIGN(global_video[id].o_width * r_min / 256, 2), input->width);
height = min(ALIGN(global_video[id].o_height * r_min / 256, 2), input->height);
para->width = global_video[id].o_width;
para->height = global_video[id].o_height;
vin_log(VIN_LOG_SCALER, "para: xr = %ld, yr = %ld, w = %ld, h = %ld\n",
para->xratio, para->yratio, para->width, para->height);
/* Center the new crop rectangle.
* crop is before scaler
*/
input->left += (input->width - width) / 2;
input->top += (input->height - height) / 2;
input->left = ALIGN(input->left, 2);
input->top = ALIGN(input->top, 1);
input->width = width;
input->height = height;
} else {
width = ALIGN_4B(global_video[id].o_width * r_min / 256);
height = ALIGN_2B(global_video[id].o_height * r_min / 256);
para->xratio = 256 * width / global_video[id].o_width;
para->yratio = 256 * height / global_video[id].o_height;
para->xratio = clamp(para->xratio, MIN_RATIO, MAX_RATIO);
para->yratio = clamp(para->yratio, MIN_RATIO, MAX_RATIO);
para->width = global_video[id].o_width;
para->height = global_video[id].o_height;
vin_log(VIN_LOG_SCALER, "para: xr = %ld, yr = %ld, w = %ld, h = %ld\n",
para->xratio, para->yratio, para->width, para->height);
/* Center the new crop rectangle.
* crop is before scaler
*/
input->left += (input->width - width) / 2;
input->top += (input->height - height) / 2;
input->left = ALIGN_4B(input->left);
input->top = ALIGN_2B(input->top);
input->width = width;
input->height = height;
}
vin_log(VIN_LOG_SCALER, "crop: left = %ld, top = %ld, w = %ld, h = %ld\n",
input->left, input->top, input->width, input->height);
}
#ifdef VIPP_REG_MODE
static int sunxi_scaler_subdev_init(unsigned int id)
{
struct scaler_dev *scaler = global_scaler[id];
memset((void *)scaler->vipp_reg.phy_addr, 0, VIPP_REG_SIZE);
scaler->load_select = true;
vipp_set_reg_load_addr(scaler->id, (unsigned long)scaler->load_para[0].phy_addr);
vipp_set_osd_cv_update(scaler->id, NOT_UPDATED);
vipp_set_osd_ov_update(scaler->id, NOT_UPDATED);
vipp_set_para_ready(scaler->id, NOT_READY);
return 0;
}
#endif
static int sunxi_scaler_logic_s_stream(unsigned int virtual_id, int on)
{
unsigned char logic_id = vipp_virtual_find_logic[virtual_id];
struct scaler_dev *logic_scaler = global_scaler[logic_id];
int i;
if (logic_scaler->work_mode == VIPP_ONLINE && virtual_id != logic_id) {
vin_err("vipp%d work on online mode, vipp%d cannot to work!!\n", logic_id, virtual_id);
return -1;
}
if (on && (logic_scaler->logic_top_stream_count)++ > 0)
return 0;
else if (!on && (logic_scaler->logic_top_stream_count == 0 || --(logic_scaler->logic_top_stream_count) > 0))
return 0;
if (on) {
vipp_cap_disable(logic_scaler->id);
for (i = 0; i < VIPP_VIRT_NUM; i++)
vipp_chn_cap_disable(logic_scaler->id);
vipp_work_mode(logic_scaler->id, logic_scaler->work_mode);
vipp_top_clk_en(logic_scaler->id, on);
vipp_clear_status(logic_scaler->id, VIPP_STATUS_ALL);
#ifdef VIPP_ISR_EN
#if 0
vipp_irq_enable(logic_scaler->id, ID_LOST_EN | AHB_MBUS_W_EN |
CHN0_REG_LOAD_EN | CHN0_FRAME_LOST_EN | CHN0_HBLANK_SHORT_EN | CHN0_PARA_NOT_READY_EN |
CHN1_REG_LOAD_EN | CHN1_FRAME_LOST_EN | CHN1_HBLANK_SHORT_EN | CHN1_PARA_NOT_READY_EN |
CHN2_REG_LOAD_EN | CHN2_FRAME_LOST_EN | CHN2_HBLANK_SHORT_EN | CHN2_PARA_NOT_READY_EN |
CHN3_REG_LOAD_EN | CHN3_FRAME_LOST_EN | CHN3_HBLANK_SHORT_EN | CHN3_PARA_NOT_READY_EN);
#else
vipp_irq_enable(logic_scaler->id, ID_LOST_EN | AHB_MBUS_W_EN |
CHN0_FRAME_LOST_EN | CHN0_HBLANK_SHORT_EN | CHN0_PARA_NOT_READY_EN |
CHN1_FRAME_LOST_EN | CHN1_HBLANK_SHORT_EN | CHN1_PARA_NOT_READY_EN |
CHN2_FRAME_LOST_EN | CHN2_HBLANK_SHORT_EN | CHN2_PARA_NOT_READY_EN |
CHN3_FRAME_LOST_EN | CHN3_HBLANK_SHORT_EN | CHN3_PARA_NOT_READY_EN);
hal_enable_irq(logic_scaler->irq);
#endif
#endif
vipp_cap_enable(logic_scaler->id);
} else {
hal_disable_irq(logic_scaler->irq);
vipp_cap_disable(logic_scaler->id);
vipp_clear_status(logic_scaler->id, VIPP_STATUS_ALL);
vipp_irq_disable(logic_scaler->id, VIPP_EN_ALL);
vipp_top_clk_en(logic_scaler->id, on);
}
return 0;
}
int sunxi_scaler_subdev_s_stream(unsigned int id, int enable)
{
struct scaler_dev *scaler = global_scaler[id];
struct vipp_scaler_config scaler_cfg;
struct vipp_scaler_size scaler_size;
struct vipp_crop crop;
enum vipp_format out_fmt;
enum vipp_format sc_fmt;
struct sensor_format_struct *sensor_format;
int sensor_id = global_video[scaler->id].rear_sensor;
int isp_sel = global_video[scaler->id].isp_sel;
int *stream_count;
stream_count = &scaler->stream_count;
if (enable && (*stream_count)++ > 0)
return 0;
else if (!enable && (*stream_count == 0 || --(*stream_count) > 0))
return 0;
switch (global_video[id].fourcc) {
case V4L2_PIX_FMT_SBGGR8:
case V4L2_PIX_FMT_SGBRG8:
case V4L2_PIX_FMT_SGRBG8:
case V4L2_PIX_FMT_SRGGB8:
case V4L2_PIX_FMT_SBGGR10:
case V4L2_PIX_FMT_SGBRG10:
case V4L2_PIX_FMT_SGRBG10:
case V4L2_PIX_FMT_SRGGB10:
case V4L2_PIX_FMT_SBGGR12:
case V4L2_PIX_FMT_SGBRG12:
case V4L2_PIX_FMT_SGRBG12:
case V4L2_PIX_FMT_SRGGB12:
vin_log(VIN_LOG_FMT, "%s output fmt is raw, return directly\n", __func__);
return 0;
default:
break;
}
if (global_sensors[sensor_id].sensor_core->sensor_g_format)
sensor_format = global_sensors[sensor_id].sensor_core->sensor_g_format(sensor_id, isp_sel);
else
return -1;
if (sensor_format->field == V4L2_FIELD_INTERLACED || sensor_format->field == V4L2_FIELD_TOP ||
sensor_format->field == V4L2_FIELD_BOTTOM) {
vin_log(VIN_LOG_SCALER, "Scaler not support field mode, return directly!\n");
return 0;
}
if (enable) {
if (sunxi_scaler_logic_s_stream(scaler->id, enable))
return -1;
crop.hor = scaler->crop.active.left;
crop.ver = scaler->crop.active.top;
crop.width = scaler->crop.active.width;
crop.height = scaler->crop.active.height;
vipp_set_crop(scaler->id, &crop);
scaler_size.sc_width = scaler->para.width;
scaler_size.sc_height = scaler->para.height;
vipp_scaler_output_size(scaler->id, &scaler_size);
switch (global_video[id].fourcc) {
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YUV420M:
case V4L2_PIX_FMT_YVU420:
case V4L2_PIX_FMT_YVU420M:
case V4L2_PIX_FMT_NV21:
case V4L2_PIX_FMT_NV21M:
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV12M:
case V4L2_PIX_FMT_FBC:
case V4L2_PIX_FMT_LBC_2_0X:
case V4L2_PIX_FMT_LBC_2_5X:
case V4L2_PIX_FMT_LBC_1_0X:
if (scaler->id < MAX_OSD_NUM) {
sc_fmt = YUV422;
out_fmt = YUV420;
vipp_chroma_ds_en(scaler->id, 1);
} else {
sc_fmt = YUV420;
out_fmt = YUV420;
}
break;
case V4L2_PIX_FMT_YUV422P:
case V4L2_PIX_FMT_NV16:
case V4L2_PIX_FMT_NV61:
case V4L2_PIX_FMT_NV61M:
case V4L2_PIX_FMT_NV16M:
sc_fmt = YUV422;
out_fmt = YUV422;
break;
default:
sc_fmt = YUV420;
out_fmt = YUV420;
break;
}
scaler_cfg.sc_out_fmt = sc_fmt;
scaler_cfg.sc_x_ratio = scaler->para.xratio;
scaler_cfg.sc_y_ratio = scaler->para.yratio;
scaler_cfg.sc_w_shift = __scaler_w_shift(scaler->para.xratio, scaler->para.yratio);
vipp_scaler_cfg(scaler->id, &scaler_cfg);
vipp_output_fmt_cfg(scaler->id, out_fmt);
vipp_scaler_en(scaler->id, 1);
vipp_osd_en(scaler->id, 1);
vipp_set_osd_ov_update(scaler->id, HAS_UPDATED);
vipp_set_osd_cv_update(scaler->id, HAS_UPDATED);
memcpy(scaler->load_para[0].phy_addr, scaler->vipp_reg.phy_addr, VIPP_REG_SIZE);
vipp_set_para_ready(scaler->id, HAS_READY);
vipp_chn_cap_enable(scaler->id);
} else {
vipp_chn_cap_disable(scaler->id);
vipp_set_para_ready(scaler->id, NOT_READY);
vipp_chroma_ds_en(scaler->id, 0);
vipp_osd_en(scaler->id, 0);
vipp_scaler_en(scaler->id, 0);
vipp_set_osd_ov_update(scaler->id, NOT_UPDATED);
vipp_set_osd_cv_update(scaler->id, NOT_UPDATED);
sunxi_scaler_logic_s_stream(scaler->id, enable);
}
vin_log(VIN_LOG_FMT, "vipp%d %s, %ld*%ld hoff: %ld voff: %ld xr: %ld yr: %ld\n",
scaler->id, enable ? "stream on" : "stream off",
scaler->para.width, scaler->para.height,
scaler->crop.active.left, scaler->crop.active.top,
scaler->para.xratio, scaler->para.yratio);
return 0;
}
#ifdef VIPP_ISR_EN
static hal_irqreturn_t scaler_isr(void *priv)
{
uint32_t __cpsr;
struct scaler_dev *scaler = (struct scaler_dev *)priv;
struct vipp_status vipp_status;
memset(&vipp_status, 0, sizeof(struct vipp_status));
vipp_get_status(scaler->id, &vipp_status);
__cpsr = hal_spin_lock_irqsave(&scaler->slock);
if (vipp_status.id_lost_pd) {
vipp_clear_status(scaler->id, ID_LOST_PD);
vin_err("scaler%d channel ID nember is lost!!!\n", scaler->id);
}
if (vipp_status.ahb_mbus_w_pd) {
vipp_clear_status(scaler->id, VIPPAHB_MBUS_W_PD);
vin_err("scaler%d AHB and MBUS write conflict!!!\n", scaler->id);
}
if (vipp_status.chn0_frame_lost_pd) {
vipp_clear_status(scaler->id, CHN0_FRAME_LOST_PD);
vin_err("scaler%d frame lost!!!\n", scaler->id + 0);
}
if (vipp_status.chn1_frame_lost_pd) {
vipp_clear_status(scaler->id, CHN1_FRAME_LOST_PD);
vin_err("scaler%d frame lost!!!\n", scaler->id + 1);
}
if (vipp_status.chn2_frame_lost_pd) {
vipp_clear_status(scaler->id, CHN2_FRAME_LOST_PD);
vin_err("scaler%d frame lost!!!\n", scaler->id + 2);
}
if (vipp_status.chn3_frame_lost_pd) {
vipp_clear_status(scaler->id, CHN3_FRAME_LOST_PD);
vin_err("scaler%d frame lost!!!\n", scaler->id + 3);
}
if (vipp_status.chn0_hblank_short_pd) {
vipp_clear_status(scaler->id, CHN0_HBLANK_SHORT_PD);
vin_err("scaler%d Hblank short!!!\n", scaler->id + 0);
}
if (vipp_status.chn1_hblank_short_pd) {
vipp_clear_status(scaler->id, CHN1_HBLANK_SHORT_PD);
vin_err("scaler%d Hblank short!!!\n", scaler->id + 1);
}
if (vipp_status.chn2_hblank_short_pd) {
vipp_clear_status(scaler->id, CHN2_HBLANK_SHORT_PD);
vin_err("scaler%d Hblank short!!!\n", scaler->id + 2);
}
if (vipp_status.chn3_hblank_short_pd) {
vipp_clear_status(scaler->id, CHN3_HBLANK_SHORT_PD);
vin_err("scaler%d Hblank short!!!\n", scaler->id + 3);
}
if (vipp_status.chn0_para_not_ready_pd) {
vipp_clear_status(scaler->id, CHN0_PARA_NOT_READY_PD);
vin_err("scaler%d param not ready!!!\n", scaler->id + 0);
}
if (vipp_status.chn1_para_not_ready_pd) {
vipp_clear_status(scaler->id, CHN1_PARA_NOT_READY_PD);
vin_err("scaler%d param not ready!!!\n", scaler->id + 1);
}
if (vipp_status.chn2_para_not_ready_pd) {
vipp_clear_status(scaler->id, CHN2_PARA_NOT_READY_PD);
vin_err("scaler%d param not ready!!!\n", scaler->id + 2);
}
if (vipp_status.chn3_para_not_ready_pd) {
vipp_clear_status(scaler->id, CHN3_PARA_NOT_READY_PD);
vin_err("scaler%d param not ready!!!\n", scaler->id + 3);
}
if (vipp_status.chn0_reg_load_pd) {
vipp_clear_status(scaler->id, CHN0_REG_LOAD_PD);
if (!vipp_get_irq_en(scaler->id, CHN0_REG_LOAD_EN)) {
hal_spin_unlock_irqrestore(&scaler->slock, __cpsr);
return 0;
}
vin_print("vipp%d change to load reg\n", scaler->id);
if (scaler->load_select) {
memcpy(scaler->load_para[1].phy_addr, scaler->vipp_reg.phy_addr, VIPP_REG_SIZE);
vipp_set_reg_load_addr(scaler->id, (unsigned long)scaler->load_para[1].phy_addr);
scaler->load_select = false;
} else {
memcpy(scaler->load_para[0].phy_addr, scaler->vipp_reg.phy_addr, VIPP_REG_SIZE);
vipp_set_reg_load_addr(scaler->id, (unsigned long)scaler->load_para[0].phy_addr);
scaler->load_select = true;
}
vipp_irq_disable(scaler->id, CHN0_REG_LOAD_EN);
}
if (vipp_status.chn1_reg_load_pd) {
vipp_clear_status(scaler->id, CHN1_REG_LOAD_PD);
if (!vipp_get_irq_en(scaler->id, CHN1_REG_LOAD_EN)) {
hal_spin_unlock_irqrestore(&scaler->slock, __cpsr);
return 0;
}
vin_print("vipp%d change to load reg\n", scaler->id + 1);
if (global_scaler[scaler->id + 1]->load_select) {
memcpy(global_scaler[scaler->id + 1]->load_para[1].phy_addr, global_scaler[scaler->id + 1]->vipp_reg.phy_addr, VIPP_REG_SIZE);
vipp_set_reg_load_addr(global_scaler[scaler->id + 1]->id, (unsigned long)global_scaler[scaler->id + 1]->load_para[1].phy_addr);
scaler->load_select = false;
} else {
memcpy(global_scaler[scaler->id + 1]->load_para[0].phy_addr, global_scaler[scaler->id + 1]->vipp_reg.phy_addr, VIPP_REG_SIZE);
vipp_set_reg_load_addr(global_scaler[scaler->id + 1]->id, (unsigned long)global_scaler[scaler->id + 1]->load_para[0].phy_addr);
scaler->load_select = true;
}
vipp_irq_disable(scaler->id, CHN1_REG_LOAD_EN);
}
if (vipp_status.chn2_reg_load_pd) {
vipp_clear_status(scaler->id, CHN2_REG_LOAD_PD);
if (!vipp_get_irq_en(scaler->id, CHN2_REG_LOAD_EN)) {
hal_spin_unlock_irqrestore(&scaler->slock, __cpsr);
return 0;
}
vin_print("vipp%d change to load reg\n", scaler->id + 2);
if (global_scaler[scaler->id + 2]->load_select) {
memcpy(global_scaler[scaler->id + 2]->load_para[1].phy_addr, global_scaler[scaler->id + 2]->vipp_reg.phy_addr, VIPP_REG_SIZE);
vipp_set_reg_load_addr(global_scaler[scaler->id + 2]->id, (unsigned long)global_scaler[scaler->id + 2]->load_para[1].phy_addr);
scaler->load_select = false;
} else {
memcpy(global_scaler[scaler->id + 2]->load_para[0].phy_addr, global_scaler[scaler->id + 2]->vipp_reg.phy_addr, VIPP_REG_SIZE);
vipp_set_reg_load_addr(global_scaler[scaler->id + 2]->id, (unsigned long)global_scaler[scaler->id + 2]->load_para[0].phy_addr);
scaler->load_select = true;
}
vipp_irq_disable(scaler->id, CHN2_REG_LOAD_EN);
}
if (vipp_status.chn3_reg_load_pd) {
vipp_clear_status(scaler->id, CHN3_REG_LOAD_PD);
if (!vipp_get_irq_en(scaler->id, CHN3_REG_LOAD_EN)) {
hal_spin_unlock_irqrestore(&scaler->slock, __cpsr);
return 0;
}
vin_print("vipp%d change to load reg\n", scaler->id + 3);
if (global_scaler[scaler->id + 3]->load_select) {
memcpy(global_scaler[scaler->id + 3]->load_para[1].phy_addr, global_scaler[scaler->id + 3]->vipp_reg.phy_addr, VIPP_REG_SIZE);
vipp_set_reg_load_addr(global_scaler[scaler->id + 3]->id, (unsigned long)global_scaler[scaler->id + 3]->load_para[1].phy_addr);
scaler->load_select = false;
} else {
memcpy(global_scaler[scaler->id + 3]->load_para[0].phy_addr, global_scaler[scaler->id + 3]->vipp_reg.phy_addr, VIPP_REG_SIZE);
vipp_set_reg_load_addr(global_scaler[scaler->id + 3]->id, (unsigned long)global_scaler[scaler->id + 3]->load_para[0].phy_addr);
scaler->load_select = true;
}
vipp_irq_disable(scaler->id, CHN3_REG_LOAD_EN);
}
hal_spin_unlock_irqrestore(&scaler->slock, __cpsr);
return 0;
}
#endif
#ifdef VIPP_REG_MODE
static int scaler_resource_alloc(unsigned int id)
{
struct scaler_dev *scaler = global_scaler[id];
scaler->vipp_reg.size = 3 * VIPP_REG_SIZE;
scaler->vipp_reg.phy_addr = rt_memheap_alloc_align(&isp_mempool, scaler->vipp_reg.size, 0x1000);
if (scaler->vipp_reg.phy_addr == NULL) {
vin_err("%s:vipp%d:alloc vipp buffer error\n", __func__, id);
return -1;
}
memset(scaler->vipp_reg.phy_addr, 0, scaler->vipp_reg.size);
//vin_print("%s:vipp_reg phy_addr is 0x%x\n", __func__, (unsigned long)scaler->vipp_reg.phy_addr);
scaler->load_para[0].phy_addr = scaler->vipp_reg.phy_addr + VIPP_REG_SIZE;
scaler->load_para[1].phy_addr = scaler->vipp_reg.phy_addr + VIPP_REG_SIZE * 2;
return 0;
}
static void scaler_resource_free(unsigned int id)
{
//struct scaler_dev *scaler = global_scaler[id];
}
#endif
int scaler_probe(unsigned int id)
{
struct scaler_dev *scaler = NULL;
struct scaler_dev *logic_scaler = NULL;
struct sensor_format_struct *sensor_format;
int sensor_id = global_video[id].rear_sensor;
int isp_sel = global_video[id].isp_sel;
int ret = 0;
if (scaler_probe_flag[id])
return 0;
else
scaler_probe_flag[id] = true;
if (id > VIN_MAX_SCALER) {
vin_err("vipp%d is not existing, max is %d\n", id, VIN_MAX_SCALER);
return -1;
}
scaler = hal_malloc(sizeof(struct scaler_dev));
if (!scaler) {
ret = -1;
goto ekzalloc;
}
memset(scaler, 0, sizeof(struct scaler_dev));
scaler->id = id;
if (scaler->id == vipp_virtual_find_logic[scaler->id]) {
scaler->work_mode = vin_work_mode;//clamp(scaler->work_mode, VIPP_ONLINE, VIPP_OFFLINE);
} else {
scaler->work_mode = 0xff;
logic_scaler = global_scaler[vipp_virtual_find_logic[scaler->id]];
if (logic_scaler->work_mode == VIPP_ONLINE) { /*logic vipp work in online*/
vin_log(VIN_LOG_VIDEO, "scaler%d work in online mode, scaler%d cannot to work!\n", logic_scaler->id, scaler->id);
global_scaler[scaler->id] = scaler;
scaler->noneed_register = 1;
vin_log(VIN_LOG_SCALER, "scaler%d probe end\n", scaler->id);
return 0;
}
}
scaler->base = sunxi_vin_get_scaler_base(scaler->id);
if (!scaler->base) {
vin_err("Fail to get VIPP base addr!\n");
ret = -1;
goto freedev;
}
vin_log(VIN_LOG_MD, "vipp%d base reg is 0x%lx\n", scaler->id, scaler->base);
global_scaler[id] = scaler;
#ifdef VIPP_REG_MODE
scaler_resource_alloc(id);
#endif
vipp_set_base_addr(scaler->id, scaler->base);
#ifdef VIPP_REG_MODE
vipp_map_reg_load_addr(scaler->id, (unsigned long)scaler->vipp_reg.phy_addr);
sunxi_scaler_subdev_init(id);
#endif
#ifdef VIPP_ISR_EN
/*get irq resource */
if (scaler->id == vipp_virtual_find_logic[scaler->id]) {
scaler->irq = sunxi_vin_get_vipp_irq(scaler->id);
if (scaler->irq <= 0) {
scaler->is_irq_empty = 1;
if (scaler->id == vipp_virtual_find_logic[scaler->id])
vin_err("failed to get vipp%d IRQ resource\n", scaler->id);
} else {
ret = hal_request_irq(scaler->irq, scaler_isr, "sunxi_scaler", scaler);
if (ret != scaler->irq) {
vin_err("vipp%d request irq failed\n", scaler->id);
ret = -1;
goto freedev;
}
}
}
#endif
if (global_sensors[sensor_id].sensor_core->sensor_g_format) {
sensor_format = global_sensors[sensor_id].sensor_core->sensor_g_format(sensor_id, isp_sel);
} else {
vin_err("%s sensor_g_format failed!!!!\n", global_sensors[sensor_id].sensor_name);
return -1;
}
scaler->crop.active.width = sensor_format->width;
scaler->crop.active.height = sensor_format->height;
__scaler_calc_ratios(id, &scaler->crop.active, &scaler->para);
vin_log(VIN_LOG_SCALER, "scaler%d probe end\n", scaler->id);
return 0;
freedev:
hal_free(scaler);
ekzalloc:
vin_err("scaler%d probe err!\n", scaler->id);
return ret;
}
int scaler_remove(unsigned int id)
{
struct scaler_dev *scaler = global_scaler[id];
if (!scaler_probe_flag[id])
return 0;
else
scaler_probe_flag[id] = false;
if (scaler->noneed_register == 1) {
hal_free(scaler);
return 0;
}
#ifdef VIPP_REG_MODE
scaler_resource_free(id);
#endif
#ifdef VIPP_ISR_EN
if (scaler->id == vipp_virtual_find_logic[scaler->id]) {
if (!scaler->is_irq_empty)
hal_free_irq(scaler->irq);
}
#endif
hal_free(scaler);
return 0;
}