/* Copyright (c), 2001-2022, Shenshu Tech. Co., Ltd. */ #include "ot_mipi_rx.h" #include "ot_osal.h" #include "securec.h" #include "type.h" #include "sys_config.h" #include "mipi_rx_hal.h" #define MIPI_RX_DEV_NAME "ot_mipi" #define MIPI_RX_PROC_NAME "mipi_rx" #define OT_MEDIA_DYNAMIC_MINOR 255 #define COMBO_DEV_MAX_NUM 8 #define COMBO_MAX_LANE_NUM 32 #define COMBO_MIN_WIDTH 32 #define COMBO_MIN_HEIGHT 32 /* global variables definition */ typedef struct { lane_divide_mode_t lane_divide_mode; unsigned char hs_mode_cfged; combo_dev_attr_t combo_dev_attr[COMBO_DEV_MAX_NUM]; unsigned char dev_valid[COMBO_DEV_MAX_NUM]; unsigned char dev_cfged[COMBO_DEV_MAX_NUM]; unsigned int lane_bitmap[COMBO_DEV_MAX_NUM]; combo_dev_pn_swap_t dev_pn_swap[COMBO_DEV_MAX_NUM]; } mipi_dev_ctx_t; static osal_dev_t *g_mipirx_dev = NULL; static osal_mutex_t g_mipirx_mutex; static mipi_dev_ctx_t g_mipirx_dev_ctx; static osal_spinlock_t g_mipirx_ctx_lock; /**************************************************************************** * function definition * ****************************************************************************/ void mipi_rx_set_init_regs(void *regs) { mipi_rx_set_regs((mipi_rx_regs_type_t *)regs); } void mipi_rx_set_init_irq(unsigned int mipi_rx_irq) { mipi_rx_set_irq(mipi_rx_irq); } static unsigned char mipi_is_hs_mode_cfged(void) { unsigned char hs_mode_cfged; osal_spin_lock(&g_mipirx_ctx_lock); hs_mode_cfged = g_mipirx_dev_ctx.hs_mode_cfged; osal_spin_unlock(&g_mipirx_ctx_lock); return hs_mode_cfged; } static unsigned char mipi_is_dev_valid(combo_dev_t devno) { unsigned char dev_valid; osal_spin_lock(&g_mipirx_ctx_lock); dev_valid = g_mipirx_dev_ctx.dev_valid[devno]; osal_spin_unlock(&g_mipirx_ctx_lock); return dev_valid; } static unsigned char mipi_is_dev_cfged(combo_dev_t devno) { unsigned char dev_cfged; osal_spin_lock(&g_mipirx_ctx_lock); dev_cfged = g_mipirx_dev_ctx.dev_cfged[devno]; osal_spin_unlock(&g_mipirx_ctx_lock); return dev_cfged; } static int check_lane_id(combo_dev_t devno, input_mode_t input_mode, const short lane_id[]) { int lane_num = 0; int all_lane_id_invalid_flag; int i, j; lane_divide_mode_t cur_lane_divide_mode; if (input_mode == INPUT_MODE_MIPI) { lane_num = MIPI_LANE_NUM_PRE_DEV; } osal_spin_lock(&g_mipirx_ctx_lock); cur_lane_divide_mode = g_mipirx_dev_ctx.lane_divide_mode; osal_spin_unlock(&g_mipirx_ctx_lock); all_lane_id_invalid_flag = 1; for (i = 0; i < lane_num; i++) { int temp_id = lane_id[i]; int lane_valid; if (temp_id < -1 || temp_id >= COMBO_MAX_LANE_NUM) { ot_err("lane_id[%d] is invalid value %d.\n", i, temp_id); return TD_FAILURE; } if (temp_id == -1) { continue; } all_lane_id_invalid_flag = 0; for (j = i + 1; j < lane_num; j++) { if (temp_id == lane_id[j]) { ot_err("lane_id[%d] can't be same value %d as lane_id[%d]\n", i, temp_id, j); return TD_FAILURE; } } lane_valid = mipi_rx_drv_is_lane_valid(devno, temp_id, cur_lane_divide_mode); if (!lane_valid) { ot_err("lane_id[%d] %d is invalid in hs_mode %d\n", i, temp_id, cur_lane_divide_mode); return TD_FAILURE; } } if (all_lane_id_invalid_flag) { ot_err("all lane_id is invalid!\n"); return TD_FAILURE; } if (check_lane_can_used(devno, lane_id, MIPI_LANE_NUM_PRE_DEV)) { ot_err("lane used invalid!\n"); return TD_FAILURE; } return TD_SUCCESS; } static int check_pn_swap(combo_dev_t devno, const unsigned char *pn_swap) { int i; const int lane_num = MIPI_LANE_NUM_PRE_DEV; for (i = 0; i < lane_num; i++) { if (pn_swap[i] != FALSE && pn_swap[i] != TRUE) { ot_err("dev %u pn_swap[%d] must be FASLE or TRUE", devno, i); return TD_FAILURE; } } return TD_SUCCESS; } static unsigned int mipi_get_lane_bitmap(input_mode_t input_mode, const short *lane_id, unsigned int *total_lane_num_out) { unsigned int lane_bitmap = 0; int lane_num = 0; int total_lane_num; int i; if (input_mode == INPUT_MODE_MIPI) { lane_num = MIPI_LANE_NUM_PRE_DEV; } total_lane_num = 0; for (i = 0; i < lane_num; i++) { short tmp_lane_id; tmp_lane_id = lane_id[i]; if (tmp_lane_id != -1) { lane_bitmap = lane_bitmap | (1 << (unsigned short)(tmp_lane_id)); total_lane_num++; } } *total_lane_num_out = total_lane_num; return lane_bitmap; } static int mipi_check_comb_dev_attr(const combo_dev_attr_t *attr) { if (attr->devno >= COMBO_DEV_MAX_NUM) { ot_err("invalid combo_dev number(%d).\n", attr->devno); return TD_FAILURE; } if (attr->input_mode < INPUT_MODE_MIPI || attr->input_mode >= INPUT_MODE_BUTT) { ot_err("invalid input_mode(%d).\n", attr->input_mode); return TD_FAILURE; } return TD_SUCCESS; } static int check_mipi_dev_attr(combo_dev_t devno, const mipi_dev_attr_t *attr) { int ret; if (devno >= MIPI_RX_MAX_PHY_NUM) { ot_err("devno:%u invalid [0, %u)\n", devno, MIPI_RX_MAX_PHY_NUM); return TD_FAILURE; } if ((attr->input_data_type < DATA_TYPE_YUV422_8BIT) || (attr->input_data_type >= DATA_TYPE_BUTT)) { ot_err("invalid input_data_type, must be in [%d, %d)\n", DATA_TYPE_YUV422_8BIT, DATA_TYPE_BUTT); return TD_FAILURE; } ret = check_lane_id(devno, INPUT_MODE_MIPI, attr->lane_id); if (ret < 0) { ot_err("check_lane_id failed!\n"); return TD_FAILURE; } return TD_SUCCESS; } static void mipi_set_dt_and_mode(combo_dev_t devno, const mipi_dev_attr_t *attr) { data_type_t input_data_type; input_data_type = attr->input_data_type; mipi_rx_drv_set_mipi_yuv_dt(devno, input_data_type); } static void mipi_set_pin_mux(void) { int chip; if (mipi_rx_get_chip_id() == CHIP_SS522V100) { chip = CHIP_SS522V100; } else if (mipi_rx_get_chip_id() == CHIP_SS524V100) { chip = CHIP_SS524V100; } else { chip = CHIP_SS524V100; ot_err("chip err!\n"); } mipi_pin_mux(chip); } static void mipi_init_int_ctrl_info(combo_dev_t devno) { int ret; phy_err_int_cnt_t *phy_err_int_cnt = mipi_hal_get_phy_err_int(devno); mipi_err_int_cnt_t *mipi_err_int_cnt = mipi_hal_get_mipi_err_int(devno); align_err_int_cnt_t *align_err_int_cnt = mipi_hal_get_align_err_int(devno); /* interrupt mask */ ret = memset_s(phy_err_int_cnt, sizeof(phy_err_int_cnt_t), 0, sizeof(phy_err_int_cnt_t)); if (ret != EOK) { ot_err("memset_s phy_err_int err!\n"); return; } ret = memset_s(mipi_err_int_cnt, sizeof(mipi_err_int_cnt_t), 0, sizeof(mipi_err_int_cnt_t)); if (ret != EOK) { ot_err("memset_s mipi_err_int err!\n"); return; } ret = memset_s(align_err_int_cnt, sizeof(align_err_int_cnt_t), 0, sizeof(align_err_int_cnt_t)); if (ret != EOK) { ot_err("memset_s align_err_int err!\n"); return; } mipi_rx_drv_set_chn_int_mask(devno); mipi_rx_drv_set_mipi_ctrl_int_mask(devno, MIPI_CTRL_INT_MASK); mipi_rx_drv_set_mipi_csi_int_mask(devno, MIPI_CSI_INT_MASK); mipi_rx_drv_set_align_int_mask(devno, ALIGN0_INT_MASK); mipi_rx_drv_set_chn_int_category_mask(devno, MIPI_CHN_INT_MASK); } static int mipi_set_mipi_dev_attr(const combo_dev_attr_t *combo_dev_attr) { combo_dev_t devno; const mipi_dev_attr_t *mipi_attr = NULL; unsigned int lane_bitmap; unsigned int lane_num; int ret; devno = combo_dev_attr->devno; mipi_attr = &combo_dev_attr->mipi_attr; if (mipi_is_hs_mode_cfged() != TRUE) { ot_err("mipi must set hs mode before set mipi attr!\n"); return TD_FAILURE; } if (!mipi_is_dev_valid(devno)) { ot_err("invalid combo dev num after set hs mode!\n"); return TD_FAILURE; } ret = check_mipi_dev_attr(devno, mipi_attr); if (ret < 0) { ot_err("check_mipi_dev_attr failed!\n"); return TD_FAILURE; } ret = mipi_check_lane_mode(devno, combo_dev_attr->mipi_attr.lane_id, sizeof(combo_dev_attr->mipi_attr.lane_id) / sizeof(short)); if (ret < 0) { ot_err("check_mipi_dev_attr failed!\n"); return TD_FAILURE; } /* image crop */ mipi_rx_drv_set_mipi_crop_en(devno, FALSE); /* data type & mode */ mipi_set_dt_and_mode(devno, mipi_attr); /* set sync clear */ mipi_rx_drv_set_clear_en(devno); /* scan mode */ mipi_rx_drv_set_scan_mode(devno, MIPI_SCAN_INTERLACED); lane_bitmap = mipi_get_lane_bitmap(INPUT_MODE_MIPI, mipi_attr->lane_id, &lane_num); /* phy lane config */ mipi_rx_drv_set_link_lane_id(devno, INPUT_MODE_MIPI, mipi_attr->lane_id); g_mipirx_dev_ctx.lane_bitmap[devno] = lane_bitmap; mipi_rx_drv_set_mem_cken(devno, TRUE); mipi_rx_drv_set_phy_config(devno, INPUT_MODE_MIPI, lane_bitmap); mipi_init_int_ctrl_info(devno); return TD_SUCCESS; } static int mipi_set_combo_dev_attr(const combo_dev_attr_t *attr) { int ret; ret = mipi_check_comb_dev_attr(attr); if (ret < 0) { ot_err("mipi check combo_dev attr failed!\n"); return TD_FAILURE; } if (osal_mutex_lock_interruptible(&g_mipirx_mutex)) { return -ERESTARTSYS; } switch (attr->input_mode) { case INPUT_MODE_MIPI: { ret = mipi_set_mipi_dev_attr(attr); if (ret < 0) { ot_err("mipi set mipi attr failed!\n"); ret = TD_FAILURE; } break; } default: { ot_err("invalid input mode\n"); ret = TD_FAILURE; break; } } osal_mutex_unlock(&g_mipirx_mutex); return ret; } static int mipi_set_combo_dev_pn_swap(const combo_dev_pn_swap_t *combo_dev_pn_swap) { int ret; combo_dev_t devno; const unsigned char *pn_swap = NULL; devno = combo_dev_pn_swap->devno; pn_swap = combo_dev_pn_swap->pn_swap; if (devno >= COMBO_DEV_MAX_NUM) { ot_err("invalid combo_dev number(%d).\n", devno); return TD_FAILURE; } if (mipi_is_hs_mode_cfged() != TRUE) { ot_err("mipi must set hs mode before set pn swap!\n"); return TD_FAILURE; } if (!mipi_is_dev_valid(devno)) { ot_err("invalid combo dev num!\n"); return TD_FAILURE; } ret = check_pn_swap(devno, pn_swap); if (ret < 0) { ot_err("check pn reverse fail!\n"); return ret; } mipi_rx_drv_set_pn_swap(devno, pn_swap); osal_spin_lock(&g_mipirx_ctx_lock); ret = memcpy_s(g_mipirx_dev_ctx.dev_pn_swap[devno].pn_swap, sizeof(g_mipirx_dev_ctx.dev_pn_swap[devno].pn_swap), pn_swap, sizeof(unsigned char) * MIPI_LANE_NUM_PRE_DEV); if (ret != EOK) { osal_spin_unlock(&g_mipirx_ctx_lock); ot_err("memset_s err!\n"); return ret; } osal_spin_unlock(&g_mipirx_ctx_lock); return TD_SUCCESS; } static int mipi_set_phy_cmvmode(combo_dev_t devno, phy_cmv_mode_t cmv_mode) { input_mode_t input_mode; unsigned int lane_bit_map; if (devno >= COMBO_DEV_MAX_NUM) { ot_err("invalid mipi dev number(%d).\n", devno); return TD_FAILURE; } if (cmv_mode < PHY_CMV_GE1200MV || cmv_mode >= PHY_CMV_BUTT) { ot_err("invalid common mode voltage mode: %d, must be int [%d, %d)\n", cmv_mode, PHY_CMV_GE1200MV, PHY_CMV_BUTT); return TD_FAILURE; } if (osal_mutex_lock_interruptible(&g_mipirx_mutex)) { return -ERESTARTSYS; } if (!mipi_is_dev_cfged(devno)) { osal_mutex_unlock(&g_mipirx_mutex); ot_err("MIPI device %d has not beed configured\n", devno); return TD_FAILURE; } osal_spin_lock(&g_mipirx_ctx_lock); input_mode = g_mipirx_dev_ctx.combo_dev_attr[devno].input_mode; lane_bit_map = g_mipirx_dev_ctx.lane_bitmap[devno]; osal_spin_unlock(&g_mipirx_ctx_lock); if (input_mode != INPUT_MODE_MIPI) { osal_mutex_unlock(&g_mipirx_mutex); ot_err("devno: %d, input mode: %d, not support set common voltage mode\n", devno, input_mode); return TD_FAILURE; } mipi_rx_drv_set_phy_cmvmode(input_mode, cmv_mode, lane_bit_map); osal_mutex_unlock(&g_mipirx_mutex); return TD_SUCCESS; } static int mipi_reset_mipi_rx(combo_dev_t combo_dev) { if (combo_dev >= MIPI_RX_MAX_DEV_NUM) { ot_err("invalid combo_dev num(%d).\n", combo_dev); return TD_FAILURE; } mipi_rx_drv_core_reset(combo_dev); mipi_rx_unlock_config(); return TD_SUCCESS; } static int mipi_unreset_mipi_rx(combo_dev_t combo_dev) { if (combo_dev >= MIPI_RX_MAX_DEV_NUM) { ot_err("invalid combo_dev num(%d).\n", combo_dev); return TD_FAILURE; } mipi_rx_drv_core_unreset(combo_dev); return TD_SUCCESS; } static void mipi_set_dev_valid(lane_divide_mode_t mode) { int i; switch (mode) { case LANE_DIVIDE_MODE_0: for (i = 0; i < MIPI_RX_MAX_DEV_NUM; i++) { g_mipirx_dev_ctx.dev_valid[i] = 1; } break; default: break; } } static void mipi_set_lane_id_invalid(void) { int i, j; for (i = 0; i < COMBO_DEV_MAX_NUM; i++) { for (j = 0; j < MIPI_RX_LANE_NUM; j++) { g_mipirx_dev_ctx.combo_dev_attr[i].mipi_attr.lane_id[j] = MIPI_RX_LANE_ID_INVALID; } } mipi_init_lane_mode(); } static int mipi_set_hs_mode(lane_divide_mode_t lane_divide_mode) { int ret; if ((lane_divide_mode < LANE_DIVIDE_MODE_0) || (lane_divide_mode >= LANE_DIVIDE_MODE_BUTT)) { ot_err("invalid lane_divide_mode(%d), must be in [%d, %d)\n", lane_divide_mode, LANE_DIVIDE_MODE_0, LANE_DIVIDE_MODE_BUTT); return TD_FAILURE; } /* mipi pinmux */ mipi_set_pin_mux(); mipi_rx_drv_set_hs_mode(lane_divide_mode); osal_spin_lock(&g_mipirx_ctx_lock); g_mipirx_dev_ctx.lane_divide_mode = lane_divide_mode; g_mipirx_dev_ctx.hs_mode_cfged = TRUE; ret = memset_s(g_mipirx_dev_ctx.dev_valid, sizeof(g_mipirx_dev_ctx.dev_valid), 0, sizeof(g_mipirx_dev_ctx.dev_valid)); if (ret != EOK) { osal_spin_unlock(&g_mipirx_ctx_lock); return TD_FAILURE; } mipi_set_dev_valid(lane_divide_mode); mipi_set_lane_id_invalid(); osal_spin_unlock(&g_mipirx_ctx_lock); return TD_SUCCESS; } static int mipi_enable_mipi_rx_clock(combo_dev_t combo_dev) { if (combo_dev >= MIPI_RX_MAX_DEV_NUM) { ot_err("invalid combo_dev num(%d).\n", combo_dev); return TD_FAILURE; } mipi_rx_drv_enable_clock(combo_dev); return TD_SUCCESS; } static int mipi_disable_mipi_rx_clock(combo_dev_t combo_dev) { if (combo_dev >= MIPI_RX_MAX_DEV_NUM) { ot_err("invalid combo_dev num(%d).\n", combo_dev); return TD_FAILURE; } mipi_rx_drv_disable_clock(combo_dev); return TD_SUCCESS; } static int mipi_rx_set_dev_attr(const unsigned int *argp) { int ret; combo_dev_t devno; combo_dev_attr_t *pstcombo_dev_attr = (combo_dev_attr_t *)argp; ret = mipi_set_combo_dev_attr(pstcombo_dev_attr); if (ret < 0) { ot_err("mipi set combo_dev attr failed!\n"); return TD_FAILURE; } else { devno = pstcombo_dev_attr->devno; osal_spin_lock(&g_mipirx_ctx_lock); ret = memcpy_s(&g_mipirx_dev_ctx.combo_dev_attr[devno], sizeof(combo_dev_attr_t), pstcombo_dev_attr, sizeof(combo_dev_attr_t)); if (ret != EOK) { ot_err("memcpy_s err\n"); osal_spin_unlock(&g_mipirx_ctx_lock); return TD_FAILURE; } g_mipirx_dev_ctx.dev_cfged[devno] = TRUE; osal_spin_unlock(&g_mipirx_ctx_lock); } return TD_SUCCESS; } static int mipi_rx_set_pn_swap(const unsigned int *argp) { int ret; combo_dev_pn_swap_t *combo_dev_pn_reverse = (combo_dev_pn_swap_t *)argp; ret = mipi_set_combo_dev_pn_swap(combo_dev_pn_reverse); if (ret < 0) { ot_err("mipi set pn reverse failed!\n"); return TD_FAILURE; } return TD_SUCCESS; } static int mipi_rx_set_cmv_mode(const unsigned int *argp) { int ret; phy_cmv_t *phy_cmv = (phy_cmv_t *)argp; ret = mipi_set_phy_cmvmode(phy_cmv->devno, phy_cmv->cmv_mode); if (ret < 0) { ot_err("mipi set phy cmv mode failed!\n"); return TD_FAILURE; } return TD_SUCCESS; } static int mipi_rx_reset(const unsigned int *argp) { int ret; combo_dev_t combo_dev; ret = memcpy_s(&combo_dev, sizeof(combo_dev_t), argp, sizeof(combo_dev_t)); if (ret != EOK) { ot_err("memcpy_s err\n"); return TD_FAILURE; } ret = mipi_reset_mipi_rx(combo_dev); if (ret < 0) { ot_err("mipi reset mipi_rx failed!\n"); return TD_FAILURE; } return TD_SUCCESS; } static int mipi_rx_unreset(const unsigned int *argp) { int ret; combo_dev_t combo_dev; ret = memcpy_s(&combo_dev, sizeof(combo_dev_t), argp, sizeof(combo_dev_t)); if (ret != EOK) { ot_err("memcpy_s err\n"); return TD_FAILURE; } ret = mipi_unreset_mipi_rx(combo_dev); if (ret < 0) { ot_err("mipi unreset mipi_rx failed!\n"); return TD_FAILURE; } return TD_SUCCESS; } static int mipi_rx_set_hs_mode(const unsigned int *argp) { int ret; lane_divide_mode_t lane_divide_mode; ret = memcpy_s(&lane_divide_mode, sizeof(lane_divide_mode_t), argp, sizeof(lane_divide_mode_t)); if (ret != EOK) { ot_err("memcpy_s err\n"); return TD_FAILURE; } ret = mipi_set_hs_mode(lane_divide_mode); if (ret < 0) { ot_err("mipi set hs mode failed!\n"); return TD_FAILURE; } return TD_SUCCESS; } static int mipi_rx_enable_clock(const unsigned int *argp) { int ret; combo_dev_t combo_dev; ret = memcpy_s(&combo_dev, sizeof(combo_dev_t), argp, sizeof(combo_dev_t)); if (ret != EOK) { ot_err("memcpy_s err\n"); return TD_FAILURE; } ret = mipi_enable_mipi_rx_clock(combo_dev); if (ret < 0) { ot_err("mipi enable mipi_rx clock failed!\n"); return TD_FAILURE; } return TD_SUCCESS; } static int mipi_rx_disable_clock(const unsigned int *argp) { int ret; combo_dev_t combo_dev; ret = memcpy_s(&combo_dev, sizeof(combo_dev_t), argp, sizeof(combo_dev_t)); if (ret != EOK) { ot_err("memcpy_s err\n"); return TD_FAILURE; } ret = mipi_disable_mipi_rx_clock(combo_dev); if (ret < 0) { ot_err("mipi disable mipi_rx clock failed!\n"); return TD_FAILURE; } else { osal_spin_lock(&g_mipirx_ctx_lock); g_mipirx_dev_ctx.dev_cfged[combo_dev] = FALSE; osal_spin_unlock(&g_mipirx_ctx_lock); } return TD_SUCCESS; } static long mipi_rx_ioctl(unsigned int cmd, unsigned long arg, void *private_data) { unsigned int *argp = (unsigned int *)(uintptr_t)arg; int ret; mipirx_check_null_ptr_return(argp); ot_mipi_rx_unused(private_data); switch (cmd) { case OT_MIPI_SET_DEV_ATTR: { ret = mipi_rx_set_dev_attr(argp); break; } case OT_MIPI_SET_PN_SWAP: { ret = mipi_rx_set_pn_swap(argp); break; } case OT_MIPI_SET_PHY_CMVMODE: { ret = mipi_rx_set_cmv_mode(argp); break; } case OT_MIPI_RESET_MIPI: { ret = mipi_rx_reset(argp); break; } case OT_MIPI_UNRESET_MIPI: { ret = mipi_rx_unreset(argp); break; } case OT_MIPI_SET_HS_MODE: { ret = mipi_rx_set_hs_mode(argp); break; } case OT_MIPI_ENABLE_MIPI_CLOCK: { ret = mipi_rx_enable_clock(argp); break; } case OT_MIPI_DISABLE_MIPI_CLOCK: { ret = mipi_rx_disable_clock(argp); break; } default: { ot_err("invalid ot_mipi ioctl cmd\n"); ret = TD_FAILURE; break; } } return ret; } #ifdef CONFIG_COMPAT static long mipi_rx_compat_ioctl(unsigned int cmd, unsigned long arg, void *private_data) { return mipi_rx_ioctl(cmd, arg, private_data); } #endif static const char *mipi_get_intput_mode_name(input_mode_t input_mode) { switch (input_mode) { case INPUT_MODE_MIPI: return "MIPI"; default: break; } return "N/A"; } static const char *mipi_get_raw_data_type_name(data_type_t type) { switch (type) { case DATA_TYPE_YUV422_8BIT: return "yuv422_8bit"; default: break; } return "N/A"; } static const char *mipi_get_scan_mode_name(mipi_scan_mode_t scan_mode) { switch (scan_mode) { case MIPI_SCAN_INTERLACED: return "I"; case MIPI_SCAN_PROGRESSIVE: return "P"; default: break; } return "N/A"; } static const char *mipi_get_pn_swap_name(unsigned char pn_reverse) { switch (pn_reverse) { case FALSE: return "N"; case TRUE: return "Y"; default: break; } return "N/A"; } static const char *mipi_print_lane_divide_mode(lane_divide_mode_t mode) { switch (mode) { case LANE_DIVIDE_MODE_0: return "4"; default: break; } return "N/A"; } static unsigned int mipi_rx_get_phy_data(int phy_id, short lane_id) { int lane_id_in_phy; unsigned int phy_data; if (lane_id == -1) { return 0x0; } lane_id_in_phy = lane_id % MIPI_LANE_NUM_PRE_DEV; phy_data = mipi_rx_drv_get_phy_data(phy_id, lane_id_in_phy); return phy_data; } static unsigned int mipi_rx_get_phy_mipi_link_data(int phy_id, short lane_id) { int lane_id_in_phy; if (lane_id == -1) { return 0x0; } lane_id_in_phy = lane_id % MIPI_LANE_NUM_PRE_DEV; return mipi_rx_drv_get_phy_mipi_link_data(phy_id, lane_id_in_phy); } static void proc_show_mipi_device(osal_proc_entry_t *s) { combo_dev_t devno; input_mode_t input_mode; data_type_t data_type = DATA_TYPE_BUTT; osal_seq_printf(s, "\n----------------------------------------mipi dev attr" "-------------------------------------------------------------------\n"); osal_seq_printf(s, "%4s" "%12s" "%14s" "%9s" "%9s" "%9s" "%9s" "%12s" "\n", "dev", "work_mode", "data_type", "img_x", "img_y", "img_w", "img_h", "scan_mode"); for (devno = 0; devno < MIPI_RX_MAX_DEV_NUM; devno++) { combo_dev_attr_t *pdev_attr = &g_mipirx_dev_ctx.combo_dev_attr[devno]; input_mode = pdev_attr->input_mode; if (!mipi_is_dev_cfged(devno)) { continue; } if (input_mode == INPUT_MODE_MIPI) { data_type = pdev_attr->mipi_attr.input_data_type; } osal_seq_printf(s, "%4d" "%12s" "%14s" "%9d" "%9d" "%9d" "%9d" "%12s" "\n", devno, mipi_get_intput_mode_name(input_mode), mipi_get_raw_data_type_name(data_type), pdev_attr->img_rect.x, pdev_attr->img_rect.y, pdev_attr->img_rect.width, pdev_attr->img_rect.height, mipi_get_scan_mode_name(pdev_attr->scan_mode)); } } static void proc_show_mipi_lane(osal_proc_entry_t *s) { combo_dev_t devno; input_mode_t input_mode; osal_seq_printf(s, "\n----------------------------------------mipi lane info" "------------------------------------------------------------------\n"); osal_seq_printf(s, "%4s" "%24s" "%24s" "\n", "dev", "lane_id", "pn_swap"); for (devno = 0; devno < MIPI_RX_MAX_DEV_NUM; devno++) { combo_dev_attr_t *pdev_attr = &g_mipirx_dev_ctx.combo_dev_attr[devno]; combo_dev_pn_swap_t *pn_swap = &g_mipirx_dev_ctx.dev_pn_swap[devno]; input_mode = pdev_attr->input_mode; if (!mipi_is_dev_cfged(devno)) { continue; } if (input_mode == INPUT_MODE_MIPI) { osal_seq_printf(s, "%4d" "%15d,%3d,%3d,%3d" "%12s,%3s,%3s,%3s" "\n", devno, pdev_attr->mipi_attr.lane_id[MIPI_LANE_ID_0], pdev_attr->mipi_attr.lane_id[MIPI_LANE_ID_1], pdev_attr->mipi_attr.lane_id[MIPI_LANE_ID_2], pdev_attr->mipi_attr.lane_id[MIPI_LANE_ID_3], mipi_get_pn_swap_name(pn_swap->pn_swap[MIPI_LANE_ID_0]), mipi_get_pn_swap_name(pn_swap->pn_swap[MIPI_LANE_ID_1]), mipi_get_pn_swap_name(pn_swap->pn_swap[MIPI_LANE_ID_2]), mipi_get_pn_swap_name(pn_swap->pn_swap[MIPI_LANE_ID_3])); } } } static void show_mipi_phy_data(int phy_num, osal_proc_entry_t *s, combo_dev_attr_t *pdev_attr) { int i; if (pdev_attr->mipi_attr.lane_id[MIPI_LANE_ID_0] == -1) { osal_seq_printf(s, " %5s", "--,"); } else { osal_seq_printf(s, " 0x%02x,", mipi_rx_get_phy_data(phy_num, pdev_attr->mipi_attr.lane_id[MIPI_LANE_ID_0])); } for (i = MIPI_LANE_ID_1; i < MIPI_LANE_ID_3; i++) { if (pdev_attr->mipi_attr.lane_id[i] == -1) { osal_seq_printf(s, "%5s", "--,"); } else { osal_seq_printf(s, "0x%02x,", mipi_rx_get_phy_data(phy_num, pdev_attr->mipi_attr.lane_id[i])); } } if (pdev_attr->mipi_attr.lane_id[MIPI_LANE_ID_3] == -1) { osal_seq_printf(s, "%4s", "--"); } else { osal_seq_printf(s, " 0x%02x", mipi_rx_get_phy_data(phy_num, pdev_attr->mipi_attr.lane_id[MIPI_LANE_ID_3])); } } static void show_mipi_link_data(int phy_num, osal_proc_entry_t *s, combo_dev_attr_t *pdev_attr) { int i; if (pdev_attr->mipi_attr.lane_id[MIPI_LANE_ID_0] == -1) { osal_seq_printf(s, " %5s", "--,"); } else { osal_seq_printf(s, " 0x%02x,", mipi_rx_get_phy_mipi_link_data(phy_num, pdev_attr->mipi_attr.lane_id[MIPI_LANE_ID_0])); } for (i = MIPI_LANE_ID_1; i < MIPI_LANE_ID_3; i++) { if (pdev_attr->mipi_attr.lane_id[i] == -1) { osal_seq_printf(s, "%5s", "--,"); } else { osal_seq_printf(s, "0x%02x,", mipi_rx_get_phy_mipi_link_data(phy_num, pdev_attr->mipi_attr.lane_id[i])); } } if (pdev_attr->mipi_attr.lane_id[MIPI_LANE_ID_3] == -1) { osal_seq_printf(s, "%4s", "--"); } else { osal_seq_printf(s, " 0x%02x", mipi_rx_get_phy_mipi_link_data(phy_num, pdev_attr->mipi_attr.lane_id[MIPI_LANE_ID_3])); } } static void proc_show_mipi_phy_data(osal_proc_entry_t *s) { int i; osal_seq_printf(s, "\n----------------------------------------mipi phy data info" "--------------------------------------------------------------\n"); osal_seq_printf(s, "%8s" "%15s" "%19s" "%24s" "\n", "phy_id", "lane_id", "phy_data", "mipi_data"); for (i = 0; i < MIPI_RX_MAX_PHY_NUM; i++) { combo_dev_attr_t *pdev_attr = &g_mipirx_dev_ctx.combo_dev_attr[i]; if (!mipi_is_dev_cfged(i)) { continue; } osal_seq_printf(s, "%8d%8d,%2d,%2d,%2d", i, pdev_attr->mipi_attr.lane_id[MIPI_LANE_ID_0], pdev_attr->mipi_attr.lane_id[MIPI_LANE_ID_1], pdev_attr->mipi_attr.lane_id[MIPI_LANE_ID_2], pdev_attr->mipi_attr.lane_id[MIPI_LANE_ID_3]); show_mipi_phy_data(i, s, pdev_attr); show_mipi_link_data(i, s, pdev_attr); osal_seq_printf(s, "\n"); } } static void proc_show_mipi_detect_info(osal_proc_entry_t *s, const combo_dev_t devno_array[], int mipi_cnt) { img_size_t image_size; short vc_num; int devno_idx; osal_seq_printf(s, "\n----------------------------------------mipi detect info" "----------------------------------------------------------------\n"); osal_seq_printf(s, "%4s%5s%8s%9s\n", "dev", "vc", "width", "height"); for (devno_idx = 0; devno_idx < mipi_cnt; devno_idx++) { for (vc_num = 0; vc_num < MIPI_VC_NUM; vc_num++) { mipi_rx_drv_get_mipi_imgsize_statis(devno_array[devno_idx], vc_num, &image_size); osal_seq_printf(s, "%4d%5d%8d%9d\n", devno_array[devno_idx], vc_num, image_size.width, image_size.height); } } } static void proc_show_mipi_hs_mode(osal_proc_entry_t *s) { lane_divide_mode_t lane_divide_mode; osal_spin_lock(&g_mipirx_ctx_lock); lane_divide_mode = g_mipirx_dev_ctx.lane_divide_mode; osal_spin_unlock(&g_mipirx_ctx_lock); osal_seq_printf(s, "\n----------------------------------------mipi lane divide mode" "-----------------------------------------------------------\n"); osal_seq_printf(s, "%5s" "%20s" "\n", "mode", "lane_divide"); osal_seq_printf(s, "%5d" "%20s" "\n", lane_divide_mode, mipi_print_lane_divide_mode(lane_divide_mode)); } static void proc_show_phy_cil_int_err_cnt1(osal_proc_entry_t *s) { int phy_id; phy_err_int_cnt_t *phy_err_int_cnt = NULL; osal_seq_printf(s, "\n----------------------------------------phy cil err int info 1" "----------------------------------------------------------\n"); osal_seq_printf(s, "%8s%14s%13s%15s%15s%15s%15s%11s%10s\n", "phy_id", "clk2_tm_out", "clk_tm_out", "lane0_tm_out", "lane1_tm_out", "lane2_tm_out", "lane3_tm_out", "clk2_esc", "clk_esc"); for (phy_id = 0; phy_id < MIPI_RX_MAX_PHY_NUM; phy_id++) { if (!mipi_is_dev_cfged(phy_id)) { continue; } phy_err_int_cnt = mipi_hal_get_phy_err_int(phy_id); osal_seq_printf(s, "%8d%14d%13d%15d%15d%15d%15d%11d%10d\n", phy_id, phy_err_int_cnt->clk1_fsm_timeout_err_cnt, phy_err_int_cnt->clk0_fsm_timeout_err_cnt, phy_err_int_cnt->d0_fsm_timeout_err_cnt, phy_err_int_cnt->d1_fsm_timeout_err_cnt, phy_err_int_cnt->d2_fsm_timeout_err_cnt, phy_err_int_cnt->d3_fsm_timeout_err_cnt, phy_err_int_cnt->clk1_fsm_escape_err_cnt, phy_err_int_cnt->clk0_fsm_escape_err_cnt); } } static void proc_show_phy_cil_int_err_cnt2(osal_proc_entry_t *s) { int phy_id; phy_err_int_cnt_t *phy_err_int_cnt = NULL; osal_seq_printf(s, "\n----------------------------------------phy cil err int info 2" "----------------------------------------------------------\n"); osal_seq_printf(s, "%8s%12s%12s%12s%12s\n", "phy_id", "lane0_esc", "lane1_esc", "lane2_esc", "lane3_esc"); for (phy_id = 0; phy_id < MIPI_RX_MAX_PHY_NUM; phy_id++) { if (!mipi_is_dev_cfged(phy_id)) { continue; } phy_err_int_cnt = mipi_hal_get_phy_err_int(phy_id); osal_seq_printf(s, "%8d%12d%12d%12d%12d\n", phy_id, phy_err_int_cnt->d0_fsm_escape_err_cnt, phy_err_int_cnt->d1_fsm_escape_err_cnt, phy_err_int_cnt->d2_fsm_escape_err_cnt, phy_err_int_cnt->d3_fsm_escape_err_cnt); } } static void proc_show_mipi_int_err1(osal_proc_entry_t *s, const combo_dev_t devno_array[], int mipi_cnt) { int devno_idx; combo_dev_t devno; mipi_err_int_cnt_t *mipi_err_int_cnt = NULL; osal_seq_printf(s, "\n----------------------------------------mipi error int info 1" "-----------------------------------------------------------\n"); osal_seq_printf(s, "%4s%6s%9s%9s%9s%9s%18s%18s%18s%18s\n", "dev", "ecc2", "vc0_crc", "vc1_crc", "vc2_crc", "vc3_crc", "vc0_ecc_correct", "vc1_ecc_correct", "vc2_ecc_correct", "vc3_ecc_correct"); for (devno_idx = 0; devno_idx < mipi_cnt; devno_idx++) { devno = devno_array[devno_idx]; mipi_err_int_cnt = mipi_hal_get_mipi_err_int(devno); osal_seq_printf(s, "%4d%6d%9d%9d%9d%9d%18d%18d%18d%18d\n", devno, mipi_err_int_cnt->err_ecc_double_cnt, mipi_err_int_cnt->vc0_err_crc_cnt, mipi_err_int_cnt->vc1_err_crc_cnt, mipi_err_int_cnt->vc2_err_crc_cnt, mipi_err_int_cnt->vc3_err_crc_cnt, mipi_err_int_cnt->vc0_err_ecc_corrected_cnt, mipi_err_int_cnt->vc1_err_ecc_corrected_cnt, mipi_err_int_cnt->vc2_err_ecc_corrected_cnt, mipi_err_int_cnt->vc3_err_ecc_corrected_cnt); } } static void proc_show_mipi_int_err3(osal_proc_entry_t *s, const combo_dev_t devno_array[], int mipi_cnt) { int devno_idx; combo_dev_t devno; mipi_err_int_cnt_t *mipi_err_int_cnt = NULL; osal_seq_printf(s, "\n----------------------------------------mipi error int info 3" "-----------------------------------------------------------\n"); osal_seq_printf(s, "%4s%13s%13s%13s%13s%14s%14s%14s%14s\n", "dev", "vc0_frm_seq", "vc1_frm_seq", "vc2_frm_seq", "vc3_frm_seq", "vc0_bndry_mt", "vc1_bndry_mt", "vc2_bndry_mt", "vc3_bndry_mt"); for (devno_idx = 0; devno_idx < mipi_cnt; devno_idx++) { devno = devno_array[devno_idx]; mipi_err_int_cnt = mipi_hal_get_mipi_err_int(devno); osal_seq_printf(s, "%4d%13d%13d%13d%13d%14d%14d%14d%14d\n", devno, mipi_err_int_cnt->err_f_seq_vc0_cnt, mipi_err_int_cnt->err_f_seq_vc1_cnt, mipi_err_int_cnt->err_f_seq_vc2_cnt, mipi_err_int_cnt->err_f_seq_vc3_cnt, mipi_err_int_cnt->err_f_bndry_match_vc0_cnt, mipi_err_int_cnt->err_f_bndry_match_vc1_cnt, mipi_err_int_cnt->err_f_bndry_match_vc2_cnt, mipi_err_int_cnt->err_f_bndry_match_vc3_cnt); } } static void proc_show_mipi_int_err4(osal_proc_entry_t *s, const combo_dev_t devno_array[], int mipi_cnt) { int devno_idx; combo_dev_t devno; mipi_err_int_cnt_t *mipi_err_int_cnt = NULL; osal_seq_printf(s, "\n----------------------------------------mipi error int info 4" "-----------------------------------------------------------\n"); osal_seq_printf(s, "%4s%20s%19s%20s%21s\n", "dev", "data_fifo_read_err", "cmd_fifo_read_err", "cmd_fifo_write_err", "data_fifo_write_err"); for (devno_idx = 0; devno_idx < mipi_cnt; devno_idx++) { devno = devno_array[devno_idx]; mipi_err_int_cnt = mipi_hal_get_mipi_err_int(devno); osal_seq_printf(s, "%4d%20d%19d%20d%21d\n", devno, mipi_err_int_cnt->data_fifo_rderr_cnt, mipi_err_int_cnt->cmd_fifo_rderr_cnt, mipi_err_int_cnt->data_fifo_wrerr_cnt, mipi_err_int_cnt->cmd_fifo_wrerr_cnt); } } static void proc_show_mipi_int_err(osal_proc_entry_t *s, const combo_dev_t devno_array[], int mipi_cnt) { proc_show_mipi_int_err1(s, devno_array, mipi_cnt); proc_show_mipi_int_err3(s, devno_array, mipi_cnt); proc_show_mipi_int_err4(s, devno_array, mipi_cnt); } static void proc_show_align_int_err(osal_proc_entry_t *s) { combo_dev_t devno; align_err_int_cnt_t *align_err_int_cnt = NULL; osal_seq_printf(s, "\n----------------------------------------align error int info" "------------------------------------------------------------\n"); osal_seq_printf(s, "%4s%16s%12s%12s%12s%12s\n", "dev", "fifo_full_err", "lane0_err", "lane1_err", "lane2_err", "lane3_err"); for (devno = 0; devno < MIPI_RX_MAX_DEV_NUM; devno++) { if (!mipi_is_dev_cfged(devno)) { continue; } align_err_int_cnt = mipi_hal_get_align_err_int(devno); osal_seq_printf(s, "%4d%16d%12d%12d%12d%12d\n", devno, align_err_int_cnt->fifo_full_err_cnt, align_err_int_cnt->lane0_align_err_cnt, align_err_int_cnt->lane1_align_err_cnt, align_err_int_cnt->lane2_align_err_cnt, align_err_int_cnt->lane3_align_err_cnt); } } static void mipi_proc_show(osal_proc_entry_t *s) { combo_dev_t devno; int mipi_cnt = 0; input_mode_t input_mode; combo_dev_attr_t *dev_attr = NULL; combo_dev_t devno_mipi[MIPI_RX_MAX_DEV_NUM] = {0}; for (devno = 0; devno < MIPI_RX_MAX_DEV_NUM; devno++) { if (!mipi_is_dev_cfged(devno)) { continue; } osal_spin_lock(&g_mipirx_ctx_lock); dev_attr = &g_mipirx_dev_ctx.combo_dev_attr[devno]; input_mode = dev_attr->input_mode; osal_spin_unlock(&g_mipirx_ctx_lock); if (input_mode == INPUT_MODE_MIPI) { devno_mipi[mipi_cnt] = devno; mipi_cnt++; } } if ((mipi_cnt > 0) && (mipi_cnt <= MIPI_RX_MAX_DEV_NUM)) { proc_show_mipi_hs_mode(s); proc_show_mipi_device(s); proc_show_mipi_lane(s); proc_show_mipi_phy_data(s); proc_show_mipi_detect_info(s, devno_mipi, mipi_cnt); proc_show_phy_cil_int_err_cnt1(s); proc_show_phy_cil_int_err_cnt2(s); proc_show_mipi_int_err(s, devno_mipi, mipi_cnt); proc_show_align_int_err(s); } } static int mipi_rx_proc_show(osal_proc_entry_t *s) { osal_seq_printf(s, "\nmodule: [mipi_rx], build time["__DATE__", "__TIME__"]\n"); mipi_proc_show(s); return TD_SUCCESS; } static int mipi_rx_init(void) { int ret; osal_mutex_init(&g_mipirx_mutex); osal_spin_lock_init(&g_mipirx_ctx_lock); ret = mipi_rx_drv_init(); if (ret < 0) { ot_err("mipi_rx_drv_init fail!\n"); return TD_FAILURE; } return TD_SUCCESS; } static void mipi_rx_exit(void) { mipi_rx_drv_exit(); osal_spin_lock_destroy(&g_mipirx_ctx_lock); osal_mutex_destroy(&g_mipirx_mutex); } static int mipi_rx_open(void *private_data) { ot_mipi_rx_unused(private_data); mipi_rx_unlock_config(); return TD_SUCCESS; } static int mipi_rx_release(void *private_data) { ot_mipi_rx_unused(private_data); return TD_SUCCESS; } static osal_fileops_t g_mipi_rx_fops = { .open = mipi_rx_open, .release = mipi_rx_release, .unlocked_ioctl = mipi_rx_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = mipi_rx_compat_ioctl, #endif }; int mipi_rx_mod_init(void) { int ret; osal_proc_entry_t *mipi_rx_proc_entry = NULL; g_mipirx_dev = osal_createdev(MIPI_RX_DEV_NAME); if (g_mipirx_dev == NULL) { ot_err("create mipi_rx device failed!\n"); goto fail0; } g_mipirx_dev->fops = &g_mipi_rx_fops; g_mipirx_dev->minor = OT_MEDIA_DYNAMIC_MINOR; ret = osal_registerdevice(g_mipirx_dev); if (ret < 0) { ot_err("register mipi_rx device failed!\n"); goto fail1; } mipi_rx_proc_entry = osal_create_proc_entry(MIPI_RX_PROC_NAME, NULL); if (mipi_rx_proc_entry == NULL) { ot_err("create mipi_rx proc(%s) failed!\n", MIPI_RX_PROC_NAME); goto fail2; } mipi_rx_proc_entry->read = mipi_rx_proc_show; mipi_rx_proc_entry->write = NULL; ret = mipi_rx_init(); if (ret < 0) { ot_err("mipi_rx_init failed!\n"); goto fail3; } osal_printk("load mipi_rx.ko ....OK!\n"); return TD_SUCCESS; fail3: osal_remove_proc_entry(MIPI_RX_PROC_NAME, NULL); fail2: osal_deregisterdevice(g_mipirx_dev); fail1: osal_destroydev(g_mipirx_dev); g_mipirx_dev = NULL; fail0: ot_err("load mipi_rx.ko ....failed!\n"); return TD_FAILURE; } void mipi_rx_mod_exit(void) { mipi_rx_exit(); osal_remove_proc_entry(MIPI_RX_PROC_NAME, NULL); osal_deregisterdevice(g_mipirx_dev); osal_destroydev(g_mipirx_dev); g_mipirx_dev = NULL; osal_printk("unload mipi_rx.ko ....OK!\n"); }