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

941 lines
29 KiB
C
Executable File

/*
* vin.c
*
* Copyright (c) 2018 by Allwinnertech Co., Ltd. http://www.allwinnertech.com
*
* Authors: Zequn Zheng <zequnzhengi@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_clk.h>
#include <hal_timer.h>
#include <sunxi_hal_gpadc.h>
#include <openamp/sunxi_helper/openamp.h>
#include <hal_cfg.h>
//#include <script.h>
#include "vin.h"
struct rt_memheap isp_mempool;
unsigned int vin_log_mask = 0;// = 0xffff - VIN_LOG_ISP - VIN_LOG_STAT - VIN_LOG_STAT1;
struct isp_get_cfg_t isp_get_cfg[ISP_GET_CFG_NUM] = {
[0] = {
.sensor_get_fps = 15,
},
[1] = {
.sensor_get_fps = 15,
},
};
extern struct csi_dev *global_csi[VIN_MAX_CSI];
extern struct vin_core *global_vinc[VIN_MAX_VIDEO];
void vin_set_from_partition(int isp_id, unsigned char *ir_en)
{
SENSOR_ISP_CONFIG_S *sensor_isp_cfg = NULL;
enum ir_mode ir_mode = DAY_MODE;
unsigned int check_sign = 0;
unsigned int gpadc_ch = 0;
unsigned int gpadc_value = 0;
int id = clamp(isp_id, 0, ISP_GET_CFG_NUM - 1);
#if defined CONFIG_ISP_HARD_LIGHTADC || defined CONFIG_ISP_ONLY_HARD_LIGHTADC
hal_gpadc_init();
hal_gpadc_channel_init(gpadc_ch);
#endif
#ifdef CONFIG_SUPPORT_THREE_CAMERA
/*read from ddr*/
if (id == 0) { /* isp0 */
sensor_isp_cfg = (SENSOR_ISP_CONFIG_S *)VIN_SENSOR0_RESERVE_ADDR;
check_sign = 0xAA66AA66;
} else if (id == 1) { /* isp1/isp2 */
sensor_isp_cfg = (SENSOR_ISP_CONFIG_S *)VIN_SENSOR1_RESERVE_ADDR;
check_sign = 0xBB66BB66;
} else {
sensor_isp_cfg = (SENSOR_ISP_CONFIG_S *)VIN_SENSOR2_RESERVE_ADDR;
check_sign = 0xCC66CC66;
}
#else
/*read from ddr*/
if (id == 0) { /* isp0 */
sensor_isp_cfg = (SENSOR_ISP_CONFIG_S *)VIN_SENSOR0_RESERVE_ADDR;
check_sign = 0xAA66AA66;
} else { /* isp1/isp2 */
sensor_isp_cfg = (SENSOR_ISP_CONFIG_S *)VIN_SENSOR1_RESERVE_ADDR;
check_sign = 0xBB66BB66;
}
#endif
if (sensor_isp_cfg->sign != check_sign) {
vin_warn("sensor%d:sign is 0x%x\n", id, sensor_isp_cfg->sign);
return;
}
isp_get_cfg[id].sensor_wdr_on = sensor_isp_cfg->wdr_mode;
if (sensor_isp_cfg->fps)
isp_get_cfg[id].sensor_get_fps = sensor_isp_cfg->fps;
isp_get_cfg[id].sensor_deinit = sensor_isp_cfg->sensor_deinit;
isp_get_cfg[id].get_yuv_en = sensor_isp_cfg->get_yuv_en;
vin_print("isp%d:get wdr mode is %d, fps is %d\n", id, isp_get_cfg[id].sensor_wdr_on, isp_get_cfg[id].sensor_get_fps);
#if defined CONFIG_ISP_HARD_LIGHTADC || defined CONFIG_ISP_ONLY_HARD_LIGHTADC
gpadc_value = gpadc_read_channel_data(gpadc_ch);
/* boot0 set ir, melis set isp ir */
if (sensor_isp_cfg->ircut_state) {
if (sensor_isp_cfg->ircut_state == 1) {
ir_mode = DAY_MODE;
*ir_en = 1 + 2;
} else if (sensor_isp_cfg->ircut_state == 2) {
ir_mode = NIGHT_MODE;
*ir_en = 2 + 2;
}
vin_print("boot0 set ir, ircut_state is %s, light_def is %d, gpadc_value is %d\n",
(sensor_isp_cfg->ircut_state == 1 ? "day_state" : "night_state"),
sensor_isp_cfg->light_def, gpadc_value);
} else {
/* force day or night*/
if (sensor_isp_cfg->ir_mode == DAY_MODE || sensor_isp_cfg->ir_mode == NIGHT_MODE) {
ir_mode = sensor_isp_cfg->ir_mode;
} else { /* auto mode */
if (sensor_isp_cfg->light_def == 0)
sensor_isp_cfg->light_def = 1000;
if (sensor_isp_cfg->adc_mode == 0) {
if (sensor_isp_cfg->light_def > gpadc_value)
ir_mode = NIGHT_MODE;
else
ir_mode = DAY_MODE;
} else {
if (sensor_isp_cfg->light_def > gpadc_value)
ir_mode = DAY_MODE;
else
ir_mode = NIGHT_MODE;
}
}
if (ir_mode == DAY_MODE) {
sensor_isp_cfg->ircut_state = 1;
*ir_en = 1;
} else {
sensor_isp_cfg->ircut_state = 2;
*ir_en = 2;
}
vin_print("boot0 not set ir, ir_mode is %s, ircut_state is %s, light_def is %d, gpadc_value is %d\n",
(sensor_isp_cfg->ir_mode == DAY_MODE ? "day_mode" : (sensor_isp_cfg->ir_mode == NIGHT_MODE ? "night_mode" : "auto_mode")),
(sensor_isp_cfg->ircut_state == 1 ? "day_state" : "night_state"),
sensor_isp_cfg->light_def, gpadc_value);
}
//hal_gpadc_channel_exit(gpadc_ch);
//hal_gpadc_deinit();
#elif defined CONFIG_ISP_FAST_CONVERGENCE
if (sensor_isp_cfg->ir_mode == NIGHT_MODE) {
*ir_en = 1;
} else {
*ir_en = 0;
}
#endif
}
void vin_set_to_partition(int isp_id)
{
SENSOR_ISP_CONFIG_S *sensor_isp_cfg = NULL;
unsigned int check_sign = 0;
int id = clamp(isp_id, 0, ISP_GET_CFG_NUM - 1);
#ifdef CONFIG_SUPPORT_THREE_CAMERA
/*read from ddr*/
if (id == 0) {
sensor_isp_cfg = (SENSOR_ISP_CONFIG_S *)VIN_SENSOR0_RESERVE_ADDR;
check_sign = 0xAA66AA66;
} else if (id == 1) {
sensor_isp_cfg = (SENSOR_ISP_CONFIG_S *)VIN_SENSOR1_RESERVE_ADDR;
check_sign = 0xBB66BB66;
} else {
sensor_isp_cfg = (SENSOR_ISP_CONFIG_S *)VIN_SENSOR2_RESERVE_ADDR;
check_sign = 0xCC66CC66;
}
#else
/*read from ddr*/
if (id == 0) {
sensor_isp_cfg = (SENSOR_ISP_CONFIG_S *)VIN_SENSOR0_RESERVE_ADDR;
check_sign = 0xAA66AA66;
} else {
sensor_isp_cfg = (SENSOR_ISP_CONFIG_S *)VIN_SENSOR1_RESERVE_ADDR;
check_sign = 0xBB66BB66;
}
#endif
if (sensor_isp_cfg->sign != check_sign) {
vin_warn("sensor%d:sign is 0x%x\n", id, sensor_isp_cfg->sign);
return;
}
sensor_isp_cfg->wdr_mode = isp_get_cfg[id].sensor_wdr_on;
sensor_isp_cfg->fps = isp_get_cfg[id].sensor_get_fps;
vin_print("sensor%d:set wdr mode is %d, fps is %d\n", id, isp_get_cfg[id].sensor_wdr_on, isp_get_cfg[id].sensor_get_fps);
}
void vin_set_lightadc_from_partition(int isp_id, int sensor_id, unsigned char ir_en)
{
#if defined CONFIG_ISP_ONLY_HARD_LIGHTADC
SENSOR_ISP_CONFIG_S *sensor_isp_cfg = NULL;
unsigned int check_sign = 0;
unsigned int gpadc_ch = 0;
unsigned int gpadc_value = 0;
unsigned short ae_idx = 0;
unsigned char hdr_ratio;
struct sensor_exp_gain exp_gain;
int i;
int id = clamp(isp_id, 0, ISP_GET_CFG_NUM - 1);
#ifdef CONFIG_SUPPORT_THREE_CAMERA
/*read from ddr*/
if (id == 0) { /* isp0 */
sensor_isp_cfg = (SENSOR_ISP_CONFIG_S *)VIN_SENSOR0_RESERVE_ADDR;
check_sign = 0xAA66AA66;
} else if (id == 1) { /* isp1/isp2 */
sensor_isp_cfg = (SENSOR_ISP_CONFIG_S *)VIN_SENSOR1_RESERVE_ADDR;
check_sign = 0xBB66BB66;
} else {
sensor_isp_cfg = (SENSOR_ISP_CONFIG_S *)VIN_SENSOR2_RESERVE_ADDR;
check_sign = 0xCC66CC66;
}
#else
/*read from ddr*/
if (id == 0) { /* isp0 */
sensor_isp_cfg = (SENSOR_ISP_CONFIG_S *)VIN_SENSOR0_RESERVE_ADDR;
check_sign = 0xAA66AA66;
} else { /* isp1/isp2 */
sensor_isp_cfg = (SENSOR_ISP_CONFIG_S *)VIN_SENSOR1_RESERVE_ADDR;
check_sign = 0xBB66BB66;
}
#endif
if (sensor_isp_cfg->sign != check_sign) {
vin_warn("sensor%d:sign is 0x%x\n", id, sensor_isp_cfg->sign);
return;
}
sunxi_isp_set_lightadc_debug_en(isp_id, sensor_isp_cfg->lightadc_debug_en);
memset(&exp_gain, 0, sizeof(exp_gain));
hdr_ratio = sensor_isp_cfg->hdr_light_sensor_ratio == 0 ? 32 : sensor_isp_cfg->hdr_light_sensor_ratio;
if (sensor_isp_cfg->light_sensor_en) {
gpadc_value = gpadc_read_channel_data(gpadc_ch);
if (ir_en == 1 || ir_en == 3) { //day mode
if (isp_get_cfg[id].sensor_wdr_on == ISP_DOL_WDR_MODE) {
if (gpadc_value < sensor_isp_cfg->hdr[0].u16LightValue)
i = 0;
else {
for (i = 0; i < DAY_LIGNT_SENSOR_SIZE - 1; i++) {
if (sensor_isp_cfg->hdr[i].u16LightValue == 0)
break;
if (sensor_isp_cfg->hdr[i].u16LightValue != 0 && sensor_isp_cfg->hdr[i + 1].u16LightValue == 0)
break;
if (gpadc_value >= sensor_isp_cfg->hdr[i].u16LightValue && gpadc_value < sensor_isp_cfg->hdr[i+1].u16LightValue)
break;
}
}
exp_gain.exp_val = sensor_isp_cfg->hdr[i].u32SnsExposure;
exp_gain.exp_short_val = exp_gain.exp_val / hdr_ratio;
exp_gain.gain_val = sensor_isp_cfg->hdr[i].u32SnsAgain >> 4;
ae_idx = sensor_isp_cfg->hdr[i].ae_table_idx;
} else {
if (gpadc_value < sensor_isp_cfg->linear[0].u16LightValue)
i = 0;
else {
for (i = 0; i < DAY_LIGNT_SENSOR_SIZE - 1; i++) {
/*vin_print("table:gpadc_value is %d, exp&again is %d/%d, ae_table idx is %d\n",
sensor_isp_cfg->linear[i].u16LightValue, sensor_isp_cfg->linear[i].u32SnsExposure,
sensor_isp_cfg->linear[i+1].u16LightValue, sensor_isp_cfg->linear[i].ae_table_idx);*/
if (sensor_isp_cfg->linear[i].u16LightValue == 0)
break;
if (sensor_isp_cfg->linear[i].u16LightValue != 0 && sensor_isp_cfg->linear[i + 1].u16LightValue == 0)
break;
if (gpadc_value >= sensor_isp_cfg->linear[i].u16LightValue && gpadc_value < sensor_isp_cfg->linear[i+1].u16LightValue)
break;
}
}
exp_gain.exp_val = sensor_isp_cfg->linear[i].u32SnsExposure;
exp_gain.gain_val = sensor_isp_cfg->linear[i].u32SnsAgain >> 4;
ae_idx = sensor_isp_cfg->linear[i].ae_table_idx;
}
} else { //night mode
if (isp_get_cfg[id].sensor_wdr_on == ISP_DOL_WDR_MODE) {
if (gpadc_value < sensor_isp_cfg->hdr_night[0].u16LightValue)
i = 0;
else {
for (i = 0; i < NIGHT_LIGNT_SENSOR_SIZE - 1; i++) {
if (sensor_isp_cfg->hdr_night[i].u16LightValue == 0)
break;
if (sensor_isp_cfg->hdr_night[i].u16LightValue != 0 && sensor_isp_cfg->hdr_night[i + 1].u16LightValue == 0)
break;
if (gpadc_value >= sensor_isp_cfg->hdr_night[i].u16LightValue && gpadc_value < sensor_isp_cfg->hdr_night[i+1].u16LightValue)
break;
}
}
exp_gain.exp_val = sensor_isp_cfg->hdr_night[i].u32SnsExposure;
exp_gain.exp_short_val = exp_gain.exp_val / hdr_ratio;
exp_gain.gain_val = sensor_isp_cfg->hdr_night[i].u32SnsAgain >> 4;
ae_idx = sensor_isp_cfg->hdr_night[i].ae_table_idx;
} else {
if (gpadc_value < sensor_isp_cfg->linear_night[0].u16LightValue)
i = 0;
else {
for (i = 0; i < NIGHT_LIGNT_SENSOR_SIZE - 1; i++) {
if (sensor_isp_cfg->linear_night[i].u16LightValue == 0)
break;
if (sensor_isp_cfg->linear_night[i].u16LightValue != 0 && sensor_isp_cfg->linear_night[i + 1].u16LightValue == 0)
break;
if (gpadc_value >= sensor_isp_cfg->linear_night[i].u16LightValue && gpadc_value < sensor_isp_cfg->linear_night[i+1].u16LightValue)
break;
}
}
exp_gain.exp_val = sensor_isp_cfg->linear_night[i].u32SnsExposure;
exp_gain.gain_val = sensor_isp_cfg->linear_night[i].u32SnsAgain >> 4;
ae_idx = sensor_isp_cfg->linear_night[i].ae_table_idx;
}
}
vin_print("gpadc_value is %d, exp&again is %d/%d, ae_table idx is %d\n", gpadc_value, exp_gain.exp_val, exp_gain.gain_val, ae_idx);
if (exp_gain.exp_val == 0 || exp_gain.gain_val == 0)
return;
sunxi_isp_set_ae_idx(isp_id, ae_idx);
if (global_sensors[sensor_id].sensor_core->s_exp_gain)
global_sensors[sensor_id].sensor_core->s_exp_gain(sensor_id, &exp_gain);
}
#endif
}
static int vin_md_clk_en(unsigned int en)
{
struct vin_clk_info top_clk_src;
hal_writel(0x00000001, 0x02001c2c);
hal_writel(0x00010001, 0x02001c2c);
if (vind_default_clk[VIN_TOP_CLK].frequency > 300000000) {
top_clk_src.clock = vind_default_clk[VIN_TOP_CLK_SRC].clock;
top_clk_src.frequency = VIN_PLL_CSI_RATE;
} else {
top_clk_src.clock = vind_default_clk[VIN_TOP_CLK_SRC1].clock;
top_clk_src.frequency = vind_default_clk[VIN_TOP_CLK_SRC1].frequency;
}
if (en) {
if (hal_clk_set_parent(vind_default_clk[VIN_TOP_CLK].clock, top_clk_src.clock)) {
vin_err("set top_clk source failed!\n");
return -1;
}
if (hal_clk_set_rate(top_clk_src.clock, top_clk_src.frequency)) {
vin_warn("set top_clk src clock error\n");
//return -1;
}
if (hal_clk_set_rate(vind_default_clk[VIN_TOP_CLK].clock, vind_default_clk[VIN_TOP_CLK].frequency)) {
vin_err("set top_clk clock error\n");
return -1;
}
}
if (en) {
if (hal_clock_enable(top_clk_src.clock)) {
vin_err("top_clk_src clock enable error\n");
return -1;
}
if (hal_clock_enable(vind_default_clk[VIN_TOP_CLK].clock)) {
vin_err("top_clk clock enable error\n");
return -1;
}
if (hal_clock_enable(vind_default_isp_clk[VIN_ISP_CLK].clock)) {
vin_err("isp clock enable error\n");
return -1;
}
/*if (vind_default_clk[VIN_TOP_CLK].frequency > 300000000) {
hal_writel(0xc9006201, 0x02001048); //set pll_csi 2376M
hal_writel(0xd1303333, 0x02001148);
hal_writel(0x83000006, 0x02001c04); //set top_csi 340M
}*/
} else {
if (hal_clock_disable(vind_default_clk[VIN_TOP_CLK].clock)) {
vin_err("top_clk clock disable error\n");
return -1;
}
if (hal_clock_disable(vind_default_isp_clk[VIN_ISP_CLK].clock)) {
vin_err("isp clock disable error\n");
return -1;
}
}
hal_writel(0x00000001, 0x02001c2c);
hal_writel(0x00010001, 0x02001c2c);
vin_print("set clk end\n");
return 0;
}
static void vin_ccu_clk_gating_en(unsigned int en)
{
/*if (en) {
csic_ccu_clk_gating_enable();
csic_ccu_mcsi_clk_mode(1);
csic_ccu_mcsi_post_clk_enable(0);
csic_ccu_mcsi_post_clk_enable(1);
} else {
csic_ccu_mcsi_post_clk_disable(1);
csic_ccu_mcsi_post_clk_disable(0);
csic_ccu_mcsi_clk_mode(0);
csic_ccu_clk_gating_disable();
}*/
csic_ccu_clk_gating_disable();
}
static void vin_md_set_power(int on)
{
if (on) {
vin_md_clk_en(on);
vin_ccu_clk_gating_en(on);
hal_usleep(120);
csic_top_enable();
csic_mbus_req_mex_set(0xf);
} else {
csic_top_disable();
vin_ccu_clk_gating_en(on);
vin_md_clk_en(on);
}
}
static void vin_subdev_ccu_en(unsigned int id, unsigned int en)
{
}
static int vin_pipeline_set_mbus_config(unsigned int id)
{
struct vin_core *vinc = global_vinc[id];
struct v4l2_mbus_config mcfg;
struct mbus_framefmt_res res;
int sensor_id = vinc->rear_sensor;
memset(&res, 0, sizeof(struct mbus_framefmt_res));
if (global_sensors[sensor_id].sensor_core->g_mbus_config)
global_sensors[sensor_id].sensor_core->g_mbus_config(sensor_id, &mcfg, &res);
/* s_mbus_config on all mipi and csi */
if (vinc->mipi_sel != 0xff)
sunxi_mipi_s_mbus_config(vinc->mipi_sel, &mcfg, &res);
sunxi_csi_s_mbus_config(vinc->csi_sel, &mcfg);
vinc->total_rx_ch = global_csi[vinc->csi_sel]->bus_info.ch_total_num;
if (vinc->tdm_rx_sel != 0xff)
sunxi_tdm_s_mbus_config(vinc->tdm_rx_sel, &res);
sunxi_isp_s_mbus_config(vinc->isp_sel, &res);
return 0;
}
static int vin_s_stream(unsigned int id, int enable)
{
struct vin_core *vinc = global_vinc[id];
int sensor_id = vinc->rear_sensor;
struct vin_core *logic_vinc = global_vinc[dma_virtual_find_logic[vinc->id]];
int ret;
vin_log(VIN_LOG_MD, "vinc%d:tdm_rx_sel = %d, mipi_sel = %d, isp_sel = %d, vincid = %d, csi_sel = %d\n",
id, vinc->tdm_rx_sel, vinc->mipi_sel, vinc->isp_sel, vinc->id, vinc->csi_sel);
if (enable) {
if (vinc->tdm_rx_sel != 0xff) {
sunxi_tdm_subdev_s_stream(vinc->tdm_rx_sel, vinc->id, enable);
}
hal_usleep(120);
if (vinc->mipi_sel != 0xff)
sunxi_mipi_subdev_s_stream(vinc->mipi_sel, vinc->id, enable);
hal_usleep(120);
sunxi_isp_subdev_s_stream(vinc->isp_sel, vinc->id, enable);
hal_usleep(120);
sunxi_scaler_subdev_s_stream(vinc->id, enable);
hal_usleep(120);
vin_subdev_s_stream(vinc->id, enable);
hal_usleep(120);
sunxi_csi_subdev_s_stream(vinc->csi_sel, vinc->id, enable);
hal_usleep(120);
if (global_sensors[sensor_id].sensor_core->s_stream) {
ret = global_sensors[sensor_id].sensor_core->s_stream(sensor_id, vinc->isp_sel, enable);
if (ret)
return ret;
}
} else {
vin_subdev_s_stream(vinc->id, enable);
hal_usleep(120);
if (logic_vinc->work_mode == BK_ONLINE) {
sunxi_scaler_subdev_s_stream(vinc->id, enable);
hal_usleep(120);
sunxi_isp_subdev_s_stream(vinc->isp_sel, vinc->id, enable);
hal_usleep(120);
if (vinc->tdm_rx_sel != 0xff)
sunxi_tdm_subdev_s_stream(vinc->tdm_rx_sel, vinc->id, enable);
} else {
if (vinc->tdm_rx_sel != 0xff)
sunxi_tdm_subdev_s_stream(vinc->tdm_rx_sel, vinc->id, enable);
hal_usleep(120);
sunxi_isp_subdev_s_stream(vinc->isp_sel, vinc->id, enable);
hal_usleep(120);
sunxi_scaler_subdev_s_stream(vinc->id, enable);
}
hal_usleep(120);
sunxi_csi_subdev_s_stream(vinc->csi_sel, vinc->id, enable);
#ifndef ISP_SERVER_FASTINIT
hal_usleep(120);
if (vinc->mipi_sel != 0xff)
sunxi_mipi_subdev_s_stream(vinc->mipi_sel, vinc->id, enable);
hal_usleep(120);
if (global_sensors[sensor_id].sensor_core->s_stream) {
ret = global_sensors[sensor_id].sensor_core->s_stream(sensor_id, vinc->isp_sel, enable);
if (ret)
return ret;
}
#endif
}
return 0;
}
static void vin_probe(unsigned int id)
{
struct vin_core *vinc = &global_video[id];
if (vinc->mipi_sel != 0xff)
mipi_probe(vinc->mipi_sel);
csi_probe(vinc->csi_sel);
if (vinc->tdm_rx_sel != 0xff)
tdm_probe(vinc->tdm_rx_sel);
isp_probe(vinc->isp_sel); /* isp0 must first probe */
scaler_probe(vinc->id);
vin_core_probe(vinc->id);
}
static void vin_free(unsigned int id)
{
struct vin_core *vinc = &global_video[id];
if (vinc->mipi_sel != 0xff)
mipi_remove(vinc->mipi_sel);
csi_remove(vinc->csi_sel);
if (vinc->tdm_rx_sel != 0xff)
tdm_remove(vinc->tdm_rx_sel);
isp_remove(vinc->isp_sel);
scaler_remove(vinc->id);
vin_core_remove(vinc->id);
}
static int vin_g_config(void)
{
int i, ret = -1;
user_gpio_set_t gpio_cfg;
char main_name[16];
char sub_name[16];
int ivalue = 0;
for (i = 0; i< VIN_MAX_VIDEO; i++)
{
ivalue = 0;
sprintf(main_name, "sensor%d", i);
sprintf(sub_name, "used%d", i);
ret = Hal_Cfg_GetSubKeyValue(main_name, sub_name, (void*)&ivalue, 1);
if(0 != ret) {
vin_err("%s is %d\n", sub_name, ivalue);
break;
}
//vin_err("%s is %d\n", sub_name, ivalue);
global_video[i].used = ivalue;
if(1 != ivalue)
continue;
#if (CONFIG_ISP_NUMBER == 2)
//sensor_name
char sensor_name[100];
memset(sensor_name, 0, sizeof(sensor_name));
memset(sub_name, 0, sizeof(sub_name));
sprintf(sub_name, "name%d", i);
ret = Hal_Cfg_GetSubKeyValue(main_name, sub_name, (void*)sensor_name, DATA_TYPE_STRING);
if(0 != ret) {
vin_err("%s %s: %s\n", main_name, sub_name, sensor_name);
//break;
}else{
memset(global_sensors[i].sensor_name, 0, sizeof(global_sensors[i].sensor_name));
sprintf(global_sensors[i].sensor_name, "%s", sensor_name);
}
//addr_width
int addr_width = 0;
memset(sub_name, 0, sizeof(sub_name));
sprintf(sub_name, "addr_width%d", i);
ret = Hal_Cfg_GetSubKeyValue(main_name, sub_name, (void*)&addr_width, DATA_TYPE_SINGLE_WORD);
if(0 != ret) {
vin_err("%s %s: 0x%x\n", main_name, sub_name, addr_width);
//break;
}else{
global_sensors[i].addr_width = addr_width;
}
//data_width
int data_width = 0;
memset(sub_name, 0, sizeof(sub_name));
sprintf(sub_name, "data_width%d", i);
ret = Hal_Cfg_GetSubKeyValue(main_name, sub_name, (void*)&data_width, DATA_TYPE_SINGLE_WORD);
if(0 != ret) {
vin_err("%s %s: 0x%x\n", main_name, sub_name, data_width);
//break;
}else{
global_sensors[i].data_width = data_width;
}
#endif
sprintf(sub_name, "reset%d", i);
ret = Hal_Cfg_GetSubKeyValue(main_name, sub_name, (void*)&gpio_cfg, 4);
if(0 != ret) {
vin_err("%s is port %d, num %d\n", main_name, gpio_cfg.port, gpio_cfg.port_num);
break;
}
global_sensors[i].reset_gpio = (gpio_cfg.port - 1) * 32 + gpio_cfg.port_num;
sprintf(sub_name, "pwdn%d", i);
ret = Hal_Cfg_GetSubKeyValue(main_name, sub_name, (void*)&gpio_cfg, 4);
if(0 != ret) {
vin_err("%s is port %d, num %d\n", main_name, gpio_cfg.port, gpio_cfg.port_num);
break;
}
global_sensors[i].pwdn_gpio = (gpio_cfg.port - 1) * 32 + gpio_cfg.port_num;
sprintf(sub_name, "mclk%d", i);
ret = Hal_Cfg_GetSubKeyValue(main_name, sub_name, (void*)&gpio_cfg, 4);
if(0 != ret) {
vin_err("%s is port %d, num %d\n", main_name, gpio_cfg.port, gpio_cfg.port_num);
break;
}
vind_default_mclk[i].pin = (gpio_cfg.port - 1) * 32 + gpio_cfg.port_num;
vind_default_mclk[i].pin_func[0] = gpio_cfg.mul_sel;
vind_default_mclk[i].pin_func[1] = 0xf;
#if (CONFIG_ISP_NUMBER == 2)
sprintf(sub_name, "twi_id%d", i);
ret = Hal_Cfg_GetSubKeyValue(main_name, sub_name, (void*)&ivalue, 1);
if(0 == ret) {
vin_err("%s is %d ok, default:%d\n", sub_name, ivalue, global_sensors[i].sensor_twi_id);
global_sensors[i].sensor_twi_id = ivalue;
}else{
vin_err("%s is %d faill, default:%d\n", sub_name, ivalue, global_sensors[i].sensor_twi_id);
}
sprintf(sub_name, "twi_addr%d", i);
ret = Hal_Cfg_GetSubKeyValue(main_name, sub_name, (void*)&ivalue, 1);
if(0 == ret) {
vin_err("%s is %d ok, default:0x%x\n", sub_name, ivalue, global_sensors[i].sensor_twi_addr);
global_sensors[i].sensor_twi_addr = ivalue;
}else{
vin_err("%s is %d faill, default:0x%x\n", sub_name, ivalue, global_sensors[i].sensor_twi_addr);
}
sprintf(sub_name, "mclk_id%d", i);
ret = Hal_Cfg_GetSubKeyValue(main_name, sub_name, (void*)&ivalue, 1);
if(0 == ret) {
vin_err("%s is %d ok, default:0x%x\n", sub_name, ivalue, global_sensors[i].mclk_id);
global_sensors[i].mclk_id = ivalue;
}else{
vin_err("%s is %d faill, default:0x%x\n", sub_name, ivalue, global_sensors[i].mclk_id);
}
#endif
}
return 0;
}
static int vin_g_status(void)
{
int i, ret = -1;
for (i = 0; i < VIN_MAX_VIDEO; i++) {
if (global_video[i].used == 1)
ret = 0;
}
return ret;
}
static void vin_detect_sensor_list(int sensor_id)
{
int i, save_detect_id;
struct isp_autoflash_config_s *isp_autoflash_cfg = NULL;
unsigned int sign;
int ret = -1;
switch (sensor_id) {
case 0:
isp_autoflash_cfg = (struct isp_autoflash_config_s *)ISP0_NORFLASH_SAVE;
sign = 0xAA22AA22;
break;
case 1:
isp_autoflash_cfg = (struct isp_autoflash_config_s *)ISP1_NORFLASH_SAVE;
sign = 0xBB22BB22;
break;
#ifdef CONFIG_SUPPORT_THREE_CAMERA
case 2:
isp_autoflash_cfg = (struct isp_autoflash_config_s *)ISP2_NORFLASH_SAVE;
sign = 0xCC22CC22;
break;
#endif
default:
isp_autoflash_cfg = (struct isp_autoflash_config_s *)ISP0_NORFLASH_SAVE;
sign = 0xAA22AA22;
break;
}
save_detect_id = min(isp_autoflash_cfg->sensor_detect_id, MAX_DETECT_SENSOR - 1);
vin_print("sensor%d save_detect_id is %d\n", sensor_id, save_detect_id);
memcpy(&global_sensors[sensor_id], &global_sensors_list[sensor_id][save_detect_id], sizeof(struct sensor_list));
global_sensors[sensor_id].sensor_core = find_sensor_func(global_sensors[sensor_id].sensor_name);
if (global_sensors[sensor_id].sensor_core->sensor_test_i2c) {
vin_print("sensor %s to save detect\n", global_sensors[sensor_id].sensor_name);
ret = global_sensors[sensor_id].sensor_core->sensor_test_i2c(sensor_id);
}
if (ret) {
for (i = 0; i < MAX_DETECT_SENSOR; i++) {
if (i == save_detect_id)
continue;
memcpy(&global_sensors[sensor_id], &global_sensors_list[sensor_id][i], sizeof(struct sensor_list));
global_sensors[sensor_id].sensor_core = find_sensor_func(global_sensors[sensor_id].sensor_name);
if (global_sensors[sensor_id].sensor_core->sensor_test_i2c) {
vin_print("sensor %s to detect\n", global_sensors[sensor_id].sensor_name);
ret = global_sensors[sensor_id].sensor_core->sensor_test_i2c(sensor_id);
if (!ret) {
vin_print("find sensor %s\n", global_sensors[sensor_id].sensor_name);
isp_autoflash_cfg->sensorlist_sign_id = sign;
strcpy(isp_autoflash_cfg->sensor_name, global_sensors[sensor_id].sensor_name);
isp_autoflash_cfg->sensor_twi_addr = global_sensors[sensor_id].sensor_twi_addr;
isp_autoflash_cfg->sensor_detect_id = i;
break;
}
}
}
if (ret)
isp_autoflash_cfg->sensorlist_sign_id = 0xFFFFFFFF;
}
}
static void __csic_dump_regs(unsigned long addr, unsigned long size)
{
unsigned int val;
int cnt = 0;
do {
if (cnt % 4 == 0)
printk("0x%08x:", addr + cnt * 4);
val = hal_readl(addr + cnt * 4);
printk(" 0x%08x ", val);
cnt++;
if (cnt % 4 == 0 && cnt != 0)
printk("\n");
} while (size > cnt * 4);
}
int csi_init(int argc, const char **argv)
{
struct vin_core *vinc = NULL;
unsigned long reg_base;
unsigned long ccu_base;
int ret = 0;
int i, j;
int sensor_id;
int select_video_num = VIN_MAX_VIDEO; //VIN_MAX_VIDEO
unsigned char ir_en = 0;
int sensor_enable = 1;
if (hal_readl(rtc_base + 0x100 + 0x4 * RTC_NUM) & 0x2) {
vin_print("rtc%d is 0x%x, csi_init is already init once, reinit isp server\n", RTC_NUM, hal_readl(rtc_base + 0x100 + 0x4 * RTC_NUM));
openamp_init();
for (i = 0; i < select_video_num; i++) {
if (global_video[i].used == 1) {
ret = isp_reinit(global_video[i].isp_sel);
}
}
return ret;
}
vin_log(VIN_LOG_MD, "CSI start!\n");
ret = vin_g_config();
if (ret != 0) {
vin_err("vin get config error\n");
return -1;
}
ret = vin_g_status();
if (ret != 0) {
vin_err("There is no open CSI\n");
return -1;
}
rt_memheap_init(&isp_mempool, "isp-mempool", (void *)MEMRESERVE, MEMRESERVE_SIZE);
reg_base = sunxi_vin_get_top_base();
csic_top_set_base_addr(reg_base);
vin_log(VIN_LOG_MD, "reg is 0x%lx\n", reg_base);
ccu_base = sunxi_vin_get_ccu_base();
csic_ccu_set_base_addr(ccu_base);
vin_log(VIN_LOG_MD, "reg is 0x%lx\n", ccu_base);
vin_md_set_power(PWR_ON);
sunxi_twi_init(0);
sunxi_twi_init(1);
#ifdef CONFIG_SUPPORT_THREE_CAMERA
sunxi_twi_init(2);
#endif
#if 0
i = 0;
if (global_sensors[sensor_id].sensor_core->sensor_test_i2c) {
ret = global_sensors[i].sensor_core->sensor_test_i2c(i);
if (ret)
return -1;
}
#endif
//vin_probe(0);
for (i = 0; i < select_video_num; i++) {
if (global_video[i].used == 1) {
sensor_id = global_video[i].rear_sensor;
global_sensors[sensor_id].sensor_core = find_sensor_func(global_sensors[sensor_id].sensor_name);
if (global_video[i].use_sensor_list)
vin_detect_sensor_list(sensor_id);
vin_set_from_partition(global_video[i].isp_sel, &ir_en);
vin_probe(i);
vinc = global_vinc[i];
vinc->get_yuv_en = isp_get_cfg[clamp(vinc->isp_sel, 0, ISP_GET_CFG_NUM - 1)].get_yuv_en;
vin_subdev_ccu_en(i, PWR_ON);
vin_pipeline_set_mbus_config(i);
if ((vinc->csi_ch != 0xff) && (vinc->csi_ch & 0x10))
{
csic_isp_input_select(vinc->isp_sel/ISP_VIRT_NUM, vinc->isp_sel%ISP_VIRT_NUM + 0, vinc->csi_sel, vinc->csi_ch & 0xf);
}
else
{
for (j = 0; j < vinc->total_rx_ch; j++) {
csic_isp_input_select(vinc->isp_sel/ISP_VIRT_NUM, vinc->isp_sel%ISP_VIRT_NUM + j, vinc->csi_sel, j);
}
}
csic_vipp_input_select(vinc->vipp_sel/VIPP_VIRT_NUM, vinc->isp_sel/ISP_VIRT_NUM, vinc->isp_tx_ch);
#ifdef CONFIG_ISP_FAST_CONVERGENCE
if (global_sensors[sensor_id].sensor_core->s_ir_status) {
if (ir_en)
global_sensors[sensor_id].sensor_core->s_ir_status(sensor_id, IR_NIGHT);
else
global_sensors[sensor_id].sensor_core->s_ir_status(sensor_id, IR_DAY);
}
#elif defined CONFIG_ISP_HARD_LIGHTADC || defined CONFIG_ISP_ONLY_HARD_LIGHTADC
if (global_sensors[sensor_id].sensor_core->s_ir_status) {
if (ir_en == 1)
global_sensors[sensor_id].sensor_core->s_ir_status(sensor_id, IR_DAY);
else if (ir_en == 2)
global_sensors[sensor_id].sensor_core->s_ir_status(sensor_id, IR_NIGHT);
}
#endif
if (global_sensors[sensor_id].sensor_core->sensor_power)
global_sensors[sensor_id].sensor_core->sensor_power(sensor_id, PWR_ON);
if (global_sensors[sensor_id].sensor_core->sensor_g_format)
global_sensors[sensor_id].sensor_core->sensor_g_format(sensor_id, vinc->isp_sel);
ret = vin_s_stream(i, PWR_ON);
if (ret) {
sensor_enable = 0;
vin_err("find not sensor\n");
}
vin_set_lightadc_from_partition(vinc->isp_sel, sensor_id, ir_en);
}
}
//__csic_dump_regs(0x05830000, 0x300);
for (i = 0; i < select_video_num; i++) {
if (global_video[i].used == 1) {
vinc = global_vinc[i];
if (vinc->get_yuv_en) {
while (vinc->frame_cnt != 2)
hal_usleep(1000);
}
if (global_sensors[i].use_isp && sensor_enable) {
while (sunxi_isp_ae_done(vinc->isp_sel, 8) != 0)
hal_usleep(1000);
}
vin_print("close video%d\n", vinc->id);
vin_s_stream(i, PWR_OFF);
}
}
for (i = 0; i < select_video_num; i++) {
if (global_video[i].used == 1) {
vinc = global_vinc[i];
vin_free(i);
}
}
//vin_free(0);
openamp_init(); //wait rpmsg init
for (i = 0; i < select_video_num; i++) {
if (global_video[i].used == 1) {
vinc = &global_video[i]; //global_vinc is free
sensor_id = vinc->rear_sensor;
#if defined CONFIG_ISP_FAST_CONVERGENCE || defined CONFIG_ISP_HARD_LIGHTADC
if (global_sensors[sensor_id].sensor_core->sensor_g_switch_format)
global_sensors[sensor_id].sensor_core->sensor_g_switch_format(sensor_id, vinc->isp_sel);
sunxi_isp_update_server(vinc->isp_sel);
if (global_sensors[sensor_id].sensor_core->s_switch)
global_sensors[sensor_id].sensor_core->s_switch(sensor_id);
#endif
sunxi_isp_reset_server(vinc->isp_sel);
vin_set_to_partition(vinc->isp_sel);
if (isp_get_cfg[clamp(vinc->isp_sel, 0, ISP_GET_CFG_NUM - 1)].sensor_deinit) {
if (vinc->mipi_sel != 0xff)
sunxi_mipi_subdev_s_stream(vinc->mipi_sel, vinc->id, 0);
hal_usleep(120);
if (global_sensors[sensor_id].sensor_core->s_stream)
global_sensors[sensor_id].sensor_core->s_stream(sensor_id, vinc->isp_sel, 0);
if (global_sensors[sensor_id].sensor_core->sensor_power)
global_sensors[sensor_id].sensor_core->sensor_power(sensor_id, PWR_OFF);
vin_print("sensor%d is close\n", sensor_id);
}
}
}
sunxi_twi_exit(0);
sunxi_twi_exit(1);
#ifdef CONFIG_SUPPORT_THREE_CAMERA
sunxi_twi_exit(2);
#endif
rt_memheap_detach(&isp_mempool);
hal_writel(hal_readl(rtc_base + 0x100 + 0x4 * RTC_NUM) | 0x2, rtc_base + 0x100 + 0x4 * RTC_NUM);
vin_print("set rtc%d is 0x%x\n", RTC_NUM, hal_readl(rtc_base + 0x100 + 0x4 * RTC_NUM));
vin_log(VIN_LOG_MD, "GoodBye CSI!\n");
return ret;
}
FINSH_FUNCTION_EXPORT_ALIAS(csi_init, csi_init, rtthread vin run code);