diff options
5 files changed, 282 insertions, 10 deletions
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c index 4c0991e0dd26..c9656e748f09 100644 --- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c +++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c @@ -58,6 +58,9 @@ static int msm_ispif_clk_ahb_enable(struct ispif_device *ispif, int enable); static int ispif_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh); +static long msm_ispif_subdev_ioctl_unlocked(struct v4l2_subdev *sd, + unsigned int cmd, void *arg); + int msm_ispif_get_clk_info(struct ispif_device *ispif_dev, struct platform_device *pdev); @@ -95,6 +98,192 @@ static struct msm_cam_clk_info ispif_8626_reset_clk_info[] = { {"camss_csi_vfe_clk", NO_SET_RATE}, }; +#ifdef CONFIG_COMPAT +struct ispif_cfg_data_ext_32 { + enum ispif_cfg_type_t cfg_type; + compat_caddr_t data; + uint32_t size; +}; + +#define VIDIOC_MSM_ISPIF_CFG_EXT_COMPAT \ + _IOWR('V', BASE_VIDIOC_PRIVATE+1, struct ispif_cfg_data_ext_32) +#endif + +static void msm_ispif_get_pack_mask_from_cfg( + struct msm_ispif_pack_cfg *pack_cfg, + struct msm_ispif_params_entry *entry, + uint32_t *pack_mask) +{ + int i; + uint32_t temp; + + if (WARN_ON(!entry)) + return; + + memset(pack_mask, 0, sizeof(uint32_t) * 2); + for (i = 0; i < entry->num_cids; i++) { + temp = (pack_cfg[entry->cids[i]].pack_mode & 0x3)| + (pack_cfg[entry->cids[i]].even_odd_sel & 0x1) << 2 | + (pack_cfg[entry->cids[i]].pixel_swap_en & 0x1) << 3; + temp = (temp & 0xF) << ((entry->cids[i] % CID8) * 4); + + if (entry->cids[i] > CID7) + pack_mask[1] |= temp; + else + pack_mask[0] |= temp; + CDBG("%s:num %d cid %d mode %d pack_mask %x %x\n", + __func__, entry->num_cids, entry->cids[i], + pack_cfg[i].pack_mode, + pack_mask[0], pack_mask[1]); + + } +} + +static int msm_ispif_config2(struct ispif_device *ispif, + void *data) +{ + int rc = 0, i = 0; + enum msm_ispif_intftype intftype; + enum msm_ispif_vfe_intf vfe_intf; + uint32_t pack_cfg_mask[2]; + struct msm_ispif_param_data_ext *params = + (struct msm_ispif_param_data_ext *)data; + + if (WARN_ON(!ispif) || WARN_ON(!params)) + return -EINVAL; + + if (ispif->ispif_state != ISPIF_POWER_UP) { + pr_err("%s: ispif invalid state %d\n", __func__, + ispif->ispif_state); + rc = -EPERM; + return rc; + } + if (params->num > MAX_PARAM_ENTRIES) { + pr_err("%s: invalid param entries %d\n", __func__, + params->num); + rc = -EINVAL; + return rc; + } + + for (i = 0; i < params->num; i++) { + intftype = params->entries[i].intftype; + vfe_intf = params->entries[i].vfe_intf; + + CDBG("%s, num %d intftype %x, vfe_intf %d, csid %d\n", __func__, + params->num, intftype, vfe_intf, + params->entries[i].csid); + + if ((intftype >= INTF_MAX) || + (vfe_intf >= ispif->vfe_info.num_vfe) || + (ispif->csid_version <= CSID_VERSION_V22 && + (vfe_intf > VFE0))) { + pr_err("%s: VFEID %d and CSID version %d mismatch\n", + __func__, vfe_intf, ispif->csid_version); + return -EINVAL; + } + + msm_ispif_get_pack_mask_from_cfg(params->pack_cfg, + ¶ms->entries[i], pack_cfg_mask); + msm_ispif_cfg_pack_mode(ispif, intftype, vfe_intf, + pack_cfg_mask); + } + return rc; +} + +static long msm_ispif_cmd_ext(struct v4l2_subdev *sd, + void *arg) +{ + long rc = 0; + struct ispif_device *ispif = + (struct ispif_device *)v4l2_get_subdevdata(sd); + struct ispif_cfg_data_ext pcdata; + struct msm_ispif_param_data_ext *params = NULL; +#ifdef CONFIG_COMPAT + struct ispif_cfg_data_ext_32 *pcdata32 = + (struct ispif_cfg_data_ext_32 *)arg; + + if (pcdata32 == NULL) { + pr_err("Invalid params passed from user\n"); + return -EINVAL; + } + pcdata.cfg_type = pcdata32->cfg_type; + pcdata.size = pcdata32->size; + pcdata.data = compat_ptr(pcdata32->data); + +#else + struct ispif_cfg_data_ext *pcdata64 = + (struct ispif_cfg_data_ext *)arg; + + if (pcdata64 == NULL) { + pr_err("Invalid params passed from user\n"); + return -EINVAL; + } + pcdata.cfg_type = pcdata64->cfg_type; + pcdata.size = pcdata64->size; + pcdata.data = pcdata64->data; +#endif + if (pcdata.size != sizeof(struct msm_ispif_param_data_ext)) { + pr_err("%s: payload size mismatch\n", __func__); + return -EINVAL; + } + + params = kzalloc(sizeof(struct msm_ispif_param_data_ext), GFP_KERNEL); + if (!params) { + CDBG("%s: params alloc failed\n", __func__); + return -ENOMEM; + } + if (copy_from_user(params, (void __user *)(pcdata.data), + pcdata.size)) { + kfree(params); + return -EFAULT; + } + + mutex_lock(&ispif->mutex); + switch (pcdata.cfg_type) { + case ISPIF_CFG2: + rc = msm_ispif_config2(ispif, params); + msm_ispif_io_dump_reg(ispif); + break; + default: + pr_err("%s: invalid cfg_type\n", __func__); + rc = -EINVAL; + break; + } + mutex_unlock(&ispif->mutex); + kfree(params); + return rc; +} + +#ifdef CONFIG_COMPAT +static long msm_ispif_subdev_ioctl_compat(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + if (WARN_ON(!sd)) + return -EINVAL; + + switch (cmd) { + case VIDIOC_MSM_ISPIF_CFG_EXT_COMPAT: + return msm_ispif_cmd_ext(sd, arg); + + default: + return msm_ispif_subdev_ioctl_unlocked(sd, cmd, arg); + } +} +static long msm_ispif_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + if (is_compat_task()) + return msm_ispif_subdev_ioctl_compat(sd, cmd, arg); + else + return msm_ispif_subdev_ioctl_unlocked(sd, cmd, arg); +} +#else +static long msm_ispif_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + return msm_ispif_subdev_ioctl_unlocked(sd, cmd, arg); +} +#endif static void msm_ispif_put_regulator(struct ispif_device *ispif_dev) { int i; @@ -649,7 +838,6 @@ static uint16_t msm_ispif_get_cids_mask_from_cfg( { int i; uint16_t cids_mask = 0; - BUG_ON(!entry); for (i = 0; i < entry->num_cids; i++) @@ -657,14 +845,15 @@ static uint16_t msm_ispif_get_cids_mask_from_cfg( return cids_mask; } - static int msm_ispif_config(struct ispif_device *ispif, - struct msm_ispif_param_data *params) + void *data) { int rc = 0, i = 0; uint16_t cid_mask; enum msm_ispif_intftype intftype; enum msm_ispif_vfe_intf vfe_intf; + struct msm_ispif_param_data *params = + (struct msm_ispif_param_data *)data; BUG_ON(!ispif); BUG_ON(!params); @@ -1415,7 +1604,7 @@ static long msm_ispif_cmd(struct v4l2_subdev *sd, void *arg) } static struct v4l2_file_operations msm_ispif_v4l2_subdev_fops; -static long msm_ispif_subdev_ioctl(struct v4l2_subdev *sd, +static long msm_ispif_subdev_ioctl_unlocked(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { struct ispif_device *ispif = @@ -1424,6 +1613,8 @@ static long msm_ispif_subdev_ioctl(struct v4l2_subdev *sd, switch (cmd) { case VIDIOC_MSM_ISPIF_CFG: return msm_ispif_cmd(sd, arg); + case VIDIOC_MSM_ISPIF_CFG_EXT: + return msm_ispif_cmd_ext(sd, arg); case MSM_SD_NOTIFY_FREEZE: { ispif->ispif_sof_debug = 0; ispif->ispif_rdi0_debug = 0; diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h index b82fd34f2396..d488ca618537 100644 --- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h +++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2016, 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 @@ -115,4 +115,10 @@ #define ISPIF_IRQ_GLOBAL_CLEAR_CMD 0x000001 #define ISPIF_STOP_INTF_IMMEDIATELY 0xAAAAAAAA + +/* ISPIF RDI pack mode not supported */ +static inline void msm_ispif_cfg_pack_mode(struct ispif_device *ispif, + uint8_t intftype, uint8_t vfe_intf, uint32_t *pack_cfg_mask) +{ +} #endif /* __MSM_ISPIF_HWREG_V1_H__ */ diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v2.h b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v2.h index 01dce6d45897..8ae61dc2d4f6 100644 --- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v2.h +++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v2.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2016, 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 @@ -96,4 +96,9 @@ #define ISPIF_STOP_INTF_IMMEDIATELY 0xAAAAAAAA +/* ISPIF RDI pack mode not supported */ +static inline void msm_ispif_cfg_pack_mode(struct ispif_device *ispif, + uint8_t intftype, uint8_t vfe_intf, uint32_t *pack_cfg_mask) +{ +} #endif /* __MSM_ISPIF_HWREG_V2_H__ */ diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v3.h b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v3.h index 343575263816..94cc974441ee 100644 --- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v3.h +++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v3.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2016, 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 @@ -10,8 +10,8 @@ * GNU General Public License for more details. */ -#ifndef __MSM_ISPIF_HWREG_V2_H__ -#define __MSM_ISPIF_HWREG_V2_H__ +#ifndef __MSM_ISPIF_HWREG_V3_H__ +#define __MSM_ISPIF_HWREG_V3_H__ /* common registers */ #define ISPIF_RST_CMD_ADDR 0x008 @@ -99,4 +99,38 @@ #define ISPIF_STOP_INTF_IMMEDIATELY 0xAAAAAAAA -#endif /* __MSM_ISPIF_HWREG_V2_H__ */ +/* ISPIF RDI pack mode support */ +static inline void msm_ispif_cfg_pack_mode(struct ispif_device *ispif, + uint8_t intftype, uint8_t vfe_intf, uint32_t *pack_cfg_mask) +{ + uint32_t pack_addr[2]; + + if (WARN_ON(!ispif)) + return; + + switch (intftype) { + case RDI0: + pack_addr[0] = ISPIF_VFE_m_RDI_INTF_n_PACK_0(vfe_intf, 0); + pack_addr[1] = ISPIF_VFE_m_RDI_INTF_n_PACK_1(vfe_intf, 0); + break; + case RDI1: + pack_addr[0] = ISPIF_VFE_m_RDI_INTF_n_PACK_0(vfe_intf, 1); + pack_addr[1] = ISPIF_VFE_m_RDI_INTF_n_PACK_1(vfe_intf, 1); + break; + case RDI2: + pack_addr[0] = ISPIF_VFE_m_RDI_INTF_n_PACK_0(vfe_intf, 2); + pack_addr[1] = ISPIF_VFE_m_RDI_INTF_n_PACK_1(vfe_intf, 2); + break; + default: + pr_debug("%s: pack_mode not supported on intftype=%d\n", + __func__, intftype); + return; + } + pr_debug("%s: intftype %d pack_mask %x: 0x%x, %x:0x%x\n", + __func__, intftype, pack_addr[0], + pack_cfg_mask[0], pack_addr[1], + pack_cfg_mask[1]); + msm_camera_io_w_mb(pack_cfg_mask[0], ispif->base + pack_addr[0]); + msm_camera_io_w_mb(pack_cfg_mask[1], ispif->base + pack_addr[1]); +} +#endif /* __MSM_ISPIF_HWREG_V3_H__ */ diff --git a/include/uapi/media/msmb_ispif.h b/include/uapi/media/msmb_ispif.h index 26bd8a2ce87f..7f4deaf12683 100644 --- a/include/uapi/media/msmb_ispif.h +++ b/include/uapi/media/msmb_ispif.h @@ -72,6 +72,24 @@ enum msm_ispif_csid { CSID_MAX }; +enum msm_ispif_pixel_odd_even { + PIX_EVEN, + PIX_ODD +}; + +enum msm_ispif_pixel_pack_mode { + PACK_BYTE, + PACK_PLAIN_PACK, + PACK_NV_P8, + PACK_NV_P16 +}; + +struct msm_ispif_pack_cfg { + int pixel_swap_en; + enum msm_ispif_pixel_odd_even even_odd_sel; + enum msm_ispif_pixel_pack_mode pack_mode; +}; + struct msm_ispif_params_entry { enum msm_ispif_vfe_intf vfe_intf; enum msm_ispif_intftype intftype; @@ -83,6 +101,12 @@ struct msm_ispif_params_entry { uint16_t crop_end_pixel; }; +struct msm_ispif_param_data_ext { + uint32_t num; + struct msm_ispif_params_entry entries[MAX_PARAM_ENTRIES]; + struct msm_ispif_pack_cfg pack_cfg[CID_MAX]; +}; + struct msm_ispif_param_data { uint32_t num; struct msm_ispif_params_entry entries[MAX_PARAM_ENTRIES]; @@ -111,6 +135,7 @@ enum ispif_cfg_type_t { ISPIF_RELEASE, ISPIF_ENABLE_REG_DUMP, ISPIF_SET_VFE_INFO, + ISPIF_CFG2, }; struct ispif_cfg_data { @@ -123,8 +148,19 @@ struct ispif_cfg_data { }; }; +struct ispif_cfg_data_ext { + enum ispif_cfg_type_t cfg_type; + void __user *data; + uint32_t size; +}; + +#define ISPIF_RDI_PACK_MODE_SUPPORT 1 + #define VIDIOC_MSM_ISPIF_CFG \ _IOWR('V', BASE_VIDIOC_PRIVATE, struct ispif_cfg_data) +#define VIDIOC_MSM_ISPIF_CFG_EXT \ + _IOWR('V', BASE_VIDIOC_PRIVATE+1, struct ispif_cfg_data_ext) + #endif |