diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index 4eeea1cb100c..1cfc74089633 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -1826,7 +1826,9 @@ static int rkcif_csi_channel_init(struct rkcif_stream *stream, channel->vc = stream->vc; else channel->vc = channel->id; - + v4l2_dbg(3, rkcif_debug, &dev->v4l2_dev, + "%s: channel width %d, height %d, virtual_width %d, vc %d\n", __func__, + channel->width, channel->height, channel->virtual_width, channel->vc); return 0; } @@ -1941,7 +1943,10 @@ static int rkcif_csi_channel_set(struct rkcif_stream *stream, else val &= ~LVDS_COMPACT; } - + if (stream->is_high_align) + val |= CSI_ENABLE_MIPI_HIGH_ALIGN; + else + val &= ~CSI_ENABLE_MIPI_HIGH_ALIGN; rkcif_write_register(dev, get_reg_index_of_id_ctrl0(channel->id), val); return 0; @@ -2944,12 +2949,21 @@ static int rkcif_stream_start(struct rkcif_stream *stream) | stream->cif_fmt_in->dvp_fmt_val | xfer_mode | yc_swap | multi_id_en | multi_id_sel | multi_id_mode | bt1120_edge_mode; + + if (stream->is_high_align) + val |= CIF_HIGH_ALIGN; + else + val &= ~CIF_HIGH_ALIGN; rkcif_write_register(dev, CIF_REG_DVP_FOR, val); val = stream->pixm.width; if (stream->cif_fmt_in->fmt_type == CIF_FMT_TYPE_RAW) { fmt = find_output_fmt(stream, stream->pixm.pixelformat); - val = stream->pixm.width * rkcif_cal_raw_vir_line_ratio(stream, fmt); + if (fmt->fmt_type == CIF_FMT_TYPE_RAW && + fmt->csi_fmt_val == CSI_WRDDR_TYPE_RAW8) + val = ALIGN(stream->pixm.width * fmt->raw_bpp / 8, 256); + else + val = stream->pixm.width * rkcif_cal_raw_vir_line_ratio(stream, fmt); } rkcif_write_register(dev, CIF_REG_DVP_VIR_LINE_WIDTH, val); rkcif_write_register(dev, CIF_REG_DVP_SET_SIZE, @@ -3410,10 +3424,19 @@ void rkcif_stream_init(struct rkcif_device *dev, u32 id) stream->crop_dyn_en = false; stream->crop_mask = 0x0; - if (dev->chip_id >= CHIP_RV1126_CIF) - stream->is_compact = true; - else - stream->is_compact = false; + if (dev->inf_id == RKCIF_DVP) { + if (dev->chip_id <= CHIP_RK3568_CIF) + stream->is_compact = false; + else + stream->is_compact = true; + } else { + if (dev->chip_id >= CHIP_RV1126_CIF) + stream->is_compact = true; + else + stream->is_compact = false; + } + + stream->is_high_align = false; if (dev->chip_id == CHIP_RV1126_CIF || dev->chip_id == CHIP_RV1126_CIF_LITE) @@ -3846,42 +3869,53 @@ err: return -EINVAL; } -static int rkcif_g_ctrl(struct file *file, void *fh, - struct v4l2_control *ctrl) -{ - struct rkcif_stream *stream = video_drvdata(file); - - switch (ctrl->id) { - case V4L2_CID_CIF_DATA_COMPACT: - if (stream->is_compact) - ctrl->value = CSI_MEM_COMPACT; - else - ctrl->value = CSI_MEM_BYTE_LE; - break; - default: - return -EINVAL; - } - - return 0; -} - -static int rkcif_s_ctrl(struct file *file, void *fh, - struct v4l2_control *ctrl) +static long rkcif_ioctl_default(struct file *file, void *fh, + bool valid_prio, unsigned int cmd, void *arg) { struct rkcif_stream *stream = video_drvdata(file); struct rkcif_device *dev = stream->cifdev; + const struct cif_input_fmt *in_fmt; + struct v4l2_rect rect; + int vc = 0; - if (stream->state == RKCIF_STATE_STREAMING) { - v4l2_err(&dev->v4l2_dev, "set failed, the stream is streaming\n"); - return -EBUSY; - } - - switch (ctrl->id) { - case V4L2_CID_CIF_DATA_COMPACT: - if (ctrl->value == CSI_LVDS_MEM_COMPACT) + switch (cmd) { + case RKCIF_CMD_GET_CSI_MEMORY_MODE: + if (stream->is_compact) { + *(int *)arg = CSI_LVDS_MEM_COMPACT; + } else { + if (stream->is_high_align) + *(int *)arg = CSI_LVDS_MEM_WORD_HIGH_ALIGN; + else + *(int *)arg = CSI_LVDS_MEM_WORD_LOW_ALIGN; + } + break; + case RKCIF_CMD_SET_CSI_MEMORY_MODE: + if (dev->terminal_sensor.sd) { + in_fmt = get_input_fmt(dev->terminal_sensor.sd, &rect, 0, &vc); + if (in_fmt == NULL) { + v4l2_err(&dev->v4l2_dev, "can't get sensor input format\n"); + return -EINVAL; + } + } else { + v4l2_err(&dev->v4l2_dev, "can't get sensor device\n"); + return -EINVAL; + } + if (*(int *)arg == CSI_LVDS_MEM_COMPACT) { + if (((dev->inf_id == RKCIF_DVP && dev->chip_id <= CHIP_RK3568_CIF) || + (dev->inf_id == RKCIF_MIPI_LVDS && dev->chip_id < CHIP_RV1126_CIF)) && + in_fmt->csi_fmt_val != CSI_WRDDR_TYPE_RAW8) { + v4l2_err(&dev->v4l2_dev, "device not support compact\n"); + return -EINVAL; + } stream->is_compact = true; - else + stream->is_high_align = false; + } else if (*(int *)arg == CSI_LVDS_MEM_WORD_HIGH_ALIGN) { stream->is_compact = false; + stream->is_high_align = true; + } else { + stream->is_compact = false; + stream->is_high_align = false; + } break; default: return -EINVAL; @@ -3913,8 +3947,7 @@ static const struct v4l2_ioctl_ops rkcif_v4l2_ioctl_ops = { .vidioc_g_selection = rkcif_g_selection, .vidioc_enum_frameintervals = rkcif_enum_frameintervals, .vidioc_enum_framesizes = rkcif_enum_framesizes, - .vidioc_g_ctrl = rkcif_g_ctrl, - .vidioc_s_ctrl = rkcif_s_ctrl, + .vidioc_default = rkcif_ioctl_default, }; static void rkcif_unregister_stream_vdev(struct rkcif_stream *stream) diff --git a/drivers/media/platform/rockchip/cif/dev.c b/drivers/media/platform/rockchip/cif/dev.c index 8c66d1704249..ba5cdf82266a 100644 --- a/drivers/media/platform/rockchip/cif/dev.c +++ b/drivers/media/platform/rockchip/cif/dev.c @@ -152,6 +152,64 @@ static ssize_t rkcif_store_dummybuf_mode(struct device *dev, return len; } +/* show the compact mode of each stream in stream index order, + * 1 for compact, 0 for 16bit + */ +static ssize_t rkcif_show_memory_mode(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rkcif_device *cif_dev = (struct rkcif_device *)dev_get_drvdata(dev); + int ret; + + ret = snprintf(buf, PAGE_SIZE, + "stream[0~3] %d %d %d %d, 0(low align) 1(high align) 2(compact)\n", + cif_dev->stream[0].is_compact ? 2 : (cif_dev->stream[0].is_high_align ? 1 : 0), + cif_dev->stream[1].is_compact ? 2 : (cif_dev->stream[1].is_high_align ? 1 : 0), + cif_dev->stream[2].is_compact ? 2 : (cif_dev->stream[2].is_high_align ? 1 : 0), + cif_dev->stream[3].is_compact ? 2 : (cif_dev->stream[3].is_high_align ? 1 : 0)); + return ret; +} + +static ssize_t rkcif_store_memory_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct rkcif_device *cif_dev = (struct rkcif_device *)dev_get_drvdata(dev); + int i, index; + char val[4]; + + if (buf) { + index = 0; + for (i = 0; i < len; i++) { + if (buf[i] == ' ') { + continue; + } else if (buf[i] == '\0') { + break; + } else { + val[index] = buf[i]; + index++; + if (index == 4) + break; + } + } + + for (i = 0; i < index; i++) { + if (cif_dev->stream[i].is_compact) { + dev_info(cif_dev->dev, "stream[%d] set memory align fail, is compact mode\n", + i); + continue; + } + if (val[i] - '0' == 0) + cif_dev->stream[i].is_high_align = false; + else + cif_dev->stream[i].is_high_align = true; + } + } + + return len; +} + static DEVICE_ATTR(compact_test, S_IWUSR | S_IRUSR, rkcif_show_compact_mode, rkcif_store_compact_mode); @@ -161,11 +219,15 @@ static DEVICE_ATTR(wait_line, S_IWUSR | S_IRUSR, static DEVICE_ATTR(is_use_dummybuf, S_IWUSR | S_IRUSR, rkcif_show_dummybuf_mode, rkcif_store_dummybuf_mode); +static DEVICE_ATTR(is_high_align, S_IWUSR | S_IRUSR, + rkcif_show_memory_mode, rkcif_store_memory_mode); + static struct attribute *dev_attrs[] = { &dev_attr_compact_test.attr, &dev_attr_wait_line.attr, &dev_attr_is_use_dummybuf.attr, + &dev_attr_is_high_align.attr, NULL, }; diff --git a/drivers/media/platform/rockchip/cif/dev.h b/drivers/media/platform/rockchip/cif/dev.h index 9b4573fac866..d8d65675c3da 100644 --- a/drivers/media/platform/rockchip/cif/dev.h +++ b/drivers/media/platform/rockchip/cif/dev.h @@ -447,6 +447,7 @@ struct rkcif_stream { bool is_line_inten; bool is_can_stop; bool is_buf_active; + bool is_high_align; }; struct rkcif_lvds_subdev { diff --git a/drivers/media/platform/rockchip/cif/regs.h b/drivers/media/platform/rockchip/cif/regs.h index b8f1f01f515a..44a8f392db18 100644 --- a/drivers/media/platform/rockchip/cif/regs.h +++ b/drivers/media/platform/rockchip/cif/regs.h @@ -432,6 +432,7 @@ enum cif_reg_index { #define BT656_1120_MULTI_ID_1_MASK ~(0x03 << 12) #define BT656_1120_MULTI_ID_2_MASK ~(0x03 << 20) #define BT656_1120_MULTI_ID_3_MASK ~(0x03 << 28) +#define CIF_HIGH_ALIGN (0x01 << 18) /* CIF_SCL_CTRL */ #define ENABLE_SCL_DOWN (0x01 << 0) @@ -515,6 +516,7 @@ enum cif_reg_index { #define CSI_YUV_INPUT_ORDER_VYUY (0x1 << 16) #define CSI_YUV_INPUT_ORDER_YUYV (0x2 << 16) #define CSI_YUV_INPUT_ORDER_YVYU (0x3 << 16) +#define CSI_ENABLE_MIPI_HIGH_ALIGN (0x1 << 31) #define LVDS_ENABLE_CAPTURE (0x1 << 16) #define LVDS_MODE(mode) (((mode) & 0x7) << 17) diff --git a/include/uapi/linux/rkcif-config.h b/include/uapi/linux/rkcif-config.h index 9e05f3abf273..0fa5f040f321 100644 --- a/include/uapi/linux/rkcif-config.h +++ b/include/uapi/linux/rkcif-config.h @@ -11,12 +11,31 @@ #define RKCIF_API_VERSION KERNEL_VERSION(0, 1, 0xa) -#define V4L2_CID_CIF_DATA_COMPACT (V4L2_CID_PRIVATE_BASE + 0) +#define RKCIF_CMD_GET_CSI_MEMORY_MODE \ + _IOR('V', BASE_VIDIOC_PRIVATE + 0, int) + +#define RKCIF_CMD_SET_CSI_MEMORY_MODE \ + _IOW('V', BASE_VIDIOC_PRIVATE + 1, int) + +/* cif memory mode + * 0: raw12/raw10/raw8 8bit memory compact + * 1: raw12/raw10 16bit memory one pixel + * low align for rv1126/rv1109/rk356x + * |15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0| + * | -| -| -| -|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0| + * 2: raw12/raw10 16bit memory one pixel + * high align for rv1126/rv1109/rk356x + * |15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0| + * |11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0| -| -| -| -| + * + * note: rv1109/rv1126/rk356x dvp only support uncompact mode, + * and can be set low align or high align + */ enum cif_csi_lvds_memory { - CSI_LVDS_MEM_16BITS = 0, - CSI_LVDS_MEM_COMPACT, - CSI_LVDS_MEM_MAX, + CSI_LVDS_MEM_COMPACT = 0, + CSI_LVDS_MEM_WORD_LOW_ALIGN = 1, + CSI_LVDS_MEM_WORD_HIGH_ALIGN = 2, }; #endif