Merge "msm: isp: Add support to multipass offline ISP"

This commit is contained in:
Linux Build Service Account 2016-11-29 16:18:50 -08:00 committed by Gerrit - the friendly Code Review server
commit d43553d47d
9 changed files with 338 additions and 5 deletions

View file

@ -243,6 +243,8 @@ struct msm_vfe_core_ops {
bool (*is_module_cfg_lock_needed)(uint32_t reg_offset);
int (*ahb_clk_cfg)(struct vfe_device *vfe_dev,
struct msm_isp_ahb_clk_cfg *ahb_cfg);
int (*start_fetch_eng_multi_pass)(struct vfe_device *vfe_dev,
void *arg);
};
struct msm_vfe_stats_ops {
int (*get_stats_idx)(enum msm_isp_stats_type stats_type);

View file

@ -1054,11 +1054,72 @@ static int msm_vfe40_start_fetch_engine(struct vfe_device *vfe_dev,
return 0;
}
static int msm_vfe40_start_fetch_engine_multi_pass(struct vfe_device *vfe_dev,
void *arg)
{
int rc = 0;
uint32_t bufq_handle = 0;
struct msm_isp_buffer *buf = NULL;
struct msm_vfe_fetch_eng_multi_pass_start *fe_cfg = arg;
struct msm_isp_buffer_mapped_info mapped_info;
if (vfe_dev->fetch_engine_info.is_busy == 1) {
pr_err("%s: fetch engine busy\n", __func__);
return -EINVAL;
}
memset(&mapped_info, 0, sizeof(struct msm_isp_buffer_mapped_info));
/* There is other option of passing buffer address from user,
* in such case, driver needs to map the buffer and use it
*/
vfe_dev->fetch_engine_info.session_id = fe_cfg->session_id;
vfe_dev->fetch_engine_info.stream_id = fe_cfg->stream_id;
vfe_dev->fetch_engine_info.offline_mode = fe_cfg->offline_mode;
vfe_dev->fetch_engine_info.fd = fe_cfg->fd;
if (!fe_cfg->offline_mode) {
bufq_handle = vfe_dev->buf_mgr->ops->get_bufq_handle(
vfe_dev->buf_mgr, fe_cfg->session_id,
fe_cfg->stream_id);
vfe_dev->fetch_engine_info.bufq_handle = bufq_handle;
rc = vfe_dev->buf_mgr->ops->get_buf_by_index(
vfe_dev->buf_mgr, bufq_handle, fe_cfg->buf_idx, &buf);
if (rc < 0 || !buf) {
pr_err("%s: No fetch buffer rc= %d buf= %p\n",
__func__, rc, buf);
return -EINVAL;
}
mapped_info = buf->mapped_info[0];
buf->state = MSM_ISP_BUFFER_STATE_DISPATCHED;
} else {
rc = vfe_dev->buf_mgr->ops->map_buf(vfe_dev->buf_mgr,
&mapped_info, fe_cfg->fd);
if (rc < 0) {
pr_err("%s: can not map buffer\n", __func__);
return -EINVAL;
}
}
vfe_dev->fetch_engine_info.buf_idx = fe_cfg->buf_idx;
vfe_dev->fetch_engine_info.is_busy = 1;
msm_camera_io_w(mapped_info.paddr + fe_cfg->input_buf_offset,
vfe_dev->vfe_base + 0x228);
msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x378);
msm_camera_io_w_mb(0x10000, vfe_dev->vfe_base + 0x4C);
msm_camera_io_w_mb(0x20000, vfe_dev->vfe_base + 0x4C);
ISP_DBG("%s:VFE%d Fetch Engine ready\n", __func__, vfe_dev->pdev->id);
return 0;
}
static void msm_vfe40_cfg_fetch_engine(struct vfe_device *vfe_dev,
struct msm_vfe_pix_cfg *pix_cfg)
{
uint32_t x_size_word;
uint32_t temp = 0;
uint32_t main_unpack_pattern = 0;
struct msm_vfe_fetch_engine_cfg *fe_cfg = NULL;
if (pix_cfg->input_mux != EXTERNAL_READ) {
@ -1089,10 +1150,14 @@ static void msm_vfe40_cfg_fetch_engine(struct vfe_device *vfe_dev,
/* need to update to use formulae to calculate X_SIZE_WORD*/
x_size_word = msm_isp_cal_word_per_line(
vfe_dev->axi_data.src_info[VFE_PIX_0].input_format,
fe_cfg->fetch_width);
fe_cfg->buf_width);
msm_camera_io_w((x_size_word - 1) << 16, vfe_dev->vfe_base + 0x23C);
x_size_word = msm_isp_cal_word_per_line(
vfe_dev->axi_data.src_info[VFE_PIX_0].input_format,
fe_cfg->fetch_width);
temp = msm_camera_io_r(vfe_dev->vfe_base + 0x1C);
temp |= 2 << 16 | pix_cfg->pixel_pattern;
msm_camera_io_w(temp, vfe_dev->vfe_base + 0x1C);
@ -1118,7 +1183,19 @@ static void msm_vfe40_cfg_fetch_engine(struct vfe_device *vfe_dev,
}
/* need to use formulae to calculate MAIN_UNPACK_PATTERN*/
msm_camera_io_w(0xF6543210, vfe_dev->vfe_base + 0x248);
switch (vfe_dev->axi_data.src_info[VFE_PIX_0].input_format) {
case V4L2_PIX_FMT_P16BGGR10:
case V4L2_PIX_FMT_P16GBRG10:
case V4L2_PIX_FMT_P16GRBG10:
case V4L2_PIX_FMT_P16RGGB10:
main_unpack_pattern = 0xB210;
break;
default:
main_unpack_pattern = 0xF6543210;
break;
}
msm_camera_io_w(main_unpack_pattern,
vfe_dev->vfe_base + 0x248);
msm_camera_io_w(0xF, vfe_dev->vfe_base + 0x264);
return;
@ -2261,6 +2338,8 @@ struct msm_vfe_hardware_info vfe40_hw_info = {
.is_module_cfg_lock_needed =
msm_vfe40_is_module_cfg_lock_needed,
.ahb_clk_cfg = NULL,
.start_fetch_eng_multi_pass =
msm_vfe40_start_fetch_engine_multi_pass,
},
.stats_ops = {
.get_stats_idx = msm_vfe40_get_stats_idx,

View file

@ -1077,11 +1077,70 @@ int msm_vfe47_start_fetch_engine(struct vfe_device *vfe_dev,
return 0;
}
int msm_vfe47_start_fetch_engine_multi_pass(struct vfe_device *vfe_dev,
void *arg)
{
int rc = 0;
uint32_t bufq_handle = 0;
struct msm_isp_buffer *buf = NULL;
struct msm_vfe_fetch_eng_multi_pass_start *fe_cfg = arg;
struct msm_isp_buffer_mapped_info mapped_info;
if (vfe_dev->fetch_engine_info.is_busy == 1) {
pr_err("%s: fetch engine busy\n", __func__);
return -EINVAL;
}
memset(&mapped_info, 0, sizeof(struct msm_isp_buffer_mapped_info));
vfe_dev->fetch_engine_info.session_id = fe_cfg->session_id;
vfe_dev->fetch_engine_info.stream_id = fe_cfg->stream_id;
vfe_dev->fetch_engine_info.offline_mode = fe_cfg->offline_mode;
vfe_dev->fetch_engine_info.fd = fe_cfg->fd;
if (!fe_cfg->offline_mode) {
bufq_handle = vfe_dev->buf_mgr->ops->get_bufq_handle(
vfe_dev->buf_mgr, fe_cfg->session_id,
fe_cfg->stream_id);
vfe_dev->fetch_engine_info.bufq_handle = bufq_handle;
rc = vfe_dev->buf_mgr->ops->get_buf_by_index(
vfe_dev->buf_mgr, bufq_handle, fe_cfg->buf_idx, &buf);
if (rc < 0 || !buf) {
pr_err("%s: No fetch buffer rc= %d buf= %pK\n",
__func__, rc, buf);
return -EINVAL;
}
mapped_info = buf->mapped_info[0];
buf->state = MSM_ISP_BUFFER_STATE_DISPATCHED;
} else {
rc = vfe_dev->buf_mgr->ops->map_buf(vfe_dev->buf_mgr,
&mapped_info, fe_cfg->fd);
if (rc < 0) {
pr_err("%s: can not map buffer\n", __func__);
return -EINVAL;
}
}
vfe_dev->fetch_engine_info.buf_idx = fe_cfg->buf_idx;
vfe_dev->fetch_engine_info.is_busy = 1;
msm_camera_io_w(mapped_info.paddr + fe_cfg->input_buf_offset,
vfe_dev->vfe_base + 0x2F4);
msm_camera_io_w_mb(0x100000, vfe_dev->vfe_base + 0x80);
msm_camera_io_w_mb(0x200000, vfe_dev->vfe_base + 0x80);
ISP_DBG("%s:VFE%d Fetch Engine ready\n", __func__, vfe_dev->pdev->id);
return 0;
}
void msm_vfe47_cfg_fetch_engine(struct vfe_device *vfe_dev,
struct msm_vfe_pix_cfg *pix_cfg)
{
uint32_t x_size_word, temp;
struct msm_vfe_fetch_engine_cfg *fe_cfg = NULL;
uint32_t main_unpack_pattern = 0;
if (pix_cfg->input_mux == EXTERNAL_READ) {
fe_cfg = &pix_cfg->fetch_engine_cfg;
@ -1107,10 +1166,13 @@ void msm_vfe47_cfg_fetch_engine(struct vfe_device *vfe_dev,
x_size_word = msm_isp_cal_word_per_line(
vfe_dev->axi_data.src_info[VFE_PIX_0].input_format,
fe_cfg->fetch_width);
fe_cfg->buf_width);
msm_camera_io_w((x_size_word - 1) << 16,
vfe_dev->vfe_base + 0x30c);
x_size_word = msm_isp_cal_word_per_line(
vfe_dev->axi_data.src_info[VFE_PIX_0].input_format,
fe_cfg->fetch_width);
msm_camera_io_w(x_size_word << 16 |
(temp & 0x3FFF) << 2 | VFE47_FETCH_BURST_LEN,
vfe_dev->vfe_base + 0x310);
@ -1120,7 +1182,19 @@ void msm_vfe47_cfg_fetch_engine(struct vfe_device *vfe_dev,
msm_camera_io_w(temp, vfe_dev->vfe_base + 0x314);
/* need to use formulae to calculate MAIN_UNPACK_PATTERN*/
msm_camera_io_w(0xF6543210, vfe_dev->vfe_base + 0x318);
switch (vfe_dev->axi_data.src_info[VFE_PIX_0].input_format) {
case V4L2_PIX_FMT_P16BGGR10:
case V4L2_PIX_FMT_P16GBRG10:
case V4L2_PIX_FMT_P16GRBG10:
case V4L2_PIX_FMT_P16RGGB10:
main_unpack_pattern = 0xB210;
break;
default:
main_unpack_pattern = 0xF6543210;
break;
}
msm_camera_io_w(main_unpack_pattern,
vfe_dev->vfe_base + 0x318);
msm_camera_io_w(0xF, vfe_dev->vfe_base + 0x334);
temp = msm_camera_io_r(vfe_dev->vfe_base + 0x50);
@ -2721,6 +2795,8 @@ struct msm_vfe_hardware_info vfe47_hw_info = {
.is_module_cfg_lock_needed =
msm_vfe47_is_module_cfg_lock_needed,
.ahb_clk_cfg = msm_isp47_ahb_clk_cfg,
.start_fetch_eng_multi_pass =
msm_vfe47_start_fetch_engine_multi_pass,
},
.stats_ops = {
.get_stats_idx = msm_vfe47_get_stats_idx,

View file

@ -65,6 +65,8 @@ int32_t msm_vfe47_cfg_io_format(struct vfe_device *vfe_dev,
enum msm_vfe_axi_stream_src stream_src, uint32_t io_format);
int msm_vfe47_start_fetch_engine(struct vfe_device *vfe_dev,
void *arg);
int msm_vfe47_start_fetch_engine_multi_pass(struct vfe_device *vfe_dev,
void *arg);
void msm_vfe47_cfg_fetch_engine(struct vfe_device *vfe_dev,
struct msm_vfe_pix_cfg *pix_cfg);
void msm_vfe47_cfg_testgen(struct vfe_device *vfe_dev,

View file

@ -309,6 +309,8 @@ struct msm_vfe_hardware_info vfe48_hw_info = {
.is_module_cfg_lock_needed =
msm_vfe47_is_module_cfg_lock_needed,
.ahb_clk_cfg = msm_isp47_ahb_clk_cfg,
.start_fetch_eng_multi_pass =
msm_vfe47_start_fetch_engine_multi_pass,
},
.stats_ops = {
.get_stats_idx = msm_vfe47_get_stats_idx,

View file

@ -1691,6 +1691,76 @@ static struct msm_isp_buffer *msm_isp_get_stream_buffer(
return buf;
}
int msm_isp_cfg_offline_ping_pong_address(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status,
uint32_t buf_idx)
{
int i, rc = 0;
struct msm_isp_buffer *buf = NULL;
uint32_t pingpong_bit;
uint32_t buffer_size_byte = 0;
int32_t word_per_line = 0;
dma_addr_t paddr;
uint32_t bufq_handle = 0;
int vfe_idx;
bufq_handle = stream_info->bufq_handle[VFE_BUF_QUEUE_DEFAULT];
if (!vfe_dev->is_split) {
rc = vfe_dev->buf_mgr->ops->get_buf_by_index(
vfe_dev->buf_mgr, bufq_handle, buf_idx, &buf);
if (rc < 0 || !buf) {
pr_err("%s: No fetch buffer rc= %d buf= %p\n",
__func__, rc, buf);
return -EINVAL;
}
if (buf->num_planes != stream_info->num_planes) {
pr_err("%s: Invalid buffer\n", __func__);
vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr,
bufq_handle, buf->buf_idx);
return -EINVAL;
}
vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
pingpong_bit = ((pingpong_status >>
stream_info->wm[vfe_idx][0]) & 0x1);
for (i = 0; i < stream_info->num_planes; i++) {
word_per_line = msm_isp_cal_word_per_line(
stream_info->output_format,
stream_info->plane_cfg[vfe_idx][i].
output_stride);
if (word_per_line < 0) {
/* 0 means no prefetch*/
word_per_line = 0;
buffer_size_byte = 0;
} else {
buffer_size_byte = (word_per_line * 8 *
stream_info->plane_cfg[vfe_idx][i].
output_scan_lines) -
stream_info->
plane_cfg[vfe_idx][i].plane_addr_offset;
}
paddr = buf->mapped_info[i].paddr;
vfe_dev->hw_info->vfe_ops.axi_ops.
update_ping_pong_addr(
vfe_dev->vfe_base, stream_info->wm[vfe_idx][i],
pingpong_bit, paddr +
stream_info->
plane_cfg[vfe_idx][i].plane_addr_offset,
buffer_size_byte);
stream_info->buf[!pingpong_bit] = buf;
buf->pingpong_bit = !pingpong_bit;
}
buf->state = MSM_ISP_BUFFER_STATE_DEQUEUED;
stream_info->buf[!pingpong_bit] = buf;
buf->pingpong_bit = !pingpong_bit;
}
return rc;
}
static int msm_isp_cfg_ping_pong_address(
struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status)
{
@ -1888,6 +1958,11 @@ static int msm_isp_process_done_buf(struct vfe_device *vfe_dev,
buf_event.u.buf_done.buf_idx = buf->buf_idx;
buf_event.u.buf_done.output_format =
stream_info->runtime_output_format;
if (vfe_dev->fetch_engine_info.is_busy &&
SRC_TO_INTF(stream_info->stream_src) == VFE_PIX_0) {
vfe_dev->fetch_engine_info.is_busy = 0;
}
if (stream_info->buf_divert &&
buf_src != MSM_ISP_BUFFER_SRC_SCRATCH) {
@ -2065,6 +2140,7 @@ static void msm_isp_input_enable(struct vfe_device *vfe_dev,
continue;
/* activate the input since it is deactivated */
axi_data->src_info[i].frame_id = 0;
if (axi_data->src_info[i].input_mux != EXTERNAL_READ)
axi_data->src_info[i].active = 1;
if (i >= VFE_RAW_0 && sync_frame_id_src) {
/*
@ -3534,6 +3610,7 @@ int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg)
unsigned long flags;
struct msm_isp_timestamp timestamp;
uint32_t frame_id;
int vfe_idx;
/*num_stream is uint32 and update_info[] bound by MAX_NUM_STREAM*/
if (update_cmd->num_streams > MAX_NUM_STREAM)
@ -3746,6 +3823,20 @@ int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg)
__func__);
break;
}
case UPDATE_STREAM_OFFLINE_AXI_CONFIG: {
for (i = 0; i < update_cmd->num_streams; i++) {
update_info =
(struct msm_vfe_axi_stream_cfg_update_info *)
&update_cmd->update_info[i];
stream_info = msm_isp_get_stream_common_data(vfe_dev,
HANDLE_TO_IDX(update_info->stream_handle));
vfe_idx = msm_isp_get_vfe_idx_for_stream(
vfe_dev, stream_info);
msm_isp_stream_axi_cfg_update(vfe_dev, stream_info,
update_info);
}
break;
}
default:
pr_err("%s: Invalid update type %d\n", __func__,
update_cmd->update_type);

View file

@ -157,4 +157,7 @@ static inline struct msm_vfe_axi_stream *msm_isp_vfe_get_stream(
index);
}
int msm_isp_cfg_offline_ping_pong_address(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status,
uint32_t buf_idx);
#endif /* __MSM_ISP_AXI_UTIL_H__ */

View file

@ -375,6 +375,47 @@ static int msm_isp_start_fetch_engine(struct vfe_device *vfe_dev,
start_fetch_eng(vfe_dev, arg);
}
static int msm_isp_start_fetch_engine_multi_pass(struct vfe_device *vfe_dev,
void *arg)
{
struct msm_vfe_fetch_eng_multi_pass_start *fe_cfg = arg;
struct msm_vfe_axi_stream *stream_info = NULL;
int i = 0, rc;
uint32_t wm_reload_mask = 0;
int vfe_idx;
/*
* For Offline VFE, HAL expects same frame id
* for offline output which it requested in do_reprocess.
*/
vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id =
fe_cfg->frame_id;
if (fe_cfg->offline_pass == OFFLINE_SECOND_PASS) {
stream_info = msm_isp_get_stream_common_data(vfe_dev,
HANDLE_TO_IDX(fe_cfg->output_stream_id));
if (stream_info == NULL) {
pr_err("%s: Error in Offline process\n", __func__);
return -EINVAL;
}
vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
msm_isp_reset_framedrop(vfe_dev, stream_info);
rc = msm_isp_cfg_offline_ping_pong_address(vfe_dev, stream_info,
VFE_PING_FLAG, fe_cfg->output_buf_idx);
if (rc < 0) {
pr_err("%s: Fetch engine config failed\n", __func__);
return -EINVAL;
}
for (i = 0; i < stream_info->num_planes; i++)
wm_reload_mask |= (1 << stream_info->wm[vfe_idx][i]);
vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev,
VFE_SRC_MAX);
vfe_dev->hw_info->vfe_ops.axi_ops.reload_wm(vfe_dev,
vfe_dev->vfe_base, wm_reload_mask);
}
return vfe_dev->hw_info->vfe_ops.core_ops.
start_fetch_eng_multi_pass(vfe_dev, arg);
}
void msm_isp_fetch_engine_done_notify(struct vfe_device *vfe_dev,
struct msm_vfe_fetch_engine_info *fetch_engine_info)
{
@ -880,6 +921,13 @@ static long msm_isp_ioctl_unlocked(struct v4l2_subdev *sd,
rc = msm_isp_start_fetch_engine(vfe_dev, arg);
mutex_unlock(&vfe_dev->core_mutex);
break;
case VIDIOC_MSM_ISP_FETCH_ENG_MULTI_PASS_START:
case VIDIOC_MSM_ISP_MAP_BUF_START_MULTI_PASS_FE:
mutex_lock(&vfe_dev->core_mutex);
rc = msm_isp_start_fetch_engine_multi_pass(vfe_dev, arg);
mutex_unlock(&vfe_dev->core_mutex);
break;
case VIDIOC_MSM_ISP_REG_UPDATE_CMD:
if (arg) {
enum msm_vfe_input_src frame_src =

View file

@ -261,6 +261,26 @@ struct msm_vfe_fetch_eng_start {
uint32_t frame_id;
};
enum msm_vfe_fetch_eng_pass {
OFFLINE_FIRST_PASS,
OFFLINE_SECOND_PASS,
OFFLINE_MAX_PASS,
};
struct msm_vfe_fetch_eng_multi_pass_start {
uint32_t session_id;
uint32_t stream_id;
uint32_t buf_idx;
uint8_t offline_mode;
uint32_t fd;
uint32_t buf_addr;
uint32_t frame_id;
uint32_t output_buf_idx;
uint32_t input_buf_offset;
enum msm_vfe_fetch_eng_pass offline_pass;
uint32_t output_stream_id;
};
struct msm_vfe_axi_plane_cfg {
uint32_t output_width; /*Include padding*/
uint32_t output_height;
@ -328,6 +348,7 @@ enum msm_vfe_axi_stream_update_type {
UPDATE_STREAM_REMOVE_BUFQ,
UPDATE_STREAM_SW_FRAME_DROP,
UPDATE_STREAM_REQUEST_FRAMES_VER2,
UPDATE_STREAM_OFFLINE_AXI_CONFIG,
};
#define UPDATE_STREAM_REQUEST_FRAMES_VER2 UPDATE_STREAM_REQUEST_FRAMES_VER2
@ -853,6 +874,8 @@ enum msm_isp_ioctl_cmd_code {
MSM_ISP_SET_DUAL_HW_MASTER_SLAVE,
MSM_ISP_MAP_BUF_START_FE,
MSM_ISP_UNMAP_BUF,
MSM_ISP_FETCH_ENG_MULTI_PASS_START,
MSM_ISP_MAP_BUF_START_MULTI_PASS_FE,
};
#define VIDIOC_MSM_VFE_REG_CFG \
@ -958,4 +981,11 @@ enum msm_isp_ioctl_cmd_code {
#define VIDIOC_MSM_ISP_AHB_CLK_CFG \
_IOWR('V', BASE_VIDIOC_PRIVATE+25, struct msm_isp_ahb_clk_cfg)
#define VIDIOC_MSM_ISP_FETCH_ENG_MULTI_PASS_START \
_IOWR('V', MSM_ISP_FETCH_ENG_MULTI_PASS_START, \
struct msm_vfe_fetch_eng_multi_pass_start)
#define VIDIOC_MSM_ISP_MAP_BUF_START_MULTI_PASS_FE \
_IOWR('V', MSM_ISP_MAP_BUF_START_MULTI_PASS_FE, \
struct msm_vfe_fetch_eng_multi_pass_start)
#endif /* __MSMB_ISP__ */