diff --git a/drivers/media/i2c/adv7481.c b/drivers/media/i2c/adv7481.c index a14f13c44a36..7cac0a8abd81 100644 --- a/drivers/media/i2c/adv7481.c +++ b/drivers/media/i2c/adv7481.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1031,7 +1031,10 @@ static long adv7481_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) struct msm_ba_v4l2_ioctl_t adv_arg = *(struct msm_ba_v4l2_ioctl_t *)arg; long ret = 0; int param = 0; + uint8_t status = 0; + struct timespec ts; struct csi_ctrl_params user_csi; + struct field_info_params user_field; struct adv7481_vid_params vid_params; struct adv7481_hdmi_params hdmi_params; @@ -1091,6 +1094,28 @@ static long adv7481_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) } break; } + case VIDIOC_G_FIELD_INFO: + /* Select SDP read-only Map 1 */ + adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr, + SDP_RW_MAP_REG, 0x02); + status = adv7481_rd_byte(&state->i2c_client, + state->i2c_sdp_addr, SDP_RO_MAP_1_FIELD_ADDR); + adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr, + SDP_RW_MAP_REG, 0x00); + + user_field.even_field = ADV_REG_GETFIELD(status, + SDP_RO_MAP_1_EVEN_FIELD); + get_monotonic_boottime(&ts); + user_field.field_ts.tv_sec = ts.tv_sec; + user_field.field_ts.tv_usec = ts.tv_nsec/1000; + + if (copy_to_user((void __user *)adv_arg.ptr, + (void *)&user_field, + sizeof(struct field_info_params))) { + pr_err("%s: Failed to copy FIELD params\n", __func__); + return -EINVAL; + } + break; default: pr_err("Not a typewriter! Command: 0x%x", cmd); ret = -ENOTTY; diff --git a/drivers/media/i2c/adv7481_reg.h b/drivers/media/i2c/adv7481_reg.h index b0bb5784d2ef..76c992cf4394 100644 --- a/drivers/media/i2c/adv7481_reg.h +++ b/drivers/media/i2c/adv7481_reg.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -411,6 +411,11 @@ #define SDP_RO_MAIN_IN_LOCK_BMSK 0x0001 #define SDP_RO_MAIN_IN_LOCK_SHFT 0 +/* SDP R/O Map 1 Registers */ +#define SDP_RO_MAP_1_FIELD_ADDR 0x45 +#define SDP_RO_MAP_1_EVEN_FIELD_BMSK 0x10 +#define SDP_RO_MAP_1_EVEN_FIELD_SHFT 4 + /* * CSI Map Registers diff --git a/drivers/media/platform/msm/ais/isp/msm_isp.h b/drivers/media/platform/msm/ais/isp/msm_isp.h index 86974eeb4a32..419615cc9b4a 100644 --- a/drivers/media/platform/msm/ais/isp/msm_isp.h +++ b/drivers/media/platform/msm/ais/isp/msm_isp.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -164,6 +164,9 @@ struct msm_vfe_irq_ops { void (*config_irq)(struct vfe_device *vfe_dev, uint32_t irq_status0, uint32_t irq_status1, enum msm_isp_irq_operation); + void (*process_sof_irq)(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts); void (*process_eof_irq)(struct vfe_device *vfe_dev, uint32_t irq_status0); }; diff --git a/drivers/media/platform/msm/ais/isp/msm_isp47.c b/drivers/media/platform/msm/ais/isp/msm_isp47.c index 1215713ea8c2..9cd367925314 100644 --- a/drivers/media/platform/msm/ais/isp/msm_isp47.c +++ b/drivers/media/platform/msm/ais/isp/msm_isp47.c @@ -593,7 +593,6 @@ void msm_vfe47_process_reg_update(struct vfe_device *vfe_dev, case VFE_RAW_1: case VFE_RAW_2: msm_isp_increment_frame_id(vfe_dev, i, ts); - msm_isp_notify(vfe_dev, ISP_EVENT_SOF, i, ts); msm_isp_update_framedrop_reg(vfe_dev, i); /* * Reg Update is pseudo SOF for RDI, @@ -641,7 +640,6 @@ void msm_vfe47_process_epoch_irq(struct vfe_device *vfe_dev, msm_isp_update_framedrop_reg(vfe_dev, VFE_PIX_0); msm_isp_update_stats_framedrop_reg(vfe_dev); msm_isp_update_error_frame_count(vfe_dev); - msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts); if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0 && vfe_dev->axi_data.src_info[VFE_PIX_0]. pix_stream_count == 0) { @@ -653,6 +651,23 @@ void msm_vfe47_process_epoch_irq(struct vfe_device *vfe_dev, } } +void msm_isp47_process_sof_irq(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts) +{ + if ((!(irq_status0 & 0x1)) && (!(irq_status1 & 0xE0000000))) + return; + + if (irq_status0 & BIT(0)) + msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts); + if (irq_status1 & BIT(29)) + msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_RAW_0, ts); + if (irq_status1 & BIT(30)) + msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_RAW_1, ts); + if (irq_status1 & BIT(31)) + msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_RAW_2, ts); +} + void msm_isp47_process_eof_irq(struct vfe_device *vfe_dev, uint32_t irq_status0) { @@ -2709,6 +2724,7 @@ struct msm_vfe_hardware_info vfe47_hw_info = { .process_stats_irq = msm_isp_process_stats_irq, .process_epoch_irq = msm_vfe47_process_epoch_irq, .config_irq = msm_vfe47_config_irq, + .process_sof_irq = msm_isp47_process_sof_irq, .process_eof_irq = msm_isp47_process_eof_irq, }, .axi_ops = { diff --git a/drivers/media/platform/msm/ais/isp/msm_isp47.h b/drivers/media/platform/msm/ais/isp/msm_isp47.h index 9af0acd3656a..33a2c5a638c9 100644 --- a/drivers/media/platform/msm/ais/isp/msm_isp47.h +++ b/drivers/media/platform/msm/ais/isp/msm_isp47.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -44,6 +44,9 @@ void msm_vfe47_process_reg_update(struct vfe_device *vfe_dev, void msm_vfe47_process_epoch_irq(struct vfe_device *vfe_dev, uint32_t irq_status0, uint32_t irq_status1, struct msm_isp_timestamp *ts); +void msm_isp47_process_sof_irq(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts); void msm_isp47_process_eof_irq(struct vfe_device *vfe_dev, uint32_t irq_status0); void msm_vfe47_reg_update(struct vfe_device *vfe_dev, diff --git a/drivers/media/platform/msm/ais/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/ais/isp/msm_isp_axi_util.c index c0a36843d7ff..aa31795fafcf 100644 --- a/drivers/media/platform/msm/ais/isp/msm_isp_axi_util.c +++ b/drivers/media/platform/msm/ais/isp/msm_isp_axi_util.c @@ -951,6 +951,8 @@ void msm_isp_notify(struct vfe_device *vfe_dev, uint32_t event_type, enum msm_vfe_dual_hw_ms_type ms_type; int i, j; unsigned long flags; + struct msm_vfe_axi_stream *stream_info = + &vfe_dev->axi_data.stream_info[INTF_TO_SRC(frame_src)]; memset(&event_data, 0, sizeof(event_data)); @@ -1041,7 +1043,11 @@ void msm_isp_notify(struct vfe_device *vfe_dev, uint32_t event_type, break; } - event_data.frame_id = vfe_dev->axi_data.src_info[frame_src].frame_id; + if (event_type == ISP_EVENT_SOF) + event_data.frame_id = stream_info->frame_id + 1; + else + event_data.frame_id = + vfe_dev->axi_data.src_info[frame_src].frame_id; event_data.timestamp = ts->event_time; event_data.mono_timestamp = ts->buf_time; msm_isp_send_event(vfe_dev, event_type | frame_src, &event_data); @@ -4080,7 +4086,7 @@ void msm_isp_process_axi_irq_stream(struct vfe_device *vfe_dev, } msm_isp_process_done_buf(vfe_dev, stream_info, - done_buf, time_stamp, frame_id); + done_buf, time_stamp, stream_info->frame_id); } void msm_isp_process_axi_irq(struct vfe_device *vfe_dev, diff --git a/drivers/media/platform/msm/ais/isp/msm_isp_axi_util.h b/drivers/media/platform/msm/ais/isp/msm_isp_axi_util.h index 5ed89161b7f3..02adf7a3eddd 100644 --- a/drivers/media/platform/msm/ais/isp/msm_isp_axi_util.h +++ b/drivers/media/platform/msm/ais/isp/msm_isp_axi_util.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -19,6 +19,10 @@ #define SRC_TO_INTF(src) \ ((src < RDI_INTF_0 || src == VFE_AXI_SRC_MAX) ? VFE_PIX_0 : \ (VFE_RAW_0 + src - RDI_INTF_0)) +/* automotive has 1vs1 mapping currently */ +#define INTF_TO_SRC(intf) \ + ((intf == VFE_PIX_0 || intf == VFE_SRC_MAX) ? CAMIF_RAW : \ + (RDI_INTF_0 + intf - VFE_RAW_0)) int msm_isp_axi_create_stream(struct vfe_device *vfe_dev, struct msm_vfe_axi_shared_data *axi_data, diff --git a/drivers/media/platform/msm/ais/isp/msm_isp_util.c b/drivers/media/platform/msm/ais/isp/msm_isp_util.c index 0f749ec03132..8f5a2f72da0c 100644 --- a/drivers/media/platform/msm/ais/isp/msm_isp_util.c +++ b/drivers/media/platform/msm/ais/isp/msm_isp_util.c @@ -2153,6 +2153,8 @@ void msm_isp_do_tasklet(unsigned long data) irq_ops->process_stats_irq(vfe_dev, irq_status0, irq_status1, pingpong_status, &ts); + irq_ops->process_sof_irq(vfe_dev, + irq_status0, irq_status1, &ts); irq_ops->process_axi_irq(vfe_dev, irq_status0, irq_status1, pingpong_status, &ts); diff --git a/drivers/video/msm/ba/msm_ba.c b/drivers/video/msm/ba/msm_ba.c index 566cb634ae8f..95edb5bd48a9 100644 --- a/drivers/video/msm/ba/msm_ba.c +++ b/drivers/video/msm/ba/msm_ba.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -574,6 +574,24 @@ long msm_ba_private_ioctl(void *instance, int cmd, void *arg) } } break; + case VIDIOC_G_FIELD_INFO: { + dprintk(BA_DBG, "VIDIOC_G_FIELD_INFO"); + sd = inst->sd; + if (!sd) { + dprintk(BA_ERR, "No sd registered"); + return -EINVAL; + } + if (arg) { + rc = v4l2_subdev_call(sd, core, ioctl, cmd, arg); + if (rc) + dprintk(BA_ERR, "%s failed: %ld on cmd: 0x%x", + __func__, rc, cmd); + } else { + dprintk(BA_ERR, "%s: NULL argument provided", __func__); + rc = -EINVAL; + } + } + break; default: dprintk(BA_WARN, "Not a typewriter! Command: 0x%x", cmd); rc = -ENOTTY; diff --git a/include/uapi/media/msm_ba.h b/include/uapi/media/msm_ba.h index 587d14652f3f..933dd85bb48b 100644 --- a/include/uapi/media/msm_ba.h +++ b/include/uapi/media/msm_ba.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -23,6 +23,12 @@ struct csi_ctrl_params { uint32_t lane_count; }; +/* Field info params */ +struct field_info_params { + bool even_field; + struct timeval field_ts; +}; + /* private ioctl structure */ struct msm_ba_v4l2_ioctl_t { size_t len; @@ -32,4 +38,8 @@ struct msm_ba_v4l2_ioctl_t { /* ADV7481 private ioctls for CSI control params */ #define VIDIOC_G_CSI_PARAMS \ _IOWR('V', BASE_VIDIOC_PRIVATE, struct msm_ba_v4l2_ioctl_t) +/* ADV7481 private ioctls for field info query */ +#define VIDIOC_G_FIELD_INFO \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 40, struct msm_ba_v4l2_ioctl_t) + #endif