msm: camera: Add support for ISP statistics collection

Add suppport to configure statistics modules
Add support for statistics buffer handling
Handle statistics module interrupt and generate event
to notify userspace.

Change-Id: I58f610f9509d259dcae7cb55e35ce7e3c4ab03d4
Signed-off-by: Kevin Chan <ktchan@codeaurora.org>
[smuckle@codeaurora.org: backported from msm-3.7]
Signed-off-by: Steve Muckle <smuckle@codeaurora.org>
This commit is contained in:
Kevin Chan
2013-02-14 10:49:39 -08:00
committed by Jay Chokshi
parent ee9eb7ef2d
commit 3454e2b2ea
7 changed files with 445 additions and 276 deletions
@@ -34,6 +34,9 @@
#define MAX_INIT_FRAME_DROP 31
#define ISP_SUB(a) ((a > 0) ? a-1 : 0)
#define VFE_PING_FLAG 0xFFFFFFFF
#define VFE_PONG_FLAG 0x0
struct vfe_device;
struct msm_vfe_axi_stream;
struct msm_vfe_stats_stream;
@@ -133,14 +136,12 @@ struct msm_vfe_core_ops {
int (*get_platform_data) (struct vfe_device *vfe_dev);
};
struct msm_vfe_stats_ops {
int (*get_stats_idx) (enum msm_isp_stats_type stats_type);
void (*cfg_framedrop) (struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info);
void (*clear_framedrop) (struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info);
void (*cfg_comp_mask) (struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info);
void (*clear_comp_mask) (struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info);
void (*cfg_comp_mask) (struct vfe_device *vfe_dev);
void (*cfg_wm_irq_mask) (struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info);
void (*clear_wm_irq_mask) (struct vfe_device *vfe_dev,
@@ -153,20 +154,17 @@ struct msm_vfe_stats_ops {
void (*cfg_ub) (struct vfe_device *vfe_dev);
void (*stats_enable) (struct vfe_device *vfe_dev,
void (*enable_module) (struct vfe_device *vfe_dev,
uint32_t stats_mask, uint8_t enable);
void (*update_ping_pong_addr) (struct vfe_device *vfe_dev,
enum msm_isp_stats_type stats_type, uint32_t pingpong_status,
unsigned long paddr);
struct msm_vfe_stats_stream *stream_info,
uint32_t pingpong_status, unsigned long paddr);
uint32_t (*get_frame_id) (struct vfe_device *vfe_dev);
uint32_t (*get_wm_mask) (uint32_t irq_status0, uint32_t irq_status1);
uint32_t (*get_comp_mask) (uint32_t irq_status0, uint32_t irq_status1);
uint32_t (*get_pingpong_status) (struct vfe_device *vfe_dev);
uint32_t (*get_active_pingpong_idx) (uint32_t pingpong_status,
enum msm_isp_stats_type stats_type);
};
struct msm_vfe_ops {
@@ -179,6 +177,7 @@ struct msm_vfe_ops {
struct msm_vfe_hardware_info {
struct msm_vfe_ops vfe_ops;
struct msm_vfe_axi_hardware_info *axi_hw_info;
struct msm_vfe_stats_hardware_info *stats_hw_info;
struct v4l2_subdev_internal_ops *subdev_internal_ops;
struct v4l2_subdev_ops *subdev_ops;
};
@@ -189,7 +188,6 @@ struct msm_vfe_axi_hardware_info {
uint8_t num_rdi_master;
uint8_t num_comp_mask;
uint32_t min_wm_ub;
uint8_t num_stats_comp_mask;
};
enum msm_vfe_axi_state {
@@ -243,6 +241,7 @@ struct msm_vfe_axi_composite_info {
uint32_t stream_handle;
uint32_t stream_composite_mask;
};
struct msm_vfe_src_info {
unsigned long frame_id;
uint8_t active;
@@ -251,40 +250,12 @@ struct msm_vfe_src_info {
enum msm_vfe_inputmux input_mux;
};
enum msm_vfe_stats_state {
STATE_AVALIABLE,
STATE_INACTIVE,
STATE_ACTIVE,
STATE_START_PENDING,
STATE_STOP_PENDING,
STATE_STOPPING,
};
struct msm_vfe_stats_stream {
uint32_t frame_id;
uint8_t enable;
enum msm_isp_stats_type stats_type;
int8_t comp_mask_index;
struct msm_isp_buffer *buf[2];
uint32_t session_id;
uint32_t stream_id;
uint32_t bufq_handle;
uint32_t stream_handle;
uint32_t framedrop_pattern;
uint8_t comp_flag;
uint8_t comp_idx;
enum msm_vfe_stats_state state;
};
struct msm_vfe_stats_composite_info {
uint32_t stats_mask;
uint8_t comp_flag;
};
enum msm_wm_ub_cfg_type {
MSM_WM_UB_CFG_DEFAULT,
MSM_WM_UB_EQUAL_SLICING,
MSM_WM_UB_CFG_MAX_NUM
};
struct msm_vfe_axi_shared_data {
struct msm_vfe_axi_hardware_info *hw_info;
struct msm_vfe_axi_stream stream_info[MAX_NUM_STREAM];
@@ -305,14 +276,44 @@ struct msm_vfe_axi_shared_data {
unsigned long event_mask;
};
struct msm_vfe_stats_hardware_info {
uint32_t stats_capability_mask;
uint32_t stats_ping_pong_offset;
uint8_t num_stats_type;
uint8_t num_stats_comp_mask;
};
enum msm_vfe_stats_state {
STATS_AVALIABLE,
STATS_INACTIVE,
STATS_ACTIVE,
STATS_START_PENDING,
STATS_STOP_PENDING,
STATS_STOPPING,
};
struct msm_vfe_stats_stream {
uint32_t session_id;
uint32_t stream_id;
uint32_t stream_handle;
enum msm_isp_stats_type stats_type;
enum msm_vfe_stats_state state;
uint32_t framedrop_pattern;
uint32_t irq_subsample_pattern;
struct msm_isp_buffer *buf[2];
uint32_t bufq_handle;
};
struct msm_vfe_stats_shared_data {
struct msm_vfe_stats_stream stream_info[MSM_ISP_STATS_MAX];
struct msm_vfe_stats_composite_info
composite_info[MAX_NUM_STATS_COMP_MASK];
enum msm_vfe_stats_pipeline_policy stats_pipeline_policy;
uint32_t comp_framedrop_pattern;
uint32_t comp_irq_subsample_pattern;
uint8_t num_active_stream;
uint8_t num_used_composite_mask;
uint16_t stream_handle_cnt;
};
struct msm_vfe_tasklet_queue_cmd {
struct list_head list;
uint32_t vfeInterruptStatus0;
@@ -30,6 +30,7 @@
#endif
#define VFE40_BURST_LEN 4
#define VFE40_UB_SIZE 1024
#define VFE40_EQUAL_SLICE_UB 117
#define VFE40_WM_BASE(idx) (0x6C + 0x24 * idx)
#define VFE40_RDI_BASE(idx) (0x2E8 + 0x4 * idx)
@@ -41,6 +42,13 @@
#define VFE40_PING_PONG_BASE(wm, ping_pong) \
(VFE40_WM_BASE(wm) + 0x4 * (1 + (~(ping_pong >> wm) & 0x1)))
#define VFE40_NUM_STATS_TYPE 8
#define VFE40_STATS_PING_PONG_OFFSET 8
#define VFE40_STATS_BASE(idx) (0x168 + 0x18 * idx)
#define VFE40_STATS_PING_PONG_BASE(idx, ping_pong) \
(VFE40_STATS_BASE(idx) + 0x4 * \
(~(ping_pong >> (idx + VFE40_STATS_PING_PONG_OFFSET)) & 0x1))
#define VFE40_VBIF_CLKON 0x4
#define VFE40_VBIF_IN_RD_LIM_CONF0 0xB0
#define VFE40_VBIF_IN_RD_LIM_CONF1 0xB4
@@ -907,64 +915,160 @@ static uint32_t msm_vfe40_get_pingpong_status(
return msm_camera_io_r(vfe_dev->vfe_base + 0x268);
}
static void msm_vfe40_stats_cfg_comp_mask(
struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info)
static int msm_vfe40_get_stats_idx(enum msm_isp_stats_type stats_type)
{
switch (stats_type) {
case MSM_ISP_STATS_BE:
return 0;
case MSM_ISP_STATS_BG:
return 1;
case MSM_ISP_STATS_BF:
return 2;
case MSM_ISP_STATS_AWB:
return 3;
case MSM_ISP_STATS_RS:
return 4;
case MSM_ISP_STATS_CS:
return 5;
case MSM_ISP_STATS_IHIST:
return 6;
case MSM_ISP_STATS_BHIST:
return 7;
default:
pr_err("%s: Invalid stats type\n", __func__);
return -EINVAL;
}
}
static void msm_vfe40_stats_clear_comp_mask(
struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info)
static void msm_vfe40_stats_cfg_comp_mask(struct vfe_device *vfe_dev)
{
if (vfe_dev->stats_data.stats_pipeline_policy == STATS_COMP_ALL)
msm_camera_io_w(0x00FF0000, vfe_dev->vfe_base + 0x44);
else
msm_camera_io_w(0x00000000, vfe_dev->vfe_base + 0x44);
}
static void msm_vfe40_stats_cfg_wm_irq_mask(
struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info)
{
uint32_t irq_mask;
irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28);
irq_mask |= 1 << (STATS_IDX(stream_info->stream_handle) + 16);
msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28);
}
static void msm_vfe40_stats_clear_wm_irq_mask(
struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info)
{
uint32_t irq_mask;
irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28);
irq_mask &= ~(1 << (STATS_IDX(stream_info->stream_handle) + 16));
msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28);
}
static void msm_vfe40_stats_cfg_wm_reg(
struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info)
{
int stats_idx = STATS_IDX(stream_info->stream_handle);
uint32_t stats_base = VFE40_STATS_BASE(stats_idx);
/*WR_ADDR_CFG*/
msm_camera_io_w(0x7C, vfe_dev->vfe_base + stats_base + 0x8);
/*WR_IRQ_FRAMEDROP_PATTERN*/
msm_camera_io_w(0xFFFFFFFF,
vfe_dev->vfe_base + stats_base + 0x10);
/*WR_IRQ_SUBSAMPLE_PATTERN*/
msm_camera_io_w(0xFFFFFFFF,
vfe_dev->vfe_base + stats_base + 0x14);
}
static void msm_vfe40_stats_clear_wm_reg(
struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info)
{
uint32_t val = 0;
int stats_idx = STATS_IDX(stream_info->stream_handle);
uint32_t stats_base = VFE40_STATS_BASE(stats_idx);
/*WR_ADDR_CFG*/
msm_camera_io_w(val, vfe_dev->vfe_base + stats_base + 0x8);
/*WR_IRQ_FRAMEDROP_PATTERN*/
msm_camera_io_w(val, vfe_dev->vfe_base + stats_base + 0x10);
/*WR_IRQ_SUBSAMPLE_PATTERN*/
msm_camera_io_w(val, vfe_dev->vfe_base + stats_base + 0x14);
}
static void msm_vfe40_stats_cfg_ub(struct vfe_device *vfe_dev)
{
int i;
uint32_t ub_offset = VFE40_UB_SIZE;
uint32_t ub_size[VFE40_NUM_STATS_TYPE] = {
64, /*MSM_ISP_STATS_BE*/
64, /*MSM_ISP_STATS_BG*/
64, /*MSM_ISP_STATS_BF*/
16, /*MSM_ISP_STATS_AWB*/
8, /*MSM_ISP_STATS_RS*/
16, /*MSM_ISP_STATS_CS*/
16, /*MSM_ISP_STATS_IHIST*/
16, /*MSM_ISP_STATS_BHIST*/
};
for (i = 0; i < VFE40_NUM_STATS_TYPE; i++) {
ub_offset -= ub_size[i];
msm_camera_io_w(VFE40_BURST_LEN << 30 |
ub_offset << 16 | (ub_size[i] - 1),
vfe_dev->vfe_base + VFE40_STATS_BASE(i) + 0xC);
}
}
static void msm_vfe40_stats_enable(struct vfe_device *vfe_dev,
static void msm_vfe40_stats_enable_module(struct vfe_device *vfe_dev,
uint32_t stats_mask, uint8_t enable)
{
int i;
uint32_t module_cfg, module_cfg_mask = 0;
for (i = 0; i < VFE40_NUM_STATS_TYPE; i++) {
if ((stats_mask >> i) & 0x1) {
switch (i) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
module_cfg_mask |= 1 << (5 + i);
break;
case 6:
module_cfg_mask |= 1 << 15;
break;
case 7:
module_cfg_mask |= 1 << 18;
break;
default:
pr_err("%s: Invalid stats mask\n", __func__);
return;
}
}
}
module_cfg = msm_camera_io_r(vfe_dev->vfe_base + 0x18);
if (enable)
module_cfg |= module_cfg_mask;
else
module_cfg &= ~module_cfg_mask;
msm_camera_io_w(module_cfg, vfe_dev->vfe_base + 0x18);
}
static void msm_vfe40_stats_update_ping_pong_addr(
struct vfe_device *vfe_dev,
enum msm_isp_stats_type stats_type,
uint32_t pingpong_status,
unsigned long paddr)
struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info,
uint32_t pingpong_status, unsigned long paddr)
{
int stats_idx = STATS_IDX(stream_info->stream_handle);
msm_camera_io_w(paddr, vfe_dev->vfe_base +
VFE40_STATS_PING_PONG_BASE(stats_idx, pingpong_status));
}
static uint32_t msm_vfe40_stats_get_wm_mask(
@@ -976,7 +1080,7 @@ static uint32_t msm_vfe40_stats_get_wm_mask(
static uint32_t msm_vfe40_stats_get_comp_mask(
uint32_t irq_status0, uint32_t irq_status1)
{
return (irq_status0 >> 29) & 0x2;
return (irq_status0 >> 29) & 0x3;
}
static uint32_t msm_vfe40_stats_get_frame_id(
@@ -985,55 +1089,6 @@ static uint32_t msm_vfe40_stats_get_frame_id(
return vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
}
static uint32_t msm_vfe40_stats_get_active_pingpong_idx(
uint32_t pingpong_status,
enum msm_isp_stats_type stats_type)
{
int pingpong_bit = 0;
switch (stats_type) {
case MSM_ISP_STATS_AWB:
if (pingpong_status & (1 << 11))
pingpong_bit = 1; /* pong is active */
break;
case MSM_ISP_STATS_RS:
if (pingpong_status & (1 << 12))
pingpong_bit = 1; /* pong is active */
break;
case MSM_ISP_STATS_CS:
if (pingpong_status & (1 << 13))
pingpong_bit = 1; /* pong is active */
break;
case MSM_ISP_STATS_IHIST:
if (pingpong_status & (1 << 14))
pingpong_bit = 1; /* pong is active */
break;
case MSM_ISP_STATS_BG:
if (pingpong_status & (1 << 9))
pingpong_bit = 1; /* pong is active */
break;
case MSM_ISP_STATS_BF:
if (pingpong_status & (1 << 10))
pingpong_bit = 1; /* pong is active */
break;
case MSM_ISP_STATS_BE:
if (pingpong_status & (1 << 8))
pingpong_bit = 1; /* pong is active */
break;
case MSM_ISP_STATS_BHIST:
if (pingpong_status & (1 << 15))
pingpong_bit = 1; /* pong is active */
break;
case MSM_ISP_STATS_SKIN:
case MSM_ISP_STATS_AEC:
case MSM_ISP_STATS_AF:
default:
pr_err("%s: not supported stats type = %d\n",
__func__, stats_type);
return -EINVAL;
}
return pingpong_bit;
}
static int msm_vfe40_get_platform_data(struct vfe_device *vfe_dev)
{
int rc = 0;
@@ -1085,12 +1140,22 @@ vfe_no_resource:
return rc;
}
struct msm_vfe_axi_hardware_info msm_vfe40_axi_hw_info = {
static struct msm_vfe_axi_hardware_info msm_vfe40_axi_hw_info = {
.num_wm = 7,
.num_comp_mask = 4,
.num_rdi = 3,
.num_rdi_master = 3,
.min_wm_ub = 64,
};
static struct msm_vfe_stats_hardware_info msm_vfe40_stats_hw_info = {
.stats_capability_mask =
1 << MSM_ISP_STATS_BE | 1 << MSM_ISP_STATS_BF |
1 << MSM_ISP_STATS_BG | 1 << MSM_ISP_STATS_BHIST |
1 << MSM_ISP_STATS_AWB | 1 << MSM_ISP_STATS_IHIST |
1 << MSM_ISP_STATS_RS | 1 << MSM_ISP_STATS_CS,
.stats_ping_pong_offset = VFE40_STATS_PING_PONG_OFFSET,
.num_stats_type = VFE40_NUM_STATS_TYPE,
.num_stats_comp_mask = 2,
};
@@ -1156,25 +1221,24 @@ struct msm_vfe_hardware_info vfe40_hw_info = {
.get_platform_data = msm_vfe40_get_platform_data,
},
.stats_ops = {
.get_stats_idx = msm_vfe40_get_stats_idx,
.cfg_comp_mask = msm_vfe40_stats_cfg_comp_mask,
.clear_comp_mask = msm_vfe40_stats_clear_comp_mask,
.cfg_wm_irq_mask = msm_vfe40_stats_cfg_wm_irq_mask,
.clear_wm_irq_mask = msm_vfe40_stats_clear_wm_irq_mask,
.cfg_wm_reg = msm_vfe40_stats_cfg_wm_reg,
.clear_wm_reg = msm_vfe40_stats_clear_wm_reg,
.cfg_ub = msm_vfe40_stats_cfg_ub,
.stats_enable = msm_vfe40_stats_enable,
.enable_module = msm_vfe40_stats_enable_module,
.update_ping_pong_addr =
msm_vfe40_stats_update_ping_pong_addr,
.get_comp_mask = msm_vfe40_stats_get_comp_mask,
.get_wm_mask = msm_vfe40_stats_get_wm_mask,
.get_frame_id = msm_vfe40_stats_get_frame_id,
.get_pingpong_status = msm_vfe40_get_pingpong_status,
.get_active_pingpong_idx =
msm_vfe40_stats_get_active_pingpong_idx,
},
},
.axi_hw_info = &msm_vfe40_axi_hw_info,
.stats_hw_info = &msm_vfe40_stats_hw_info,
.subdev_ops = &msm_vfe40_subdev_ops,
.subdev_internal_ops = &msm_vfe40_internal_ops,
};
@@ -644,8 +644,6 @@ void msm_isp_axi_stream_update(struct vfe_device *vfe_dev)
complete(&vfe_dev->stream_config_complete);
}
}
#define VFE_PING_FLAG 0xFFFFFFFF
#define VFE_PONG_FLAG 0x0
int msm_isp_cfg_ping_pong_address(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status,
@@ -13,251 +13,331 @@
#include <media/v4l2-subdev.h>
#include "msm_isp_util.h"
#include "msm_isp_stats_util.h"
#define VFE_PING_ACTIVE_FLAG 0xFFFFFFFF
#define VFE_PONG_ACTIVE_FLAG 0x0
int msm_isp_stats_cfg_ping_pong_address(struct vfe_device *vfe_dev,
static int msm_isp_stats_cfg_ping_pong_address(struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info, uint32_t pingpong_status,
struct msm_isp_buffer *out_buf)
struct msm_isp_buffer **done_buf)
{
int rc = -1;
struct msm_isp_buffer *buf;
int active_bit = 0;
int buf_idx;
uint32_t pingpong_bit = 0;
uint32_t bufq_handle = stream_info->bufq_handle;
uint32_t stats_pingpong_offset =
STATS_IDX(stream_info->stream_handle) +
vfe_dev->hw_info->stats_hw_info->stats_ping_pong_offset;
out_buf = NULL;
active_bit = vfe_dev->hw_info->vfe_ops.stats_ops.
get_active_pingpong_idx(pingpong_status,
stream_info->stats_type);
buf_idx = active_bit^0x1;
pingpong_bit = (~(pingpong_status >> stats_pingpong_offset) & 0x1);
rc = vfe_dev->buf_mgr->ops->get_buf(
vfe_dev->buf_mgr, bufq_handle, &buf);
if (rc < 0) {
pr_err("%s: No free buffer, stats_type = %d\n",
__func__, stream_info->stats_type);
pr_err("%s: No free buffer, stats_stream = %d\n",
__func__, stream_info->stream_handle);
return rc;
}
vfe_dev->hw_info->vfe_ops.stats_ops.update_ping_pong_addr(
vfe_dev, stream_info->stats_type,
pingpong_status, buf->mapped_info[buf_idx].paddr);
if (stream_info->buf[buf_idx])
out_buf = stream_info->buf[buf_idx];
stream_info->buf[buf_idx] = buf;
if (buf->num_planes != 1) {
pr_err("%s: Invalid buffer\n", __func__);
rc = -EINVAL;
goto buf_error;
}
vfe_dev->hw_info->vfe_ops.stats_ops.update_ping_pong_addr(
vfe_dev, stream_info,
pingpong_status, buf->mapped_info[0].paddr);
if (stream_info->buf[pingpong_bit] && done_buf)
*done_buf = stream_info->buf[pingpong_bit];
stream_info->buf[pingpong_bit] = buf;
return 0;
buf_error:
vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr,
buf->bufq_handle, buf->buf_idx);
return rc;
}
void msm_isp_process_stats_irq(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
struct timeval *tv)
{
uint32_t frame_id;
uint32_t stats_comp_mask = 0, stats_mask = 0;
ISP_DBG("%s: status: 0x%x\n", __func__, irq_status0);
int i;
struct msm_isp_event_data buf_event;
struct msm_isp_stats_event *stats_event = &buf_event.u.stats;
struct msm_isp_buffer *done_buf;
struct msm_vfe_stats_stream *stream_info = NULL;
uint32_t pingpong_status;
uint32_t stats_comp_mask = 0, stats_irq_mask = 0;
stats_comp_mask = vfe_dev->hw_info->vfe_ops.stats_ops.
get_comp_mask(irq_status0, irq_status1);
stats_mask = vfe_dev->hw_info->vfe_ops.stats_ops.
stats_irq_mask = vfe_dev->hw_info->vfe_ops.stats_ops.
get_wm_mask(irq_status0, irq_status1);
if (!(stats_comp_mask || stats_mask))
if (!(stats_comp_mask || stats_irq_mask))
return;
frame_id = vfe_dev->hw_info->vfe_ops.stats_ops.get_frame_id(vfe_dev);
/* TD: process comp/non comp stats */
}
ISP_DBG("%s: status: 0x%x\n", __func__, irq_status0);
static int msm_isp_stats_reserve_comp_mask(
struct vfe_device *vfe_dev,
struct msm_vfe_stats_shared_data *stats_data,
struct msm_vfe_stats_stream *stream_info)
{
int i;
uint8_t num_stats_comp;
int8_t comp_idx = -1;
if (stream_info->comp_flag == 0)
return 0;
if (vfe_dev->stats_data.stats_pipeline_policy == STATS_COMP_ALL) {
if (!stats_comp_mask)
return;
stats_irq_mask = 0xFFFFFFFF;
}
num_stats_comp = vfe_dev->axi_data.hw_info->num_stats_comp_mask;
for (i = 0; i < num_stats_comp; i++) {
if (!stats_data->composite_info[i].stats_mask == 0 &&
comp_idx < 0)
comp_idx = i;
if (stats_data->composite_info[i].comp_flag ==
stream_info->comp_flag) {
comp_idx = i;
break;
memset(&buf_event, 0, sizeof(struct msm_isp_event_data));
pingpong_status = vfe_dev->hw_info->
vfe_ops.stats_ops.get_pingpong_status(vfe_dev);
for (i = 0; i < vfe_dev->hw_info->stats_hw_info->num_stats_type; i++) {
if (!(stats_irq_mask & (1 << i)))
continue;
stream_info = &vfe_dev->stats_data.stream_info[i];
done_buf = NULL;
msm_isp_stats_cfg_ping_pong_address(vfe_dev,
stream_info, pingpong_status, &done_buf);
if (done_buf) {
stats_event->stats_mask |= 1 << stream_info->stats_type;
stats_event->stats_buf_idxs[stream_info->stats_type] =
done_buf->buf_idx;
}
}
if (comp_idx < 0) {
pr_err("%s: no more stats comp idx\n", __func__);
return -EACCES;
}
stats_data->composite_info[comp_idx].stats_mask |=
(1 << stream_info->stats_type);
if (stats_data->composite_info[comp_idx].comp_flag == 0)
stats_data->composite_info[comp_idx].comp_flag =
stream_info->comp_flag;
stream_info->comp_idx = comp_idx;
return 0;
buf_event.timestamp = *tv;
msm_isp_send_event(vfe_dev, ISP_EVENT_STATS_NOTIFY, &buf_event);
}
static int msm_isp_stats_unreserve_comp_mask(
struct vfe_device *vfe_dev,
struct msm_vfe_stats_shared_data *stats_data,
struct msm_vfe_stats_stream *stream_info)
int msm_isp_stats_create_stream(struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream_request_cmd *stream_req_cmd)
{
uint8_t comp_idx = stream_info->comp_idx;
int rc = -1;
struct msm_vfe_stats_stream *stream_info = NULL;
struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
uint32_t stats_idx;
if (stream_info->comp_flag == 0)
return 0;
stats_data->composite_info[comp_idx].stats_mask &=
~(1 << stream_info->stats_type);
if (stats_data->composite_info[comp_idx].stats_mask == 0)
memset(&stats_data->composite_info[comp_idx], 0,
sizeof(struct msm_vfe_stats_composite_info));
if (!(vfe_dev->hw_info->stats_hw_info->stats_capability_mask &
(1 << stream_req_cmd->stats_type))) {
pr_err("%s: Stats type not supported\n", __func__);
return rc;
}
stats_idx = vfe_dev->hw_info->vfe_ops.stats_ops.
get_stats_idx(stream_req_cmd->stats_type);
stream_info = &stats_data->stream_info[stats_idx];
if (stream_info->state != STATS_AVALIABLE) {
pr_err("%s: Stats already requested\n", __func__);
return rc;
}
if (stats_data->stats_pipeline_policy != STATS_COMP_ALL) {
if (stream_req_cmd->framedrop_pattern >= MAX_SKIP) {
pr_err("%s: Invalid framedrop pattern\n", __func__);
return rc;
}
if (stream_req_cmd->irq_subsample_pattern >= MAX_SKIP) {
pr_err("%s: Invalid irq subsample pattern\n", __func__);
return rc;
}
} else {
if (stats_data->comp_framedrop_pattern >= MAX_SKIP) {
pr_err("%s: Invalid comp framedrop pattern\n",
__func__);
return rc;
}
if (stats_data->comp_irq_subsample_pattern >= MAX_SKIP) {
pr_err("%s: Invalid comp irq subsample pattern\n",
__func__);
return rc;
}
stream_req_cmd->framedrop_pattern =
vfe_dev->stats_data.comp_framedrop_pattern;
stream_req_cmd->irq_subsample_pattern =
vfe_dev->stats_data.comp_irq_subsample_pattern;
}
stream_info->session_id = stream_req_cmd->session_id;
stream_info->stream_id = stream_req_cmd->stream_id;
stream_info->stats_type = stream_req_cmd->stats_type;
stream_info->framedrop_pattern = stream_req_cmd->framedrop_pattern;
stream_info->irq_subsample_pattern =
stream_req_cmd->irq_subsample_pattern;
stream_info->state = STATS_INACTIVE;
if ((vfe_dev->stats_data.stream_handle_cnt << 8) == 0)
vfe_dev->stats_data.stream_handle_cnt++;
stream_req_cmd->stream_handle =
(++vfe_dev->stats_data.stream_handle_cnt) << 8 | stats_idx;
stream_info->stream_handle = stream_req_cmd->stream_handle;
return 0;
}
int msm_isp_request_stats_stream(struct vfe_device *vfe_dev, void *arg)
{
int rc = 0;
struct msm_vfe_stats_stream_request_cmd *stream_cfg_cmd = arg;
struct msm_vfe_stats_stream_request_cmd *stream_req_cmd = arg;
struct msm_vfe_stats_stream *stream_info = NULL;
struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
uint32_t stats_idx;
if (stream_cfg_cmd->stats_type < MSM_ISP_STATS_AEC ||
stream_cfg_cmd->stats_type >= MSM_ISP_STATS_MAX) {
pr_err("%s: invalid stats type %d received\n",
__func__, stream_cfg_cmd->stats_type);
return -EINVAL;
}
stream_info = &stats_data->stream_info[stream_cfg_cmd->stats_type];
if (stream_info->stream_handle != 0) {
pr_err("%s: stats type %d has been used already\n",
__func__, stream_cfg_cmd->stats_type);
return -EBUSY;
rc = msm_isp_stats_create_stream(vfe_dev, stream_req_cmd);
if (rc < 0) {
pr_err("%s: create stream failed\n", __func__);
return rc;
}
stats_data->stream_handle_cnt++;
if (stats_data->stream_handle_cnt == 0)
stats_data->stream_handle_cnt++;
stream_info->stream_handle =
stats_data->stream_handle_cnt << 16 |
stream_cfg_cmd->stats_type;
stream_info->enable = 0;
stream_info->stats_type = stream_cfg_cmd->stats_type;
stream_info->comp_flag = stream_cfg_cmd->comp_flag;
stream_info->session_id = stream_cfg_cmd->session_id;
stream_info->stream_id = stream_cfg_cmd->stream_id;
stream_info->framedrop_pattern = stream_cfg_cmd->framedrop_pattern;
stream_cfg_cmd->stream_handle = stream_info->stream_handle;
msm_isp_stats_reserve_comp_mask(vfe_dev, stats_data, stream_info);
if (stream_info->comp_flag)
vfe_dev->hw_info->vfe_ops.stats_ops.
cfg_comp_mask(vfe_dev, stream_info);
else
stats_idx = STATS_IDX(stream_req_cmd->stream_handle);
stream_info = &stats_data->stream_info[stats_idx];
switch (stream_info->framedrop_pattern) {
case NO_SKIP:
stream_info->framedrop_pattern = VFE_NO_DROP;
break;
case EVERY_2FRAME:
stream_info->framedrop_pattern = VFE_DROP_EVERY_2FRAME;
break;
case EVERY_4FRAME:
stream_info->framedrop_pattern = VFE_DROP_EVERY_4FRAME;
break;
case EVERY_8FRAME:
stream_info->framedrop_pattern = VFE_DROP_EVERY_8FRAME;
break;
case EVERY_16FRAME:
stream_info->framedrop_pattern = VFE_DROP_EVERY_16FRAME;
break;
case EVERY_32FRAME:
stream_info->framedrop_pattern = VFE_DROP_EVERY_32FRAME;
break;
default:
stream_info->framedrop_pattern = VFE_NO_DROP;
break;
}
if (stats_data->stats_pipeline_policy == STATS_COMP_NONE)
vfe_dev->hw_info->vfe_ops.stats_ops.
cfg_wm_irq_mask(vfe_dev, stream_info);
vfe_dev->hw_info->vfe_ops.stats_ops.
cfg_wm_reg(vfe_dev, stream_info);
vfe_dev->hw_info->vfe_ops.stats_ops.cfg_wm_reg(vfe_dev, stream_info);
return rc;
}
int msm_isp_release_stats_stream(struct vfe_device *vfe_dev, void *arg)
{
int rc = 0;
int rc = -1;
struct msm_vfe_stats_stream_cfg_cmd stream_cfg_cmd;
struct msm_vfe_stats_stream_release_cmd *stream_release_cmd = arg;
struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
int stats_idx = STATS_IDX(stream_release_cmd->stream_handle);
struct msm_vfe_stats_stream *stream_info =
&stats_data->stream_info[
(stream_release_cmd->stream_handle & 0xFF)];
&stats_data->stream_info[stats_idx];
if (stream_info == NULL ||
stream_info->stream_handle !=
stream_release_cmd->stream_handle) {
pr_err("%s: handle mismatch(0x%x, 0x%x\n",
__func__, stream_info->stream_handle,
stream_release_cmd->stream_handle);
rc = -EINVAL;
if (stream_info->state == STATS_AVALIABLE) {
pr_err("%s: stream already release\n", __func__);
return rc;
} else if (stream_info->state != STATS_INACTIVE) {
stream_cfg_cmd.enable = 0;
stream_cfg_cmd.num_streams = 1;
stream_cfg_cmd.stream_handle[0] =
stream_release_cmd->stream_handle;
rc = msm_isp_cfg_stats_stream(vfe_dev, &stream_cfg_cmd);
}
if (stream_info->enable) {
struct msm_vfe_stats_stream_cfg_cmd stop_cmd;
memset(&stop_cmd, 0, sizeof(stop_cmd));
stop_cmd.num_streams = 1;
stop_cmd.stream_handle[0] = stream_release_cmd->stream_handle;
stop_cmd.enable = 0;
rc = msm_isp_cfg_stats_stream(vfe_dev, (void *)&stop_cmd);
if (rc < 0) {
pr_err("%s: cannot stop stats type %d\n",
__func__, stream_info->stats_type);
return -EPERM;
}
}
if (stream_info->bufq_handle) {
vfe_dev->buf_mgr->ops->release_buf(vfe_dev->buf_mgr,
stream_info->bufq_handle);
stream_info->bufq_handle = 0;
}
vfe_dev->hw_info->vfe_ops.stats_ops.
clear_wm_reg(vfe_dev, stream_info);
if (stream_info->comp_flag) {
msm_isp_stats_unreserve_comp_mask(vfe_dev,
stats_data, stream_info);
if (stats_data->stats_pipeline_policy == STATS_COMP_NONE)
vfe_dev->hw_info->vfe_ops.stats_ops.
clear_comp_mask(vfe_dev, stream_info);
} else {
vfe_dev->hw_info->vfe_ops.stats_ops.
clear_wm_irq_mask(vfe_dev, stream_info);
}
vfe_dev->hw_info->vfe_ops.stats_ops.
clear_framedrop(vfe_dev, stream_info);
clear_wm_irq_mask(vfe_dev, stream_info);
vfe_dev->hw_info->vfe_ops.stats_ops.clear_wm_reg(vfe_dev, stream_info);
memset(stream_info, 0, sizeof(struct msm_vfe_stats_stream));
return rc;
return 0;
}
int msm_isp_cfg_stats_stream(struct vfe_device *vfe_dev, void *arg)
{
int i, rc = 0;
uint32_t pingpong_status = 0;
struct msm_isp_buffer *buf = NULL;
struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd = arg;
struct msm_vfe_stats_stream *stream_info;
struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
int idx;
uint32_t stats_mask = 0;
uint8_t enable = stream_cfg_cmd->enable;
if (stats_data->num_active_stream == 0)
vfe_dev->hw_info->vfe_ops.stats_ops.cfg_ub(vfe_dev);
for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
idx = stream_cfg_cmd->stream_handle[i] & 0xF;
idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]);
stream_info = &stats_data->stream_info[idx];
if (stream_info->stream_handle !=
stream_cfg_cmd->stream_handle[i]) {
pr_err("%s: invalid stream handle -0x%x received\n",
pr_err("%s: Invalid stream handle: 0x%x received\n",
__func__, stream_cfg_cmd->stream_handle[i]);
continue;
}
if (enable) {
if (stream_cfg_cmd->enable) {
stream_info->bufq_handle =
vfe_dev->buf_mgr->ops->get_bufq_handle(
vfe_dev->buf_mgr, stream_info->session_id,
stream_info->stream_id);
if (stream_info->bufq_handle == 0) {
pr_err("%s: no buf configured for stats type = %d\n",
pr_err("%s: no buf configured for stream: 0x%x\n",
__func__,
stream_info->stats_type);
stream_info->stream_handle);
return -EINVAL;
}
msm_isp_stats_cfg_ping_pong_address(vfe_dev,
stream_info, VFE_PING_FLAG, NULL);
msm_isp_stats_cfg_ping_pong_address(vfe_dev,
stream_info, VFE_PONG_FLAG, NULL);
stream_info->state = STATS_START_PENDING;
stats_data->num_active_stream++;
} else {
stream_info->state = STATS_STOP_PENDING;
stats_data->num_active_stream--;
}
/* config ping address */
pingpong_status = VFE_PONG_ACTIVE_FLAG;
stats_mask |= (1 << stream_info->stats_type);
msm_isp_stats_cfg_ping_pong_address(vfe_dev,
stream_info, pingpong_status, buf);
pingpong_status = VFE_PING_ACTIVE_FLAG;
msm_isp_stats_cfg_ping_pong_address(vfe_dev,
stream_info, pingpong_status, buf);
stats_mask |= 1 << idx;
}
vfe_dev->hw_info->vfe_ops.stats_ops.
stats_enable(vfe_dev, stats_mask, enable);
enable_module(vfe_dev, stats_mask, stream_cfg_cmd->enable);
return rc;
}
int msm_isp_cfg_stats_comp_policy(struct vfe_device *vfe_dev, void *arg)
{
int rc = -1;
struct msm_vfe_stats_comp_policy_cfg *policy_cfg_cmd = arg;
struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
if (stats_data->num_active_stream != 0) {
pr_err("%s: Cannot update policy when there are active streams\n",
__func__);
return rc;
}
if (policy_cfg_cmd->stats_pipeline_policy >= MAX_STATS_POLICY) {
pr_err("%s: Invalid stats composite policy\n", __func__);
return rc;
}
if (policy_cfg_cmd->comp_framedrop_pattern >= MAX_SKIP) {
pr_err("%s: Invalid comp framedrop pattern\n", __func__);
return rc;
}
if (policy_cfg_cmd->comp_irq_subsample_pattern >= MAX_SKIP) {
pr_err("%s: Invalid comp irq subsample pattern\n", __func__);
return rc;
}
stats_data->stats_pipeline_policy =
policy_cfg_cmd->stats_pipeline_policy;
stats_data->comp_framedrop_pattern =
policy_cfg_cmd->comp_framedrop_pattern;
stats_data->comp_irq_subsample_pattern =
policy_cfg_cmd->comp_irq_subsample_pattern;
vfe_dev->hw_info->vfe_ops.stats_ops.cfg_comp_mask(vfe_dev);
return 0;
}
@@ -13,6 +13,7 @@
#define __MSM_ISP_STATS_UTIL_H__
#include "msm_isp.h"
#define STATS_IDX(idx) (idx & 0xFF)
void msm_isp_process_stats_irq(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
@@ -20,4 +21,5 @@ void msm_isp_process_stats_irq(struct vfe_device *vfe_dev,
int msm_isp_cfg_stats_stream(struct vfe_device *vfe_dev, void *arg);
int msm_isp_release_stats_stream(struct vfe_device *vfe_dev, void *arg);
int msm_isp_request_stats_stream(struct vfe_device *vfe_dev, void *arg);
int msm_isp_cfg_stats_comp_policy(struct vfe_device *vfe_dev, void *arg);
#endif /* __MSM_ISP_STATS_UTIL_H__ */
@@ -142,6 +142,9 @@ long msm_isp_ioctl(struct v4l2_subdev *sd,
case VIDIOC_MSM_ISP_CFG_STATS_STREAM:
msm_isp_cfg_stats_stream(vfe_dev, arg);
break;
case VIDIOC_MSM_ISP_CFG_STATS_COMP_POLICY:
msm_isp_cfg_stats_comp_policy(vfe_dev, arg);
break;
}
mutex_unlock(&vfe_dev->mutex);
@@ -425,6 +428,8 @@ int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
vfe_dev->buf_mgr->ops->buf_mgr_init(vfe_dev->buf_mgr, "msm_isp", 14);
memset(&vfe_dev->axi_data, 0, sizeof(struct msm_vfe_axi_shared_data));
memset(&vfe_dev->stats_data, 0,
sizeof(struct msm_vfe_stats_shared_data));
vfe_dev->axi_data.hw_info = vfe_dev->hw_info->axi_hw_info;
ISP_DBG("%s: HW Version: 0x%x\n",
+20 -1
View File
@@ -142,6 +142,12 @@ struct msm_vfe_axi_stream_cfg_cmd {
enum msm_vfe_axi_stream_cmd cmd;
};
enum msm_vfe_stats_pipeline_policy {
STATS_COMP_ALL,
STATS_COMP_NONE,
MAX_STATS_POLICY,
};
enum msm_isp_stats_type {
MSM_ISP_STATS_AEC, /* legacy based AEC */
MSM_ISP_STATS_AF, /* legacy based AF */
@@ -161,10 +167,12 @@ struct msm_vfe_stats_stream_request_cmd {
uint32_t session_id;
uint32_t stream_id;
enum msm_isp_stats_type stats_type;
uint8_t comp_flag;
uint32_t framedrop_pattern;
uint32_t irq_subsample_pattern;
uint32_t stream_handle;
uint8_t comp_flag;
};
struct msm_vfe_stats_stream_release_cmd {
uint32_t stream_handle;
};
@@ -173,6 +181,13 @@ struct msm_vfe_stats_stream_cfg_cmd {
uint32_t stream_handle[MSM_ISP_STATS_MAX];
uint8_t enable;
};
struct msm_vfe_stats_comp_policy_cfg {
enum msm_vfe_stats_pipeline_policy stats_pipeline_policy;
uint32_t comp_framedrop_pattern;
uint32_t comp_irq_subsample_pattern;
};
enum msm_vfe_reg_cfg_type {
VFE_WRITE,
VFE_WRITE_MB,
@@ -320,4 +335,8 @@ struct msm_isp_event_data {
_IOWR('V', BASE_VIDIOC_PRIVATE+11, \
struct msm_vfe_stats_stream_release_cmd)
#define VIDIOC_MSM_ISP_CFG_STATS_COMP_POLICY \
_IOWR('V', BASE_VIDIOC_PRIVATE+12, \
struct msm_vfe_stats_comp_policy_cfg)
#endif /* __MSMB_ISP__ */