msm: camera: Add camera support for apq8009

Initial snapshot of camera drivers are taken from msm-3.18 kernel
version @ 'commit cb28f8462e97 ("Merge PM / devfreq: memlat: Remove
kfree() on probe fails")'. Make required changes in camera
drivers to support camera modules on apq8009.

Change-Id: I3324684bcb866a9c67c1ba53d24fabd2bd98be43
Signed-off-by: Sundara Vinayagam <sundvi@codeaurora.org>
This commit is contained in:
Sundara Vinayagam 2018-05-15 17:13:10 +05:30 • committed by Gerrit - the friendly Code Review server
commit 16b4b35144
24 changed files with 8192 additions and 265 deletions

View file

@ -95,13 +95,22 @@ config MSM_EEPROM
and also provides support for writing data in case of FLASH ROM.
Currently supports I2C, CCI and SPI protocol
config MSM_ISP_V1
bool "QTI MSM Image Signal Processing interface support"
depends on MSMB_CAMERA
---help---
Enable support for Image Signal Processing interface module.
This module acts as a crossbar between CSID and VFE. Output
of any CID of CSID can be routed to of pix or raw
data interface in VFE.
config MSM_ISPIF
bool "QTI MSM Image Signal Processing interface support"
depends on MSMB_CAMERA
---help---
Enable support for Image Signal Processing interface module.
This module acts as a crossbar between CSID and VFE. Output
of any CID of CSID can be routed to of of pix or raw
of any CID of CSID can be routed to of pix or raw
data interface in VFE.
config MSM_ISPIF_V1

View file

@ -20,8 +20,6 @@
#define EMPTY_QSEECOM_HANDLE NULL
#define QSEECOM_SBUFF_SIZE SZ_128K
#define MSM_CAMERA_TZ_UTIL_VERBOSE
#define MSM_CAMERA_TZ_BOOT_PROTECTED (false)
/* Update version major number in case the HLOS-TA interface is changed*/

View file

@ -1,5 +1,10 @@
ccflags-y += -Idrivers/media/platform/msm/camera_v2
ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
ccflags-y += -Idrivers/media/platform/msm/camera_v2/common/
ifeq ($(CONFIG_MSM_ISP_V1),y)
obj-$(CONFIG_MSMB_CAMERA) += msm_isp_32.o msm_buf_mgr.o msm_isp_util_32.o msm_isp_axi_util_32.o msm_isp_stats_util_32.o
obj-$(CONFIG_MSMB_CAMERA) += msm_isp32.o
else
obj-$(CONFIG_MSMB_CAMERA) += msm_buf_mgr.o msm_isp_util.o msm_isp_axi_util.o msm_isp_stats_util.o
obj-$(CONFIG_MSMB_CAMERA) += msm_isp48.o msm_isp47.o msm_isp46.o msm_isp44.o msm_isp40.o msm_isp.o
endif

View file

@ -189,7 +189,9 @@ static int msm_isp_prepare_v4l2_buf(struct msm_isp_buf_mgr *buf_mgr,
int i, rc = -1;
int ret;
struct msm_isp_buffer_mapped_info *mapped_info;
#ifndef CONFIG_MSM_ISP_V1
uint32_t accu_length = 0;
#endif
struct msm_isp_bufq *bufq = NULL;
bufq = msm_isp_get_bufq(buf_mgr, buf_info->bufq_handle);
@ -228,8 +230,12 @@ static int msm_isp_prepare_v4l2_buf(struct msm_isp_buf_mgr *buf_mgr,
goto get_phy_err;
}
#ifdef CONFIG_MSM_ISP_V1
mapped_info->paddr += qbuf_buf->planes[i].offset;
#else
mapped_info->paddr += accu_length;
accu_length += qbuf_buf->planes[i].length;
#endif
CDBG("%s: plane: %d addr:%pK\n",
__func__, i, (void *)mapped_info->paddr);
@ -732,10 +738,17 @@ static int msm_isp_buf_divert(struct msm_isp_buf_mgr *buf_mgr,
spin_lock_irqsave(&bufq->bufq_lock, flags);
buf_info->frame_id = frame_id;
#ifdef CONFIG_MSM_ISP_V1
if (buf_info->state == MSM_ISP_BUFFER_STATE_DEQUEUED) {
buf_info->state = MSM_ISP_BUFFER_STATE_DIVERTED;
buf_info->tv = tv;
}
#else
if (BUF_SRC(bufq->stream_id) == MSM_ISP_BUFFER_SRC_NATIVE) {
buf_info->state = MSM_ISP_BUFFER_STATE_DIVERTED;
buf_info->tv = tv;
}
#endif
spin_unlock_irqrestore(&bufq->bufq_lock, flags);
return 0;
}
@ -1077,7 +1090,6 @@ static void msm_isp_release_all_bufq(
}
}
/**
* msm_isp_buf_put_scratch() - Release scratch buffers
* @buf_mgr: The buffer structure for h/w
@ -1220,7 +1232,6 @@ err1:
return rc;
}
static int msm_isp_init_isp_buf_mgr(struct msm_isp_buf_mgr *buf_mgr,
const char *ctx_name)
{

View file

@ -12,21 +12,15 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include "msm_isp32.h"
#include "msm_isp_util.h"
#include "msm_isp_axi_util.h"
#include "msm_isp_stats_util.h"
#include "msm_isp.h"
#include "msm_isp_util_32.h"
#include "msm_isp_axi_util_32.h"
#include "msm_isp_stats_util_32.h"
#include "msm_isp_32.h"
#include "msm.h"
#include "msm_camera_io_util.h"
static const struct platform_device_id msm_vfe32_dev_id[] = {
{"msm_vfe32", (kernel_ulong_t) &vfe32_hw_info},
{}
};
#define VFE32_BURST_LEN 2
#define VFE32_BURST_LEN 3
#define VFE32_UB_SIZE 1024
#define VFE32_UB_SIZE_32KB 2048
#define VFE32_EQUAL_SLICE_UB 194
@ -36,7 +30,7 @@ static const struct platform_device_id msm_vfe32_dev_id[] = {
#define VFE32_XBAR_BASE(idx) (0x40 + 0x4 * (idx / 4))
#define VFE32_XBAR_SHIFT(idx) ((idx % 4) * 8)
#define VFE32_PING_PONG_BASE(wm, ping_pong) \
(VFE32_WM_BASE(wm) + 0x4 * (1 + ((~ping_pong) & 0x1)))
(VFE32_WM_BASE(wm) + 0x4 * (1 + (~(ping_pong >> wm) & 0x1)))
static uint8_t stats_pingpong_offset_map[] = {
7, 8, 9, 10, 11, 12, 13};
@ -60,16 +54,6 @@ static struct msm_cam_clk_info msm_vfe32_2_clk_info[] = {
{"csi_vfe_clk", -1},
};
static uint32_t msm_vfe32_ub_reg_offset(struct vfe_device *vfe_dev, int idx)
{
return (VFE32_WM_BASE(idx) + 0x10);
}
static uint32_t msm_vfe32_get_ub_size(struct vfe_device *vfe_dev)
{
return MSM_ISP32_TOTAL_WM_UB;
}
static int32_t msm_vfe32_init_qos_parms(struct vfe_device *vfe_dev,
struct msm_vfe_hw_init_parms *qos_parms,
struct msm_vfe_hw_init_parms *ds_parms)
@ -284,8 +268,6 @@ static int msm_vfe32_init_hardware(struct vfe_device *vfe_dev)
pr_err("%s: vfe ioremap failed\n", __func__);
goto vfe_remap_failed;
}
vfe_dev->common_data->dual_vfe_res->vfe_base[vfe_dev->pdev->id] =
vfe_dev->vfe_base;
vfe_dev->vfe_vbif_base = ioremap(vfe_dev->vfe_vbif_mem->start,
resource_size(vfe_dev->vfe_vbif_mem));
@ -330,14 +312,12 @@ bus_scale_register_failed:
static void msm_vfe32_release_hardware(struct vfe_device *vfe_dev)
{
msm_camera_io_w_mb(0x0, vfe_dev->vfe_base + 0x1C);
msm_camera_io_w_mb(0x0, vfe_dev->vfe_base + 0x20);
disable_irq(vfe_dev->vfe_irq->start);
free_irq(vfe_dev->vfe_irq->start, vfe_dev);
tasklet_kill(&vfe_dev->vfe_tasklet);
msm_isp_flush_tasklet(vfe_dev);
iounmap(vfe_dev->vfe_vbif_base);
vfe_dev->vfe_vbif_base = NULL;
iounmap(vfe_dev->vfe_base);
vfe_dev->vfe_base = NULL;
if (vfe_dev->vfe_clk_idx == 1)
msm_cam_clk_enable(&vfe_dev->pdev->dev,
msm_vfe32_1_clk_info, vfe_dev->vfe_clk,
@ -346,9 +326,6 @@ static void msm_vfe32_release_hardware(struct vfe_device *vfe_dev)
msm_cam_clk_enable(&vfe_dev->pdev->dev,
msm_vfe32_2_clk_info, vfe_dev->vfe_clk,
ARRAY_SIZE(msm_vfe32_2_clk_info), 0);
vfe_dev->common_data->dual_vfe_res->vfe_base[vfe_dev->pdev->id] = NULL;
iounmap(vfe_dev->vfe_base);
vfe_dev->vfe_base = NULL;
kfree(vfe_dev->vfe_clk);
regulator_disable(vfe_dev->fs_vfe);
msm_isp_deinit_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id);
@ -369,7 +346,6 @@ static void msm_vfe32_init_hardware_reg(struct vfe_device *vfe_dev)
ds_parms.entries = "ds-entries";
ds_parms.regs = "ds-regs";
ds_parms.settings = "ds-settings";
msm_vfe32_init_qos_parms(vfe_dev, &qos_parms, &ds_parms);
msm_vfe32_init_vbif_parms(vfe_dev, &vbif_parms);
@ -381,6 +357,11 @@ static void msm_vfe32_init_hardware_reg(struct vfe_device *vfe_dev)
msm_camera_io_w_mb(0x1CFFFFFF, vfe_dev->vfe_base + 0x20);
msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x24);
msm_camera_io_w_mb(0x1FFFFFFF, vfe_dev->vfe_base + 0x28);
msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x6FC);
msm_camera_io_w(0x10000000, vfe_dev->vfe_base + VFE32_RDI_BASE(1));
msm_camera_io_w(0x10000000, vfe_dev->vfe_base + VFE32_RDI_BASE(2));
msm_camera_io_w(0x0, vfe_dev->vfe_base + VFE32_XBAR_BASE(0));
msm_camera_io_w(0x0, vfe_dev->vfe_base + VFE32_XBAR_BASE(4));
}
@ -396,13 +377,30 @@ static void msm_vfe32_clear_status_reg(struct vfe_device *vfe_dev)
static void msm_vfe32_process_reset_irq(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1)
{
if (irq_status1 & BIT(23))
if (irq_status1 & BIT(23)) {
if (vfe_dev->vfe_reset_timeout_processed == 1) {
pr_err("%s:vfe reset was processed.\n", __func__);
return;
}
complete(&vfe_dev->reset_complete);
}
}
static void msm_vfe32_process_halt_irq(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1)
{
if (irq_status1 & (1 << 24))
msm_camera_io_w_mb(0, vfe_dev->vfe_base + 0x1D8);
}
static void msm_vfe32_process_epoch_irq(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
struct msm_isp_timestamp *ts)
{
if (!(irq_status0 & 0x18))
return;
if (irq_status0 & (1 << 3))
msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts);
}
static void msm_vfe32_process_camif_irq(struct vfe_device *vfe_dev,
@ -416,10 +414,12 @@ static void msm_vfe32_process_camif_irq(struct vfe_device *vfe_dev,
ISP_DBG("%s: SOF IRQ\n", __func__);
if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0
&& vfe_dev->axi_data.src_info[VFE_PIX_0].
stream_count == 0) {
pix_stream_count == 0) {
msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts);
msm_isp_axi_stream_update(vfe_dev, VFE_PIX_0, ts);
msm_isp_update_framedrop_reg(vfe_dev, VFE_PIX_0);
if (vfe_dev->axi_data.stream_update)
msm_isp_axi_stream_update(vfe_dev,
(1 << VFE_PIX_0));
msm_isp_update_framedrop_reg(vfe_dev, (1 << VFE_PIX_0));
}
}
}
@ -485,7 +485,20 @@ static void msm_vfe32_process_violation_status(struct vfe_device *vfe_dev)
static void msm_vfe32_get_overflow_mask(uint32_t *overflow_mask)
{
*overflow_mask = 0x0;
*overflow_mask = 0x003FFF7E;
}
static void msm_vfe32_get_rdi_wm_mask(struct vfe_device *vfe_dev,
uint32_t *rdi_wm_mask)
{
*rdi_wm_mask = vfe_dev->axi_data.rdi_wm_mask;
}
static void msm_vfe32_get_irq_mask(struct vfe_device *vfe_dev,
uint32_t *irq0_mask, uint32_t *irq1_mask)
{
*irq0_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C);
*irq1_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x20);
}
static void msm_vfe32_process_error_status(struct vfe_device *vfe_dev)
@ -571,7 +584,7 @@ static void msm_vfe32_process_error_status(struct vfe_device *vfe_dev)
pr_err("%s: axi error\n", __func__);
}
static void msm_vfe32_read_and_clear_irq_status(struct vfe_device *vfe_dev,
static void msm_vfe32_read_irq_status(struct vfe_device *vfe_dev,
uint32_t *irq_status0, uint32_t *irq_status1)
{
*irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x2C);
@ -589,122 +602,127 @@ static void msm_vfe32_read_and_clear_irq_status(struct vfe_device *vfe_dev,
msm_camera_io_r(vfe_dev->vfe_base + 0x7B4);
}
static void msm_vfe32_read_irq_status(struct vfe_device *vfe_dev,
uint32_t *irq_status0, uint32_t irq_status1)
{
*irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x2C);
*irq_status1 = msm_camera_io_r(vfe_dev->vfe_base + 0x30);
}
static void msm_vfe32_process_reg_update(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
struct msm_isp_timestamp *ts)
{
uint32_t rdi_status;
enum msm_vfe_input_src i;
uint8_t input_src = 0x0;
if (!(irq_status0 & 0x20) && !(irq_status1 & 0x1C000000))
return;
if (irq_status0 & BIT(5)) {
msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts);
vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev,
VFE_PIX_0);
if (vfe_dev->axi_data.stream_update[VFE_PIX_0]) {
rdi_status = msm_camera_io_r(vfe_dev->vfe_base +
VFE32_XBAR_BASE(0));
rdi_status |= msm_camera_io_r(vfe_dev->vfe_base +
VFE32_XBAR_BASE(4));
if ((rdi_status & BIT(7)) && (!(irq_status0 & 0x20)))
return;
}
msm_isp_process_stats_reg_upd_epoch_irq(vfe_dev,
MSM_ISP_COMP_IRQ_REG_UPD);
msm_isp_notify(vfe_dev, ISP_EVENT_REG_UPDATE, VFE_PIX_0, ts);
input_src |= (1 << VFE_PIX_0);
}
if (irq_status1 & BIT(26)) {
msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_RAW_0, ts);
input_src |= (1 << VFE_RAW_0);
}
if (irq_status1 & BIT(27)) {
msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_RAW_1, ts);
input_src |= (1 << VFE_RAW_1);
}
if (irq_status1 & BIT(28)) {
msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_RAW_2, ts);
input_src |= (1 << VFE_RAW_2);
}
for (i = VFE_RAW_0; i <= VFE_RAW_2; i++) {
if (irq_status1 & BIT(26 + (i - VFE_RAW_0))) {
msm_isp_notify(vfe_dev, ISP_EVENT_SOF, i, ts);
msm_isp_axi_stream_update(vfe_dev, i, ts);
msm_isp_update_framedrop_reg(vfe_dev, i);
vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev,
i);
if (vfe_dev->axi_data.stream_update)
msm_isp_axi_stream_update(vfe_dev, input_src);
if (atomic_read(&vfe_dev->stats_data.stats_update))
msm_isp_stats_stream_update(vfe_dev);
if (vfe_dev->axi_data.stream_update ||
atomic_read(&vfe_dev->stats_data.stats_update)) {
if (input_src & (1 << VFE_PIX_0)) {
vfe_dev->hw_info->vfe_ops.core_ops.
reg_update(vfe_dev, (1 << VFE_PIX_0));
}
}
msm_isp_update_framedrop_reg(vfe_dev, input_src);
msm_isp_update_stats_framedrop_reg(vfe_dev);
msm_isp_update_error_frame_count(vfe_dev);
}
static void msm_vfe32_process_epoch_irq(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
struct msm_isp_timestamp *ts)
{
/* Not supported */
}
static void msm_vfe32_reg_update(struct vfe_device *vfe_dev,
enum msm_vfe_input_src frame_src)
{
if (vfe_dev->is_split && vfe_dev->pdev->id == ISP_VFE1) {
msm_camera_io_w_mb(0xF,
vfe_dev->common_data->dual_vfe_res->vfe_base[ISP_VFE0]
+ 0x260);
msm_camera_io_w_mb(0xF, vfe_dev->vfe_base + 0x260);
} else if (!vfe_dev->is_split) {
msm_camera_io_w_mb(0xF, vfe_dev->vfe_base + 0x260);
if ((input_src & (1 << VFE_RAW_0)) ||
(input_src & (1 << VFE_RAW_1)) ||
(input_src & (1 << VFE_RAW_2))) {
vfe_dev->hw_info->vfe_ops.core_ops.
reg_update(vfe_dev, input_src);
}
return;
}
static void msm_vfe32_reg_update(
struct vfe_device *vfe_dev, uint32_t input_src)
{
msm_camera_io_w_mb(input_src, vfe_dev->vfe_base + 0x260);
}
static long msm_vfe32_reset_hardware(struct vfe_device *vfe_dev,
uint32_t first_start, uint32_t blocking)
{
init_completion(&vfe_dev->reset_complete);
msm_camera_io_w_mb(0x3FF, vfe_dev->vfe_base + 0x4);
return wait_for_completion_timeout(
&vfe_dev->reset_complete, msecs_to_jiffies(50));
long rc = 0;
uint32_t irq_status1;
if (blocking) {
init_completion(&vfe_dev->reset_complete);
msm_camera_io_w_mb(0x3FF, vfe_dev->vfe_base + 0x4);
vfe_dev->vfe_reset_timeout_processed = 0;
rc = wait_for_completion_timeout(
&vfe_dev->reset_complete, msecs_to_jiffies(500));
} else {
msm_camera_io_w_mb(0x3FF, vfe_dev->vfe_base + 0x4);
}
if (blocking && rc <= 0) {
/*read ISP status register*/
irq_status1 = msm_camera_io_r(vfe_dev->vfe_base + 0x30);
pr_err("%s: handling vfe reset time out error. irq_status1 0x%x\n",
__func__, irq_status1);
if (irq_status1 & BIT(23)) {
pr_err("%s: vfe reset has done actually\n", __func__);
vfe_dev->vfe_reset_timeout_processed = 1;
return 1;
}
}
return rc;
}
static void msm_vfe32_axi_reload_wm(
struct vfe_device *vfe_dev, void __iomem *vfe_base,
uint32_t reload_mask)
struct vfe_device *vfe_dev, uint32_t reload_mask)
{
if (!vfe_dev->pdev->dev.of_node) {
/*vfe32 A-family: 8960*/
msm_camera_io_w_mb(reload_mask, vfe_base + 0x38);
msm_camera_io_w_mb(reload_mask, vfe_dev->vfe_base + 0x38);
} else {
/*vfe32 B-family: 8610*/
msm_camera_io_w(0x0, vfe_base + 0x24);
msm_camera_io_w(0x0, vfe_base + 0x28);
msm_camera_io_w(0x0, vfe_base + 0x20);
msm_camera_io_w_mb(0x1, vfe_base + 0x18);
msm_camera_io_w(0x9AAAAAAA, vfe_base + 0x600);
msm_camera_io_w(reload_mask, vfe_base + 0x38);
msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x28);
msm_camera_io_w(0x1C800000, vfe_dev->vfe_base + 0x20);
msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x18);
msm_camera_io_w(0x9AAAAAAA, vfe_dev->vfe_base + 0x600);
msm_camera_io_w(reload_mask, vfe_dev->vfe_base + 0x38);
}
}
static void msm_vfe32_axi_enable_wm(void __iomem *vfe_base,
static void msm_vfe32_axi_enable_wm(struct vfe_device *vfe_dev,
uint8_t wm_idx, uint8_t enable)
{
uint32_t val = msm_camera_io_r(
vfe_base + VFE32_WM_BASE(wm_idx));
vfe_dev->vfe_base + VFE32_WM_BASE(wm_idx));
if (enable)
val |= 0x1;
else
val &= ~0x1;
msm_camera_io_w_mb(val,
vfe_base + VFE32_WM_BASE(wm_idx));
vfe_dev->vfe_base + VFE32_WM_BASE(wm_idx));
}
static void msm_vfe32_axi_cfg_comp_mask(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info)
{
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
uint32_t comp_mask, comp_mask_index =
stream_info->comp_mask_index[vfe_idx];
stream_info->comp_mask_index;
uint32_t irq_mask;
comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x34);
@ -721,9 +739,7 @@ static void msm_vfe32_axi_cfg_comp_mask(struct vfe_device *vfe_dev,
static void msm_vfe32_axi_clear_comp_mask(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info)
{
int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
uint32_t comp_mask, comp_mask_index =
stream_info->comp_mask_index[vfe_idx];
uint32_t comp_mask, comp_mask_index = stream_info->comp_mask_index;
uint32_t irq_mask;
comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x34);
@ -739,10 +755,9 @@ static void msm_vfe32_axi_cfg_wm_irq_mask(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info)
{
uint32_t irq_mask;
int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C);
irq_mask |= BIT(stream_info->wm[vfe_idx][0] + 6);
irq_mask |= BIT(stream_info->wm[0] + 6);
msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C);
}
@ -750,31 +765,40 @@ static void msm_vfe32_axi_clear_wm_irq_mask(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info)
{
uint32_t irq_mask;
int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C);
irq_mask &= ~BIT(stream_info->wm[vfe_idx][0] + 6);
irq_mask &= ~BIT(stream_info->wm[0] + 6);
msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C);
}
static void msm_vfe32_cfg_framedrop(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info, uint32_t framedrop_pattern,
uint32_t framedrop_period)
struct msm_vfe_axi_stream *stream_info)
{
void __iomem *vfe_base = vfe_dev->vfe_base;
uint32_t framedrop_pattern = 0, framedrop_period = 0;
if (stream_info->runtime_init_frame_drop == 0) {
framedrop_pattern = stream_info->framedrop_pattern;
framedrop_period = stream_info->framedrop_period;
}
if (stream_info->stream_type == BURST_STREAM &&
stream_info->runtime_burst_frame_count == 0) {
framedrop_pattern = 0;
framedrop_period = 0;
}
if (stream_info->stream_src == PIX_ENCODER) {
msm_camera_io_w(framedrop_period - 1, vfe_base + 0x504);
msm_camera_io_w(framedrop_period - 1, vfe_base + 0x508);
msm_camera_io_w(framedrop_pattern, vfe_base + 0x50C);
msm_camera_io_w(framedrop_pattern, vfe_base + 0x510);
msm_camera_io_w(framedrop_period, vfe_dev->vfe_base + 0x504);
msm_camera_io_w(framedrop_period, vfe_dev->vfe_base + 0x508);
msm_camera_io_w(framedrop_pattern, vfe_dev->vfe_base + 0x50C);
msm_camera_io_w(framedrop_pattern, vfe_dev->vfe_base + 0x510);
} else if (stream_info->stream_src == PIX_VIEWFINDER) {
msm_camera_io_w(framedrop_period - 1, vfe_base + 0x514);
msm_camera_io_w(framedrop_period - 1, vfe_base + 0x518);
msm_camera_io_w(framedrop_pattern, vfe_base + 0x51C);
msm_camera_io_w(framedrop_pattern, vfe_base + 0x520);
msm_camera_io_w(framedrop_period, vfe_dev->vfe_base + 0x514);
msm_camera_io_w(framedrop_period, vfe_dev->vfe_base + 0x518);
msm_camera_io_w(framedrop_pattern, vfe_dev->vfe_base + 0x51C);
msm_camera_io_w(framedrop_pattern, vfe_dev->vfe_base + 0x520);
}
msm_camera_io_w_mb(0x1, vfe_base + 0x260);
msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x260);
}
static void msm_vfe32_clear_framedrop(struct vfe_device *vfe_dev,
@ -877,6 +901,7 @@ static void msm_vfe32_cfg_fetch_engine(struct vfe_device *vfe_dev,
struct msm_vfe_pix_cfg *pix_cfg)
{
pr_err("%s: Fetch engine not supported\n", __func__);
return;
}
static void msm_vfe32_cfg_camif(struct vfe_device *vfe_dev,
@ -924,6 +949,7 @@ static void msm_vfe32_cfg_input_mux(struct vfe_device *vfe_dev,
pr_err("%s: Unsupported input mux %d\n",
__func__, pix_cfg->input_mux);
}
return;
}
static void msm_vfe32_update_camif_state(
@ -938,19 +964,20 @@ static void msm_vfe32_update_camif_state(
if (update_state == ENABLE_CAMIF) {
val = msm_camera_io_r(vfe_dev->vfe_base + 0x1C);
val |= 0x1;
val |= 0x19;
msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x1C);
msm_camera_io_w_mb(0xA, vfe_dev->vfe_base + 0x200);
val = msm_camera_io_r(vfe_dev->vfe_base + 0x1E4);
bus_en =
((vfe_dev->axi_data.src_info[
VFE_PIX_0].raw_stream_count > 0) ? 1 : 0);
vfe_en =
((vfe_dev->axi_data.src_info[
VFE_PIX_0].stream_count > 0) ? 1 : 0);
VFE_PIX_0].pix_stream_count > 0) ? 1 : 0);
val &= 0xFFFFFF3F;
val = val | bus_en << 7 | vfe_en << 6;
msm_camera_io_w(val, vfe_dev->vfe_base + 0x1E4);
msm_camera_io_w_mb(0x4, vfe_dev->vfe_base + 0x1E0);
msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x1E0);
vfe_dev->axi_data.src_info[VFE_PIX_0].active = 1;
} else if (update_state == DISABLE_CAMIF) {
@ -990,17 +1017,16 @@ static void msm_vfe32_axi_cfg_wm_reg(
uint8_t plane_idx)
{
uint32_t val;
int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
uint32_t wm_base = VFE32_WM_BASE(stream_info->wm[vfe_idx][plane_idx]);
uint32_t wm_base = VFE32_WM_BASE(stream_info->wm[plane_idx]);
if (!stream_info->frame_based) {
/*WR_IMAGE_SIZE*/
val =
((msm_isp_cal_word_per_line(
stream_info->output_format,
stream_info->plane_cfg[vfe_idx][plane_idx].
stream_info->plane_cfg[plane_idx].
output_width)+1)/2 - 1) << 16 |
(stream_info->plane_cfg[vfe_idx][plane_idx].
(stream_info->plane_cfg[plane_idx].
output_height - 1);
msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x10);
@ -1008,9 +1034,9 @@ static void msm_vfe32_axi_cfg_wm_reg(
val =
msm_isp_cal_word_per_line(
stream_info->output_format,
stream_info->plane_cfg[vfe_idx][plane_idx].
stream_info->plane_cfg[plane_idx].
output_stride) << 16 |
(stream_info->plane_cfg[vfe_idx][plane_idx].
(stream_info->plane_cfg[plane_idx].
output_height - 1) << 4 | VFE32_BURST_LEN;
msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14);
} else {
@ -1018,12 +1044,13 @@ static void msm_vfe32_axi_cfg_wm_reg(
val =
msm_isp_cal_word_per_line(
stream_info->output_format,
stream_info->plane_cfg[vfe_idx][plane_idx].
stream_info->plane_cfg[plane_idx].
output_width) << 16 |
(stream_info->plane_cfg[vfe_idx][plane_idx].
(stream_info->plane_cfg[plane_idx].
output_height - 1) << 4 | VFE32_BURST_LEN;
msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14);
}
return;
}
static void msm_vfe32_axi_clear_wm_reg(
@ -1031,22 +1058,24 @@ static void msm_vfe32_axi_clear_wm_reg(
struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx)
{
uint32_t val = 0;
int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
uint32_t wm_base = VFE32_WM_BASE(stream_info->wm[vfe_idx][plane_idx]);
uint32_t wm_base = VFE32_WM_BASE(stream_info->wm[plane_idx]);
/* FRAME BASED */
msm_camera_io_w(val, vfe_dev->vfe_base + wm_base);
/*WR_IMAGE_SIZE*/
msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x10);
/*WR_BUFFER_CFG*/
msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14);
return;
}
static void msm_vfe32_axi_cfg_wm_xbar_reg(
struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx)
{
int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
struct msm_vfe_axi_plane_cfg *plane_cfg =
&stream_info->plane_cfg[vfe_idx][plane_idx];
uint8_t wm = stream_info->wm[vfe_idx][plane_idx];
&stream_info->plane_cfg[plane_idx];
uint8_t wm = stream_info->wm[plane_idx];
uint32_t xbar_cfg = 0;
uint32_t xbar_reg_cfg = 0;
@ -1093,14 +1122,14 @@ static void msm_vfe32_axi_cfg_wm_xbar_reg(
xbar_reg_cfg &= ~(0xFF << VFE32_XBAR_SHIFT(wm));
xbar_reg_cfg |= (xbar_cfg << VFE32_XBAR_SHIFT(wm));
msm_camera_io_w(xbar_reg_cfg, vfe_dev->vfe_base + VFE32_XBAR_BASE(wm));
return;
}
static void msm_vfe32_axi_clear_wm_xbar_reg(
struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx)
{
int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
uint8_t wm = stream_info->wm[vfe_idx][plane_idx];
uint8_t wm = stream_info->wm[plane_idx];
uint32_t xbar_reg_cfg = 0;
xbar_reg_cfg = msm_camera_io_r(vfe_dev->vfe_base + VFE32_XBAR_BASE(wm));
@ -1108,21 +1137,95 @@ static void msm_vfe32_axi_clear_wm_xbar_reg(
msm_camera_io_w(xbar_reg_cfg, vfe_dev->vfe_base + VFE32_XBAR_BASE(wm));
}
static void msm_vfe32_update_ping_pong_addr(void __iomem *vfe_base,
uint8_t wm_idx, uint32_t pingpong_bit, dma_addr_t paddr,
int32_t buf_size)
static void msm_vfe32_cfg_axi_ub_equal_default(struct vfe_device *vfe_dev)
{
int i;
uint32_t ub_offset = 0;
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
uint32_t total_image_size = 0;
uint32_t num_used_wms = 0;
uint32_t prop_size = 0;
uint32_t wm_ub_size;
uint64_t delta;
for (i = 0; i < axi_data->hw_info->num_wm; i++) {
if (axi_data->free_wm[i] > 0) {
num_used_wms++;
total_image_size += axi_data->wm_image_size[i];
}
}
prop_size = MSM_ISP32_TOTAL_WM_UB -
axi_data->hw_info->min_wm_ub * num_used_wms;
for (i = 0; i < axi_data->hw_info->num_wm; i++) {
if (axi_data->free_wm[i]) {
delta =
(uint64_t)(axi_data->wm_image_size[i] *
prop_size);
do_div(delta, total_image_size);
wm_ub_size = axi_data->hw_info->min_wm_ub +
(uint32_t)delta;
msm_camera_io_w(ub_offset << 16 |
(wm_ub_size - 1), vfe_dev->vfe_base +
VFE32_WM_BASE(i) + 0xC);
ub_offset += wm_ub_size;
} else {
msm_camera_io_w(0,
vfe_dev->vfe_base + VFE32_WM_BASE(i) + 0xC);
}
}
}
static void msm_vfe32_cfg_axi_ub_equal_slicing(struct vfe_device *vfe_dev)
{
int i;
uint32_t ub_offset = 0;
uint32_t final_ub_slice_size;
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
for (i = 0; i < axi_data->hw_info->num_wm; i++) {
if (ub_offset + VFE32_EQUAL_SLICE_UB > VFE32_AXI_SLICE_UB) {
final_ub_slice_size = VFE32_AXI_SLICE_UB - ub_offset;
msm_camera_io_w(ub_offset << 16 |
(final_ub_slice_size - 1), vfe_dev->vfe_base +
VFE32_WM_BASE(i) + 0xC);
ub_offset += final_ub_slice_size;
} else {
msm_camera_io_w(ub_offset << 16 |
(VFE32_EQUAL_SLICE_UB - 1), vfe_dev->vfe_base +
VFE32_WM_BASE(i) + 0xC);
ub_offset += VFE32_EQUAL_SLICE_UB;
}
}
}
static void msm_vfe32_cfg_axi_ub(struct vfe_device *vfe_dev)
{
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
axi_data->wm_ub_cfg_policy = MSM_WM_UB_CFG_DEFAULT;
if (axi_data->wm_ub_cfg_policy == MSM_WM_UB_EQUAL_SLICING)
msm_vfe32_cfg_axi_ub_equal_slicing(vfe_dev);
else
msm_vfe32_cfg_axi_ub_equal_default(vfe_dev);
}
static void msm_vfe32_update_ping_pong_addr(struct vfe_device *vfe_dev,
uint8_t wm_idx, uint32_t pingpong_status, dma_addr_t paddr)
{
uint32_t paddr32 = (paddr & 0xFFFFFFFF);
msm_camera_io_w(paddr32, vfe_base +
VFE32_PING_PONG_BASE(wm_idx, pingpong_bit));
msm_camera_io_w(paddr32, vfe_dev->vfe_base +
VFE32_PING_PONG_BASE(wm_idx, pingpong_status));
}
static int msm_vfe32_axi_halt(struct vfe_device *vfe_dev, uint32_t blocking)
{
uint32_t halt_mask;
uint32_t axi_busy_flag = true;
/* Keep only halt and restart mask */
msm_camera_io_w(0x01800000, vfe_dev->vfe_base + 0x20);
/*Clear IRQ Status */
msm_camera_io_w(0xFE7FFFFF, vfe_dev->vfe_base + 0x28);
msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x1D8);
while (axi_busy_flag) {
if (msm_camera_io_r(
@ -1130,10 +1233,27 @@ static int msm_vfe32_axi_halt(struct vfe_device *vfe_dev, uint32_t blocking)
axi_busy_flag = false;
}
msm_camera_io_w_mb(0, vfe_dev->vfe_base + 0x1D8);
halt_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x20);
halt_mask &= 0xFEFFFFFF;
/* Disable AXI IRQ */
msm_camera_io_w_mb(halt_mask, vfe_dev->vfe_base + 0x20);
return 0;
}
static int msm_vfe32_axi_restart(struct vfe_device *vfe_dev,
uint32_t blocking, uint32_t enable_camif)
{
vfe_dev->hw_info->vfe_ops.core_ops.restore_irq_mask(vfe_dev);
/*Clear IRQ Status */
msm_camera_io_w(0xFE7FFFFF, vfe_dev->vfe_base + 0x28);
msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x1D8);
msm_camera_io_w_mb(0xA, vfe_dev->vfe_base + 0x200);
/* Start AXI */
msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x1D8);
vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev, 0xF);
memset(&vfe_dev->error_info, 0, sizeof(vfe_dev->error_info));
atomic_set(&vfe_dev->error_info.overflow_state, NO_OVERFLOW);
if (enable_camif) {
vfe_dev->hw_info->vfe_ops.core_ops.
update_camif_state(vfe_dev, ENABLE_CAMIF);
}
return 0;
}
@ -1187,20 +1307,36 @@ static int msm_vfe32_stats_check_streams(
}
static void msm_vfe32_stats_cfg_comp_mask(struct vfe_device *vfe_dev,
uint32_t stats_mask, uint8_t comp_idx, uint8_t enable)
uint32_t stats_mask, uint8_t enable)
{
uint32_t i = 0;
atomic_t *stats_comp;
struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
stats_mask = stats_mask & 0x7F;
for (i = 0;
i < vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask; i++) {
stats_comp = &stats_data->stats_comp_mask[i];
if (enable)
atomic_add(stats_mask, stats_comp);
else
atomic_sub(stats_mask, stats_comp);
ISP_DBG("%s: comp_mask: %x\n",
__func__, atomic_read(&stats_data->stats_comp_mask[i]));
}
return;
}
static void msm_vfe32_stats_cfg_wm_irq_mask(struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info)
{
int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev,
stream_info);
uint32_t irq_mask;
irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C);
irq_mask |= BIT(STATS_IDX(stream_info->stream_handle[vfe_idx]) + 13);
irq_mask |= BIT(STATS_IDX(stream_info->stream_handle) + 13);
msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C);
return;
}
static void msm_vfe32_stats_clear_wm_irq_mask(struct vfe_device *vfe_dev,
@ -1211,18 +1347,21 @@ static void msm_vfe32_stats_clear_wm_irq_mask(struct vfe_device *vfe_dev,
irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C);
irq_mask &= ~(BIT(STATS_IDX(stream_info->stream_handle) + 13));
msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C);
return;
}
static void msm_vfe32_stats_cfg_wm_reg(struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info)
{
/*Nothing to configure for VFE3.x*/
return;
}
static void msm_vfe32_stats_clear_wm_reg(struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info)
{
/*Nothing to configure for VFE3.x*/
return;
}
static void msm_vfe32_stats_cfg_ub(struct vfe_device *vfe_dev)
@ -1247,12 +1386,7 @@ static void msm_vfe32_stats_cfg_ub(struct vfe_device *vfe_dev)
msm_camera_io_w(ub_offset << 16 | (ub_size[i] - 1),
vfe_dev->vfe_base + VFE32_STATS_BASE(i) + 0x8);
}
}
static bool msm_vfe32_is_module_cfg_lock_needed(
uint32_t reg_offset)
{
return false;
return;
}
static void msm_vfe32_stats_enable_module(struct vfe_device *vfe_dev,
@ -1294,15 +1428,13 @@ static void msm_vfe32_stats_enable_module(struct vfe_device *vfe_dev,
static void msm_vfe32_stats_update_ping_pong_addr(struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info, uint32_t pingpong_status,
dma_addr_t paddr, uint32_t buf_sz)
dma_addr_t paddr)
{
void __iomem *vfe_base = vfe_dev->vfe_base;
int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev,
stream_info);
uint32_t paddr32 = (paddr & 0xFFFFFFFF);
int stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]);
msm_camera_io_w(paddr32, vfe_base +
int stats_idx = STATS_IDX(stream_info->stream_handle);
msm_camera_io_w(paddr32, vfe_dev->vfe_base +
VFE32_STATS_PING_PONG_BASE(stats_idx, pingpong_status));
}
@ -1361,28 +1493,6 @@ static int msm_vfe32_get_platform_data(struct vfe_device *vfe_dev)
goto vfe_no_resource;
}
if (!vfe_dev->pdev->dev.of_node)
vfe_dev->iommu_ctx[0] = msm_iommu_get_ctx("vfe_imgwr");
else
vfe_dev->iommu_ctx[0] = msm_iommu_get_ctx("vfe");
if (!vfe_dev->iommu_ctx[0]) {
pr_err("%s: no iommux ctx resource?\n", __func__);
rc = -ENODEV;
goto vfe_no_resource;
}
if (!vfe_dev->pdev->dev.of_node)
vfe_dev->iommu_ctx[1] = msm_iommu_get_ctx("vfe_misc");
else
vfe_dev->iommu_ctx[1] = msm_iommu_get_ctx("vfe");
if (!vfe_dev->iommu_ctx[1]) {
pr_err("%s: no iommux ctx resource?\n", __func__);
rc = -ENODEV;
goto vfe_no_resource;
}
vfe_no_resource:
return rc;
}
@ -1394,13 +1504,27 @@ static void msm_vfe32_get_error_mask(uint32_t *error_mask0,
*error_mask1 = 0x007FFFFF;
}
struct msm_vfe_axi_hardware_info msm_vfe32_axi_hw_info = {
.num_wm = 5,
static void msm_vfe32_restore_irq_mask(struct vfe_device *vfe_dev)
{
msm_camera_io_w(vfe_dev->error_info.overflow_recover_irq_mask0,
vfe_dev->vfe_base + 0x1C);
msm_camera_io_w(vfe_dev->error_info.overflow_recover_irq_mask1,
vfe_dev->vfe_base + 0x20);
}
static void msm_vfe32_get_halt_restart_mask(uint32_t *irq0_mask,
uint32_t *irq1_mask)
{
*irq1_mask = 0x01800000;
}
static struct msm_vfe_axi_hardware_info msm_vfe32_axi_hw_info = {
.num_wm = 6,
.num_comp_mask = 3,
.num_rdi = 3,
.num_rdi_master = 3,
.min_wm_ub = 64,
.scratch_buf_range = SZ_32M,
};
static struct msm_vfe_stats_hardware_info msm_vfe32_stats_hw_info = {
@ -1412,7 +1536,22 @@ static struct msm_vfe_stats_hardware_info msm_vfe32_stats_hw_info = {
1 << MSM_ISP_STATS_SKIN | 1 << MSM_ISP_STATS_BHIST,
.stats_ping_pong_offset = stats_pingpong_offset_map,
.num_stats_type = VFE32_NUM_STATS_TYPE,
.num_stats_comp_mask = 0,
.num_stats_comp_mask = 1,
};
static struct v4l2_subdev_core_ops msm_vfe32_subdev_core_ops = {
.ioctl = msm_isp_ioctl,
.subscribe_event = msm_isp_subscribe_event,
.unsubscribe_event = msm_isp_unsubscribe_event,
};
static struct v4l2_subdev_ops msm_vfe32_subdev_ops = {
.core = &msm_vfe32_subdev_core_ops,
};
static struct v4l2_subdev_internal_ops msm_vfe32_internal_ops = {
.open = msm_isp_open_node,
.close = msm_isp_close_node,
};
struct msm_vfe_hardware_info vfe32_hw_info = {
@ -1421,16 +1560,14 @@ struct msm_vfe_hardware_info vfe32_hw_info = {
.vfe_clk_idx = VFE32_CLK_IDX,
.vfe_ops = {
.irq_ops = {
.read_and_clear_irq_status =
msm_vfe32_read_and_clear_irq_status,
.read_irq_status = msm_vfe32_read_irq_status,
.process_camif_irq = msm_vfe32_process_camif_irq,
.process_reset_irq = msm_vfe32_process_reset_irq,
.process_halt_irq = msm_vfe32_process_halt_irq,
.process_reg_update = msm_vfe32_process_reg_update,
.process_epoch_irq = msm_vfe32_process_epoch_irq,
.process_axi_irq = msm_isp_process_axi_irq,
.process_stats_irq = msm_isp_process_stats_irq,
.process_epoch_irq = msm_vfe32_process_epoch_irq,
},
.axi_ops = {
.reload_wm = msm_vfe32_axi_reload_wm,
@ -1446,15 +1583,14 @@ struct msm_vfe_hardware_info vfe32_hw_info = {
.clear_wm_reg = msm_vfe32_axi_clear_wm_reg,
.cfg_wm_xbar_reg = msm_vfe32_axi_cfg_wm_xbar_reg,
.clear_wm_xbar_reg = msm_vfe32_axi_clear_wm_xbar_reg,
.cfg_ub = msm_vfe47_cfg_axi_ub,
.cfg_ub = msm_vfe32_cfg_axi_ub,
.update_ping_pong_addr =
msm_vfe32_update_ping_pong_addr,
.get_comp_mask = msm_vfe32_get_comp_mask,
.get_wm_mask = msm_vfe32_get_wm_mask,
.get_pingpong_status = msm_vfe32_get_pingpong_status,
.halt = msm_vfe32_axi_halt,
.ub_reg_offset = msm_vfe40_ub_reg_offset,
.get_ub_size = msm_vfe40_get_ub_size,
.restart = msm_vfe32_axi_restart,
},
.core_ops = {
.reg_update = msm_vfe32_reg_update,
@ -1469,13 +1605,13 @@ struct msm_vfe_hardware_info vfe32_hw_info = {
.release_hw = msm_vfe32_release_hardware,
.get_platform_data = msm_vfe32_get_platform_data,
.get_error_mask = msm_vfe32_get_error_mask,
.process_error_status = msm_vfe32_process_error_status,
.get_overflow_mask = msm_vfe32_get_overflow_mask,
.is_module_cfg_lock_needed =
msm_vfe32_is_module_cfg_lock_needed,
.ahb_clk_cfg = NULL,
.set_bus_err_ign_mask = NULL,
.get_bus_err_mask = NULL,
.get_rdi_wm_mask = msm_vfe32_get_rdi_wm_mask,
.get_irq_mask = msm_vfe32_get_irq_mask,
.restore_irq_mask = msm_vfe32_restore_irq_mask,
.get_halt_restart_mask =
msm_vfe32_get_halt_restart_mask,
.process_error_status = msm_vfe32_process_error_status,
},
.stats_ops = {
.get_stats_idx = msm_vfe32_get_stats_idx,
@ -1493,47 +1629,12 @@ struct msm_vfe_hardware_info vfe32_hw_info = {
.get_wm_mask = msm_vfe32_stats_get_wm_mask,
.get_frame_id = msm_vfe32_stats_get_frame_id,
.get_pingpong_status = msm_vfe32_get_pingpong_status,
.enable_stats_wm = NULL,
},
},
.dmi_reg_offset = 0x5A0,
.axi_hw_info = &msm_vfe32_axi_hw_info,
.stats_hw_info = &msm_vfe32_stats_hw_info,
.subdev_ops = &msm_vfe32_subdev_ops,
.subdev_internal_ops = &msm_vfe32_internal_ops,
};
EXPORT_SYMBOL(vfe32_hw_info);
static const struct of_device_id msm_vfe32_dt_match[] = {
{
.compatible = "qcom,vfe32",
.data = &vfe32_hw_info,
},
{}
};
MODULE_DEVICE_TABLE(of, msm_vfe32_dt_match);
static struct platform_driver vfe32_driver = {
.probe = vfe_hw_probe,
.driver = {
.name = "msm_vfe32",
.owner = THIS_MODULE,
.of_match_table = msm_vfe32_dt_match,
},
.id_table = msm_vfe32_dev_id,
};
static int __init msm_vfe32_init_module(void)
{
return platform_driver_register(&vfe32_driver);
}
static void __exit msm_vfe32_exit_module(void)
{
platform_driver_unregister(&vfe32_driver);
}
module_init(msm_vfe32_init_module);
module_exit(msm_vfe32_exit_module);
MODULE_DESCRIPTION("MSM VFE32 driver");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,557 @@
/* 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
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/debugfs.h>
#include <linux/videodev2.h>
#include <linux/of_device.h>
#include <linux/sched_clock.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-event.h>
#include "msm_isp_32.h"
#include "msm_isp_util_32.h"
#include "msm_isp_axi_util_32.h"
#include "msm_isp_stats_util_32.h"
#include "msm_sd.h"
#include "msm_isp32.h"
static struct msm_sd_req_vb2_q vfe_vb2_ops;
static const struct of_device_id msm_vfe_dt_match[] = {
{
.compatible = "qcom,vfe32",
.data = &vfe32_hw_info,
},
{}
};
MODULE_DEVICE_TABLE(of, msm_vfe_dt_match);
static const struct platform_device_id msm_vfe_dev_id[] = {
{"msm_vfe32", (kernel_ulong_t) &vfe32_hw_info},
{}
};
#define MAX_OVERFLOW_COUNTERS 29
#define OVERFLOW_LENGTH 1024
#define OVERFLOW_BUFFER_LENGTH 64
static char stat_line[OVERFLOW_LENGTH];
static struct msm_isp_buf_mgr vfe_buf_mgr;
static int msm_isp_enable_debugfs(struct vfe_device *vfe_dev,
struct msm_isp_bw_req_info *isp_req_hist);
static char *stats_str[MAX_OVERFLOW_COUNTERS] = {
"imgmaster0_overflow_cnt",
"imgmaster1_overflow_cnt",
"imgmaster2_overflow_cnt",
"imgmaster3_overflow_cnt",
"imgmaster4_overflow_cnt",
"imgmaster5_overflow_cnt",
"imgmaster6_overflow_cnt",
"be_overflow_cnt",
"bg_overflow_cnt",
"bf_overflow_cnt",
"awb_overflow_cnt",
"rs_overflow_cnt",
"cs_overflow_cnt",
"ihist_overflow_cnt",
"skinbhist_overflow_cnt",
"bfscale_overflow_cnt",
"ISP_VFE0_client_info.active",
"ISP_VFE0_client_info.ab",
"ISP_VFE0_client_info.ib",
"ISP_VFE1_client_info.active",
"ISP_VFE1_client_info.ab",
"ISP_VFE1_client_info.ib",
"ISP_CPP_client_info.active",
"ISP_CPP_client_info.ab",
"ISP_CPP_client_info.ib",
"ISP_last_overflow.ab",
"ISP_last_overflow.ib",
"ISP_VFE_CLK_RATE",
"ISP_CPP_CLK_RATE",
};
#define MAX_DEPTH_BW_REQ_HISTORY 25
#define MAX_BW_HISTORY_BUFF_LEN 6144
#define MAX_BW_HISTORY_LINE_BUFF_LEN 512
#define MAX_UB_INFO_BUFF_LEN 1024
#define MAX_UB_INFO_LINE_BUFF_LEN 256
static struct msm_isp_bw_req_info
msm_isp_bw_request_history[MAX_DEPTH_BW_REQ_HISTORY];
static int msm_isp_bw_request_history_idx;
static char bw_request_history_buff[MAX_BW_HISTORY_BUFF_LEN];
static char ub_info_buffer[MAX_UB_INFO_BUFF_LEN];
static spinlock_t req_history_lock;
static int vfe_debugfs_statistics_open(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
return 0;
}
static ssize_t vfe_debugfs_statistics_read(struct file *t_file,
char __user *t_char, size_t t_size_t, loff_t *t_loff_t)
{
int i;
uint64_t *ptr;
char buffer[OVERFLOW_BUFFER_LENGTH] = {0};
struct vfe_device *vfe_dev = (struct vfe_device *)
t_file->private_data;
struct msm_isp_statistics *stats = vfe_dev->stats;
memset(stat_line, 0, sizeof(stat_line));
msm_isp_util_get_bandwidth_stats(vfe_dev, stats);
ptr = (uint64_t *)(stats);
for (i = 0; i < MAX_OVERFLOW_COUNTERS; i++) {
strlcat(stat_line, stats_str[i], sizeof(stat_line));
strlcat(stat_line, " ", sizeof(stat_line));
snprintf(buffer, sizeof(buffer), "%llu", ptr[i]);
strlcat(stat_line, buffer, sizeof(stat_line));
strlcat(stat_line, "\r\n", sizeof(stat_line));
}
return simple_read_from_buffer(t_char, t_size_t,
t_loff_t, stat_line, strlen(stat_line));
}
static ssize_t vfe_debugfs_statistics_write(struct file *t_file,
const char __user *t_char, size_t t_size_t, loff_t *t_loff_t)
{
struct vfe_device *vfe_dev = (struct vfe_device *)
t_file->private_data;
struct msm_isp_statistics *stats = vfe_dev->stats;
memset(stats, 0, sizeof(struct msm_isp_statistics));
return sizeof(struct msm_isp_statistics);
}
static int bw_history_open(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
return 0;
}
static ssize_t bw_history_read(struct file *t_file, char __user *t_char,
size_t t_size_t, loff_t *t_loff_t)
{
int i;
char *out_buffer = bw_request_history_buff;
char line_buffer[MAX_BW_HISTORY_LINE_BUFF_LEN] = {0};
struct msm_isp_bw_req_info *isp_req_hist =
(struct msm_isp_bw_req_info *) t_file->private_data;
memset(out_buffer, 0, MAX_BW_HISTORY_BUFF_LEN);
snprintf(line_buffer, sizeof(line_buffer),
"Bus bandwidth request history in chronological order:\n");
strlcat(out_buffer, line_buffer, sizeof(bw_request_history_buff));
snprintf(line_buffer, sizeof(line_buffer),
"MSM_ISP_MIN_AB = %u, MSM_ISP_MIN_IB = %u\n\n",
MSM_ISP_MIN_AB, MSM_ISP_MIN_IB);
strlcat(out_buffer, line_buffer, sizeof(bw_request_history_buff));
for (i = 0; i < MAX_DEPTH_BW_REQ_HISTORY; i++) {
snprintf(line_buffer, sizeof(line_buffer),
"idx = %d, client = %u, timestamp = %llu, ab = %llu, ib = %llu\n"
"ISP0.active = %x, ISP0.ab = %llu, ISP0.ib = %llu\n"
"ISP1.active = %x, ISP1.ab = %llu, ISP1.ib = %llu\n"
"CPP.active = %x, CPP.ab = %llu, CPP.ib = %llu\n\n",
i, isp_req_hist[i].client, isp_req_hist[i].timestamp,
isp_req_hist[i].total_ab, isp_req_hist[i].total_ib,
isp_req_hist[i].client_info[0].active,
isp_req_hist[i].client_info[0].ab,
isp_req_hist[i].client_info[0].ib,
isp_req_hist[i].client_info[1].active,
isp_req_hist[i].client_info[1].ab,
isp_req_hist[i].client_info[1].ib,
isp_req_hist[i].client_info[2].active,
isp_req_hist[i].client_info[2].ab,
isp_req_hist[i].client_info[2].ib);
strlcat(out_buffer, line_buffer,
sizeof(bw_request_history_buff));
}
return simple_read_from_buffer(t_char, t_size_t,
t_loff_t, out_buffer, strlen(out_buffer));
}
static ssize_t bw_history_write(struct file *t_file,
const char __user *t_char, size_t t_size_t, loff_t *t_loff_t)
{
struct msm_isp_bw_req_info *isp_req_hist =
(struct msm_isp_bw_req_info *) t_file->private_data;
memset(isp_req_hist, 0, sizeof(msm_isp_bw_request_history));
msm_isp_bw_request_history_idx = 0;
return sizeof(msm_isp_bw_request_history);
}
static int ub_info_open(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
return 0;
}
static ssize_t ub_info_read(struct file *t_file, char __user *t_char,
size_t t_size_t, loff_t *t_loff_t)
{
int i;
char *out_buffer = ub_info_buffer;
char line_buffer[MAX_UB_INFO_LINE_BUFF_LEN] = {0};
struct vfe_device *vfe_dev =
(struct vfe_device *) t_file->private_data;
struct msm_isp_ub_info *ub_info = vfe_dev->ub_info;
memset(out_buffer, 0, MAX_UB_INFO_LINE_BUFF_LEN);
snprintf(line_buffer, sizeof(line_buffer),
"wm_ub_policy_type = %d\n"
"num_wm = %d\n"
"wm_ub = %d\n",
ub_info->policy, ub_info->num_wm, ub_info->wm_ub);
strlcat(out_buffer, line_buffer,
sizeof(ub_info_buffer));
for (i = 0; i < ub_info->num_wm; i++) {
snprintf(line_buffer, sizeof(line_buffer),
"data[%d] = 0x%x, addr[%d] = 0x%llx\n",
i, ub_info->data[i], i, ub_info->addr[i]);
strlcat(out_buffer, line_buffer,
sizeof(ub_info_buffer));
}
return simple_read_from_buffer(t_char, t_size_t,
t_loff_t, out_buffer, strlen(out_buffer));
}
static ssize_t ub_info_write(struct file *t_file,
const char __user *t_char, size_t t_size_t, loff_t *t_loff_t)
{
struct vfe_device *vfe_dev =
(struct vfe_device *) t_file->private_data;
struct msm_isp_ub_info *ub_info = vfe_dev->ub_info;
memset(ub_info, 0, sizeof(struct msm_isp_ub_info));
return sizeof(struct msm_isp_ub_info);
}
static const struct file_operations vfe_debugfs_error = {
.open = vfe_debugfs_statistics_open,
.read = vfe_debugfs_statistics_read,
.write = vfe_debugfs_statistics_write,
};
static const struct file_operations bw_history_ops = {
.open = bw_history_open,
.read = bw_history_read,
.write = bw_history_write,
};
static const struct file_operations ub_info_ops = {
.open = ub_info_open,
.read = ub_info_read,
.write = ub_info_write,
};
static int msm_isp_enable_debugfs(struct vfe_device *vfe_dev,
struct msm_isp_bw_req_info *isp_req_hist)
{
struct dentry *debugfs_base;
char dirname[32] = {0};
snprintf(dirname, sizeof(dirname), "msm_isp%d", vfe_dev->pdev->id);
debugfs_base = debugfs_create_dir(dirname, NULL);
if (!debugfs_base)
return -ENOMEM;
if (!debugfs_create_file("stats", 0644, debugfs_base,
vfe_dev, &vfe_debugfs_error))
return -ENOMEM;
if (!debugfs_create_file("bw_req_history", 0644,
debugfs_base, isp_req_hist, &bw_history_ops))
return -ENOMEM;
if (!debugfs_create_file("ub_info", 0644,
debugfs_base, vfe_dev, &ub_info_ops))
return -ENOMEM;
return 0;
}
void msm_isp_update_req_history(uint32_t client, uint64_t ab,
uint64_t ib,
struct msm_isp_bandwidth_info *client_info,
unsigned long long ts)
{
int i;
spin_lock(&req_history_lock);
msm_isp_bw_request_history[msm_isp_bw_request_history_idx].client =
client;
msm_isp_bw_request_history[msm_isp_bw_request_history_idx].timestamp =
ts;
msm_isp_bw_request_history[msm_isp_bw_request_history_idx].total_ab =
ab;
msm_isp_bw_request_history[msm_isp_bw_request_history_idx].total_ib =
ib;
for (i = 0; i < MAX_ISP_CLIENT; i++) {
msm_isp_bw_request_history[msm_isp_bw_request_history_idx].
client_info[i].active = client_info[i].active;
msm_isp_bw_request_history[msm_isp_bw_request_history_idx].
client_info[i].ab = client_info[i].ab;
msm_isp_bw_request_history[msm_isp_bw_request_history_idx].
client_info[i].ib = client_info[i].ib;
}
msm_isp_bw_request_history_idx = (msm_isp_bw_request_history_idx + 1)
% MAX_DEPTH_BW_REQ_HISTORY;
spin_unlock(&req_history_lock);
}
#ifdef CONFIG_COMPAT
static long msm_isp_dqevent(struct file *file, struct v4l2_fh *vfh, void *arg)
{
long rc;
if (is_compat_task()) {
struct msm_isp32_event_data32 *event_data32;
struct msm_isp32_event_data *event_data;
struct v4l2_event isp_event;
struct v4l2_event *isp_event_user;
memset(&isp_event, 0, sizeof(isp_event));
rc = v4l2_event_dequeue(vfh, &isp_event,
file->f_flags & O_NONBLOCK);
if (rc)
return rc;
event_data = (struct msm_isp32_event_data *)
isp_event.u.data;
isp_event_user = (struct v4l2_event *)arg;
memcpy(isp_event_user, &isp_event,
sizeof(*isp_event_user));
event_data32 = (struct msm_isp32_event_data32 *)
isp_event_user->u.data;
memset(event_data32, 0,
sizeof(struct msm_isp32_event_data32));
event_data32->timestamp.tv_sec =
event_data->timestamp.tv_sec;
event_data32->timestamp.tv_usec =
event_data->timestamp.tv_usec;
event_data32->mono_timestamp.tv_sec =
event_data->mono_timestamp.tv_sec;
event_data32->mono_timestamp.tv_usec =
event_data->mono_timestamp.tv_usec;
event_data32->input_intf = event_data->input_intf;
event_data32->frame_id = event_data->frame_id;
memcpy(&(event_data32->u), &(event_data->u),
sizeof(event_data32->u));
} else {
rc = v4l2_event_dequeue(vfh, arg,
file->f_flags & O_NONBLOCK);
}
return rc;
}
#else
static long msm_isp_dqevent(struct file *file, struct v4l2_fh *vfh, void *arg)
{
return v4l2_event_dequeue(vfh, arg,
file->f_flags & O_NONBLOCK);
}
#endif
static long msm_isp_subdev_do_ioctl(
struct file *file, unsigned int cmd, void *arg)
{
struct video_device *vdev = video_devdata(file);
struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
struct v4l2_fh *vfh = file->private_data;
switch (cmd) {
case VIDIOC_DQEVENT: {
if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
return -ENOIOCTLCMD;
return msm_isp_dqevent(file, vfh, arg);
}
break;
case VIDIOC_SUBSCRIBE_EVENT:
return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg);
case VIDIOC_UNSUBSCRIBE_EVENT:
return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg);
default:
return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
}
}
static long msm_isp_subdev_fops_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
return video_usercopy(file, cmd, arg, msm_isp_subdev_do_ioctl);
}
static struct v4l2_file_operations msm_isp_v4l2_subdev_fops = {
#ifdef CONFIG_COMPAT
.compat_ioctl32 = msm_isp_subdev_fops_ioctl,
#endif
.unlocked_ioctl = msm_isp_subdev_fops_ioctl
};
static int vfe_probe(struct platform_device *pdev)
{
struct vfe_device *vfe_dev;
/*struct msm_cam_subdev_info sd_info;*/
const struct of_device_id *match_dev;
int rc = 0;
vfe_dev = kzalloc(sizeof(struct vfe_device), GFP_KERNEL);
if (!vfe_dev) {
rc = -ENOMEM;
goto end;
}
vfe_dev->stats = kzalloc(sizeof(struct msm_isp_statistics), GFP_KERNEL);
if (!vfe_dev->stats) {
rc = -ENOMEM;
goto probe_fail1;
}
vfe_dev->ub_info = kzalloc(sizeof(struct msm_isp_ub_info), GFP_KERNEL);
if (!vfe_dev->ub_info) {
rc = -ENOMEM;
goto probe_fail2;
}
if (pdev->dev.of_node) {
of_property_read_u32((&pdev->dev)->of_node,
"cell-index", &pdev->id);
match_dev = of_match_device(msm_vfe_dt_match, &pdev->dev);
if (!match_dev) {
pr_err("%s: No vfe hardware info\n", __func__);
rc = -EINVAL;
goto probe_fail3;
}
vfe_dev->hw_info =
(struct msm_vfe_hardware_info *) match_dev->data;
} else {
vfe_dev->hw_info = (struct msm_vfe_hardware_info *)
platform_get_device_id(pdev)->driver_data;
}
if (!vfe_dev->hw_info) {
pr_err("%s: No vfe hardware info\n", __func__);
rc = -EINVAL;
goto probe_fail3;
}
ISP_DBG("%s: device id = %d\n", __func__, pdev->id);
vfe_dev->pdev = pdev;
rc = vfe_dev->hw_info->vfe_ops.core_ops.get_platform_data(vfe_dev);
if (rc < 0) {
pr_err("%s: failed to get platform resources\n", __func__);
rc = -ENOMEM;
goto probe_fail3;
}
INIT_LIST_HEAD(&vfe_dev->tasklet_q);
tasklet_init(&vfe_dev->vfe_tasklet,
msm_isp_do_tasklet, (unsigned long)vfe_dev);
v4l2_subdev_init(&vfe_dev->subdev.sd, vfe_dev->hw_info->subdev_ops);
vfe_dev->subdev.sd.internal_ops =
vfe_dev->hw_info->subdev_internal_ops;
snprintf(vfe_dev->subdev.sd.name,
ARRAY_SIZE(vfe_dev->subdev.sd.name),
"vfe");
vfe_dev->subdev.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
vfe_dev->subdev.sd.flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
v4l2_set_subdevdata(&vfe_dev->subdev.sd, vfe_dev);
platform_set_drvdata(pdev, &vfe_dev->subdev.sd);
mutex_init(&vfe_dev->realtime_mutex);
mutex_init(&vfe_dev->core_mutex);
spin_lock_init(&vfe_dev->tasklet_lock);
spin_lock_init(&vfe_dev->shared_data_lock);
spin_lock_init(&req_history_lock);
media_entity_pads_init(&vfe_dev->subdev.sd.entity, 0, NULL);
vfe_dev->subdev.sd.entity.function = MSM_CAMERA_SUBDEV_VFE;
vfe_dev->subdev.sd.entity.name = pdev->name;
vfe_dev->subdev.close_seq = MSM_SD_CLOSE_1ST_CATEGORY | 0x2;
rc = msm_sd_register(&vfe_dev->subdev);
if (rc != 0) {
pr_err("%s: msm_sd_register error = %d\n", __func__, rc);
goto probe_fail3;
}
msm_isp_v4l2_subdev_fops.owner = v4l2_subdev_fops.owner;
msm_isp_v4l2_subdev_fops.open = v4l2_subdev_fops.open;
msm_isp_v4l2_subdev_fops.release = v4l2_subdev_fops.release;
msm_isp_v4l2_subdev_fops.poll = v4l2_subdev_fops.poll;
vfe_dev->subdev.sd.devnode->fops = &msm_isp_v4l2_subdev_fops;
vfe_dev->buf_mgr = &vfe_buf_mgr;
v4l2_subdev_notify(&vfe_dev->subdev.sd,
MSM_SD_NOTIFY_REQ_CB, &vfe_vb2_ops);
rc = msm_isp_create_isp_buf_mgr(vfe_dev->buf_mgr,
&vfe_vb2_ops, &pdev->dev,
vfe_dev->hw_info->axi_hw_info->scratch_buf_range);
if (rc < 0) {
pr_err("%s: Unable to create buffer manager\n", __func__);
rc = -EINVAL;
goto probe_fail3;
}
msm_isp_enable_debugfs(vfe_dev, msm_isp_bw_request_history);
vfe_dev->buf_mgr->init_done = 1;
vfe_dev->vfe_open_cnt = 0;
return rc;
probe_fail3:
kfree(vfe_dev->ub_info);
probe_fail2:
kfree(vfe_dev->stats);
probe_fail1:
kfree(vfe_dev);
end:
return rc;
}
static struct platform_driver vfe_driver = {
.probe = vfe_probe,
.driver = {
.name = "msm_vfe",
.owner = THIS_MODULE,
.of_match_table = msm_vfe_dt_match,
},
.id_table = msm_vfe_dev_id,
};
static int __init msm_vfe_init_module(void)
{
return platform_driver_register(&vfe_driver);
}
static void __exit msm_vfe_exit_module(void)
{
platform_driver_unregister(&vfe_driver);
}
module_init(msm_vfe_init_module);
module_exit(msm_vfe_exit_module);
MODULE_DESCRIPTION("MSM VFE driver");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,599 @@
/* 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
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __MSM_VFE_H__
#define __MSM_VFE_H__
#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/completion.h>
#include <linux/io.h>
#include <linux/list.h>
#include <linux/delay.h>
#include <media/v4l2-subdev.h>
#include <media/msmb_isp.h>
#include <linux/msm-bus.h>
#include <linux/msm-bus-board.h>
#include "msm_buf_mgr.h"
#define VFE40_8974V1_VERSION 0x10000018
#define VFE40_8974V2_VERSION 0x1001001A
#define VFE40_8974V3_VERSION 0x1001001B
#define VFE40_8x26_VERSION 0x20000013
#define VFE40_8x26V2_VERSION 0x20010014
#define VFE40_8916_VERSION 0x10030000
#define VFE40_8939_VERSION 0x10040000
#define VFE32_8909_VERSION 0x30600
#define MAX_IOMMU_CTX 2
#define MAX_NUM_WM 7
#define MAX_NUM_RDI 3
#define MAX_NUM_RDI_MASTER 3
#define MAX_NUM_COMPOSITE_MASK 4
#define MAX_NUM_STATS_COMP_MASK 2
#define MAX_INIT_FRAME_DROP 31
#define ISP_Q2 (1 << 2)
#define ISP_Q10 (1 << 10)
#define VFE_PING_FLAG 0xFFFFFFFF
#define VFE_PONG_FLAG 0x0
#define VFE_MAX_CFG_TIMEOUT 3000
#define VFE_CLK_INFO_MAX 16
#define STATS_COMP_BIT_MASK 0xFF0000
#define MSM_ISP_MIN_AB 11000000
#define MSM_ISP_MIN_IB 11000000
struct vfe_device;
struct msm_vfe_axi_stream;
struct msm_vfe_stats_stream;
struct vfe_subscribe_info {
struct v4l2_fh *vfh;
uint32_t active;
};
enum msm_isp_pack_fmt {
QCOM,
MIPI,
DPCM6,
DPCM8,
PLAIN8,
PLAIN16,
MAX_ISP_PACK_FMT,
};
enum msm_isp_camif_update_state {
NO_UPDATE,
ENABLE_CAMIF,
DISABLE_CAMIF,
DISABLE_CAMIF_IMMEDIATELY
};
struct msm_isp_timestamp {
/*Monotonic clock for v4l2 buffer*/
struct timeval buf_time;
/*Monotonic clock for VT */
struct timeval vt_time;
/*Wall clock for userspace event*/
struct timeval event_time;
};
struct msm_vfe_irq_ops {
void (*read_irq_status)(struct vfe_device *vfe_dev,
uint32_t *irq_status0, uint32_t *irq_status1);
void (*process_reg_update)(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
struct msm_isp_timestamp *ts);
void (*process_epoch_irq)(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
struct msm_isp_timestamp *ts);
void (*process_reset_irq)(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1);
void (*process_halt_irq)(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1);
void (*process_camif_irq)(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
struct msm_isp_timestamp *ts);
void (*process_axi_irq)(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
struct msm_isp_timestamp *ts);
void (*process_stats_irq)(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
struct msm_isp_timestamp *ts);
};
struct msm_vfe_axi_ops {
void (*reload_wm)(struct vfe_device *vfe_dev,
uint32_t reload_mask);
void (*enable_wm)(struct vfe_device *vfe_dev,
uint8_t wm_idx, uint8_t enable);
int32_t (*cfg_io_format)(struct vfe_device *vfe_dev,
enum msm_vfe_axi_stream_src stream_src,
uint32_t io_format);
void (*cfg_framedrop)(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info);
void (*clear_framedrop)(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info);
void (*cfg_comp_mask)(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info);
void (*clear_comp_mask)(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info);
void (*cfg_wm_irq_mask)(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info);
void (*clear_wm_irq_mask)(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info);
void (*cfg_wm_reg)(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info,
uint8_t plane_idx);
void (*clear_wm_reg)(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx);
void (*cfg_wm_xbar_reg)(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info,
uint8_t plane_idx);
void (*clear_wm_xbar_reg)(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx);
void (*cfg_ub)(struct vfe_device *vfe_dev);
void (*update_ping_pong_addr)(struct vfe_device *vfe_dev,
uint8_t wm_idx, uint32_t pingpong_status, dma_addr_t paddr);
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);
int (*halt)(struct vfe_device *vfe_dev, uint32_t blocking);
int (*restart)(struct vfe_device *vfe_dev, uint32_t blocking,
uint32_t enable_camif);
void (*update_cgc_override)(struct vfe_device *vfe_dev,
uint8_t wm_idx, uint8_t cgc_override);
};
struct msm_vfe_core_ops {
void (*reg_update)(struct vfe_device *vfe_dev, uint32_t input_src);
long (*reset_hw)(struct vfe_device *vfe_dev, uint32_t first_start,
uint32_t blocking_call);
int (*init_hw)(struct vfe_device *vfe_dev);
void (*init_hw_reg)(struct vfe_device *vfe_dev);
void (*clear_status_reg)(struct vfe_device *vfe_dev);
void (*release_hw)(struct vfe_device *vfe_dev);
void (*cfg_input_mux)(struct vfe_device *vfe_dev,
struct msm_vfe_pix_cfg *pix_cfg);
int (*start_fetch_eng)(struct vfe_device *vfe_dev,
void *arg);
void (*update_camif_state)(struct vfe_device *vfe_dev,
enum msm_isp_camif_update_state update_state);
void (*cfg_rdi_reg)(struct vfe_device *vfe_dev,
struct msm_vfe_rdi_cfg *rdi_cfg,
enum msm_vfe_input_src input_src);
int (*get_platform_data)(struct vfe_device *vfe_dev);
void (*get_error_mask)(uint32_t *error_mask0, uint32_t *error_mask1);
void (*process_error_status)(struct vfe_device *vfe_dev);
void (*get_overflow_mask)(uint32_t *overflow_mask);
void (*get_irq_mask)(struct vfe_device *vfe_dev,
uint32_t *irq0_mask, uint32_t *irq1_mask);
void (*restore_irq_mask)(struct vfe_device *vfe_dev);
void (*get_halt_restart_mask)(uint32_t *irq0_mask,
uint32_t *irq1_mask);
void (*get_rdi_wm_mask)(struct vfe_device *vfe_dev,
uint32_t *rdi_wm_mask);
};
struct msm_vfe_stats_ops {
int (*get_stats_idx)(enum msm_isp_stats_type stats_type);
int (*check_streams)(struct msm_vfe_stats_stream *stream_info);
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,
uint32_t stats_mask, uint8_t enable);
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,
struct msm_vfe_stats_stream *stream_info);
void (*cfg_wm_reg)(struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info);
void (*clear_wm_reg)(struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info);
void (*cfg_ub)(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,
struct msm_vfe_stats_stream *stream_info,
uint32_t pingpong_status, dma_addr_t 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);
void (*update_cgc_override)(struct vfe_device *vfe_dev,
uint32_t stats_mask, uint8_t enable);
};
struct msm_vfe_ops {
struct msm_vfe_irq_ops irq_ops;
struct msm_vfe_axi_ops axi_ops;
struct msm_vfe_core_ops core_ops;
struct msm_vfe_stats_ops stats_ops;
};
struct msm_vfe_hardware_info {
int num_iommu_ctx;
/* secure iommu ctx nums */
int num_iommu_secure_ctx;
int vfe_clk_idx;
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;
uint32_t dmi_reg_offset;
};
struct msm_vfe_axi_hardware_info {
uint8_t num_wm;
uint8_t num_rdi;
uint8_t num_rdi_master;
uint8_t num_comp_mask;
uint32_t min_wm_ub;
uint32_t scratch_buf_range;
};
enum msm_vfe_axi_state {
AVAILABLE,
INACTIVE,
ACTIVE,
PAUSED,
START_PENDING,
STOP_PENDING,
PAUSE_PENDING,
RESUME_PENDING,
STARTING,
STOPPING,
PAUSING,
RESUMING,
};
enum msm_vfe_axi_cfg_update_state {
NO_AXI_CFG_UPDATE,
APPLYING_UPDATE_RESUME,
UPDATE_REQUESTED,
};
#define VFE_NO_DROP 0xFFFFFFFF
#define VFE_DROP_EVERY_2FRAME 0x55555555
#define VFE_DROP_EVERY_4FRAME 0x11111111
#define VFE_DROP_EVERY_8FRAME 0x01010101
#define VFE_DROP_EVERY_16FRAME 0x00010001
#define VFE_DROP_EVERY_32FRAME 0x00000001
enum msm_vfe_axi_stream_type {
CONTINUOUS_STREAM,
BURST_STREAM,
};
struct msm_vfe_axi_stream {
uint32_t frame_id;
enum msm_vfe_axi_state state;
enum msm_vfe_axi_stream_src stream_src;
uint8_t num_planes;
uint8_t wm[MAX_PLANES_PER_STREAM];
uint32_t output_format;/*Planar/RAW/Misc*/
struct msm_vfe_axi_plane_cfg plane_cfg[MAX_PLANES_PER_STREAM];
uint8_t comp_mask_index;
struct msm_isp_buffer *buf[2];
uint32_t session_id;
uint32_t stream_id;
uint32_t bufq_handle;
uint32_t bufq_scratch_handle;
uint32_t controllable_output;
uint32_t stream_handle;
uint32_t request_frm_num;
uint8_t buf_divert;
enum msm_vfe_axi_stream_type stream_type;
uint32_t frame_based;
enum msm_vfe_frame_skip_pattern frame_skip_pattern;
uint32_t framedrop_period;
uint32_t framedrop_pattern;
uint32_t num_burst_capture;/*number of frame to capture*/
uint32_t init_frame_drop;
uint32_t burst_frame_count;/*number of sof before burst stop*/
uint8_t framedrop_update;
spinlock_t lock;
/*Bandwidth calculation info*/
uint32_t max_width;
/*Based on format plane size in Q2. e.g NV12 = 1.5*/
uint32_t format_factor;
uint32_t bandwidth;
/*Run time update variables*/
uint32_t runtime_init_frame_drop;
uint32_t runtime_burst_frame_count;/*number of sof before burst stop*/
uint32_t runtime_num_burst_capture;
uint8_t runtime_framedrop_update;
uint8_t runtime_framedrop_update_burst;
uint32_t runtime_output_format;
enum msm_stream_memory_input_t memory_input;
};
struct msm_vfe_axi_composite_info {
uint32_t stream_handle;
uint32_t stream_composite_mask;
};
struct msm_vfe_src_info {
uint32_t frame_id;
uint8_t active;
uint8_t pix_stream_count;
uint8_t raw_stream_count;
enum msm_vfe_inputmux input_mux;
uint32_t width;
long pixel_clock;
uint32_t input_format;/*V4L2 pix format with bayer pattern*/
uint32_t last_updt_frm_id;
};
struct msm_vfe_fetch_engine_info {
uint32_t session_id;
uint32_t stream_id;
uint32_t bufq_handle;
uint32_t buf_idx;
uint8_t is_busy;
};
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[VFE_AXI_SRC_MAX];
uint32_t free_wm[MAX_NUM_WM];
uint32_t wm_image_size[MAX_NUM_WM];
enum msm_wm_ub_cfg_type wm_ub_cfg_policy;
uint8_t num_used_wm;
uint8_t num_active_stream;
uint8_t num_rdi_stream;
uint8_t num_pix_stream;
uint32_t rdi_wm_mask;
struct msm_vfe_axi_composite_info
composite_info[MAX_NUM_COMPOSITE_MASK];
uint8_t num_used_composite_mask;
uint32_t stream_update;
atomic_t axi_cfg_update;
enum msm_isp_camif_update_state pipeline_update;
struct msm_vfe_src_info src_info[VFE_SRC_MAX];
uint16_t stream_handle_cnt;
uint32_t event_mask;
};
struct msm_vfe_stats_hardware_info {
uint32_t stats_capability_mask;
uint8_t *stats_ping_pong_offset;
uint8_t num_stats_type;
uint8_t num_stats_comp_mask;
};
enum msm_vfe_stats_state {
STATS_AVAILABLE,
STATS_INACTIVE,
STATS_ACTIVE,
STATS_START_PENDING,
STATS_STOP_PENDING,
STATS_STARTING,
STATS_STOPPING,
};
struct msm_vfe_stats_stream {
uint32_t session_id;
uint32_t stream_id;
uint32_t stream_handle;
uint32_t composite_flag;
enum msm_isp_stats_type stats_type;
enum msm_vfe_stats_state state;
uint32_t framedrop_pattern;
uint32_t framedrop_period;
uint32_t irq_subsample_pattern;
uint32_t init_stats_frame_drop;
uint32_t buffer_offset;
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];
uint8_t num_active_stream;
atomic_t stats_comp_mask[MAX_NUM_STATS_COMP_MASK];
uint32_t reg_mask;
uint16_t stream_handle_cnt;
atomic_t stats_update;
};
struct msm_vfe_tasklet_queue_cmd {
struct list_head list;
uint32_t vfeInterruptStatus0;
uint32_t vfeInterruptStatus1;
struct msm_isp_timestamp ts;
uint8_t cmd_used;
};
#define MSM_VFE_TASKLETQ_SIZE 200
enum msm_vfe_overflow_state {
NO_OVERFLOW,
OVERFLOW_DETECTED,
HALT_REQUESTED,
RESTART_REQUESTED,
};
struct msm_vfe_error_info {
atomic_t overflow_state;
uint32_t overflow_recover_irq_mask0;
uint32_t overflow_recover_irq_mask1;
uint32_t error_mask0;
uint32_t error_mask1;
uint32_t violation_status;
uint32_t camif_status;
uint32_t stream_framedrop_count[MAX_NUM_STREAM];
uint32_t stats_framedrop_count[MSM_ISP_STATS_MAX];
uint32_t info_dump_frame_count;
uint32_t error_count;
};
struct msm_isp_statistics {
int64_t imagemaster0_overflow;
int64_t imagemaster1_overflow;
int64_t imagemaster2_overflow;
int64_t imagemaster3_overflow;
int64_t imagemaster4_overflow;
int64_t imagemaster5_overflow;
int64_t imagemaster6_overflow;
int64_t be_overflow;
int64_t bg_overflow;
int64_t bf_overflow;
int64_t awb_overflow;
int64_t rs_overflow;
int64_t cs_overflow;
int64_t ihist_overflow;
int64_t skinbhist_overflow;
int64_t bfscale_overflow;
int64_t isp_vfe0_active;
int64_t isp_vfe0_ab;
int64_t isp_vfe0_ib;
int64_t isp_vfe1_active;
int64_t isp_vfe1_ab;
int64_t isp_vfe1_ib;
int64_t isp_cpp_active;
int64_t isp_cpp_ab;
int64_t isp_cpp_ib;
int64_t last_overflow_ab;
int64_t last_overflow_ib;
int64_t vfe_clk_rate;
int64_t cpp_clk_rate;
};
enum msm_isp_hw_client {
ISP_VFE0,
ISP_VFE1,
ISP_CPP,
MAX_ISP_CLIENT,
};
struct msm_isp_bandwidth_info {
uint32_t active;
uint64_t ab;
uint64_t ib;
};
struct msm_isp_bw_req_info {
uint32_t client;
unsigned long long timestamp;
uint64_t total_ab;
uint64_t total_ib;
struct msm_isp_bandwidth_info client_info[MAX_ISP_CLIENT];
};
#define MSM_ISP_MAX_WM 7
struct msm_isp_ub_info {
enum msm_wm_ub_cfg_type policy;
uint8_t num_wm;
uint32_t wm_ub;
uint32_t data[MSM_ISP_MAX_WM];
uint64_t addr[MSM_ISP_MAX_WM];
};
struct msm_vfe_hw_init_parms {
const char *entries;
const char *regs;
const char *settings;
};
struct vfe_device {
struct platform_device *pdev;
struct msm_sd_subdev subdev;
struct resource *vfe_irq;
struct resource *vfe_mem;
struct resource *vfe_vbif_mem;
struct resource *vfe_io;
struct resource *vfe_vbif_io;
void __iomem *vfe_base;
void __iomem *vfe_vbif_base;
struct device *iommu_ctx[MAX_IOMMU_CTX];
/*Add secure context banks*/
struct device *iommu_secure_ctx[MAX_IOMMU_CTX];
struct regulator *fs_vfe;
struct clk **vfe_clk;
uint32_t num_clk;
uint32_t bus_perf_client;
struct completion reset_complete;
struct completion halt_complete;
struct completion stream_config_complete;
struct completion stats_config_complete;
struct mutex realtime_mutex;
struct mutex core_mutex;
atomic_t irq_cnt;
uint8_t taskletq_idx;
spinlock_t tasklet_lock;
spinlock_t shared_data_lock;
struct list_head tasklet_q;
struct tasklet_struct vfe_tasklet;
struct msm_vfe_tasklet_queue_cmd
tasklet_queue_cmd[MSM_VFE_TASKLETQ_SIZE];
uint32_t vfe_hw_version;
struct msm_vfe_hardware_info *hw_info;
struct msm_vfe_axi_shared_data axi_data;
struct msm_vfe_stats_shared_data stats_data;
struct msm_vfe_error_info error_info;
struct msm_isp_buf_mgr *buf_mgr;
int dump_reg;
int vfe_clk_idx;
uint32_t vfe_open_cnt;
uint8_t vt_enable;
uint8_t ignore_error;
struct msm_isp_statistics *stats;
struct msm_vfe_fetch_engine_info fetch_engine_info;
uint64_t msm_isp_last_overflow_ab;
uint64_t msm_isp_last_overflow_ib;
uint64_t msm_isp_vfe_clk_rate;
struct msm_isp_ub_info *ub_info;
uint32_t vfe_ub_policy;
uint32_t isp_sof_debug;
uint8_t reset_pending;
uint32_t bus_util_factor;
uint8_t vfe_reset_timeout_processed;
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,72 @@
/* 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
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __MSM_ISP_AXI_UTIL_H__
#define __MSM_ISP_AXI_UTIL_H__
#include "msm_isp_32.h"
int msm_isp_axi_create_stream(
struct msm_vfe_axi_shared_data *axi_data,
struct msm_vfe32_axi_stream_request_cmd *stream_cfg_cmd);
void msm_isp_axi_destroy_stream(
struct msm_vfe_axi_shared_data *axi_data, int stream_idx);
int msm_isp_validate_axi_request(
struct msm_vfe_axi_shared_data *axi_data,
struct msm_vfe32_axi_stream_request_cmd *stream_cfg_cmd);
void msm_isp_axi_reserve_wm(
struct msm_vfe_axi_shared_data *axi_data,
struct msm_vfe_axi_stream *stream_info);
void msm_isp_axi_reserve_comp_mask(
struct msm_vfe_axi_shared_data *axi_data,
struct msm_vfe_axi_stream *stream_info);
int msm_isp_axi_check_stream_state(
struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd);
void msm_isp_calculate_framedrop(
struct msm_vfe_axi_shared_data *axi_data,
struct msm_vfe32_axi_stream_request_cmd *stream_cfg_cmd);
void msm_isp_reset_framedrop(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info);
void msm_isp_start_avtimer(void);
int msm_isp_request_axi_stream(struct vfe_device *vfe_dev, void *arg);
int msm_isp_cfg_axi_stream(struct vfe_device *vfe_dev, void *arg);
int msm_isp_release_axi_stream(struct vfe_device *vfe_dev, void *arg);
int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg);
void msm_isp_axi_cfg_update(struct vfe_device *vfe_dev);
int msm_isp_axi_halt(struct vfe_device *vfe_dev,
struct msm_vfe_axi_halt_cmd *halt_cmd);
int msm_isp_axi_reset(struct vfe_device *vfe_dev,
struct msm_vfe_axi_reset_cmd *reset_cmd);
int msm_isp_axi_restart(struct vfe_device *vfe_dev,
struct msm_vfe_axi_restart_cmd *restart_cmd);
int msm_isp_user_buf_done(struct vfe_device *vfe_dev,
struct msm_isp32_event_data *buf_cmd);
void msm_isp_axi_stream_update(struct vfe_device *vfe_dev,
uint8_t input_src);
void msm_isp_update_framedrop_reg(struct vfe_device *vfe_dev,
uint8_t input_src);
void msm_isp_notify(struct vfe_device *vfe_dev, uint32_t event_type,
enum msm_vfe_input_src frame_src, struct msm_isp_timestamp *ts);
void msm_isp_process_axi_irq(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
struct msm_isp_timestamp *ts);
void msm_isp_axi_free_wm(struct msm_vfe_axi_shared_data *axi_data,
struct msm_vfe_axi_stream *stream_info);
#endif /* __MSM_ISP_AXI_UTIL_H__ */

View file

@ -0,0 +1,709 @@
/* 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
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/io.h>
#include <linux/atomic.h>
#include <media/v4l2-subdev.h>
#include <media/msmb_isp.h>
#include "msm_isp_util_32.h"
#include "msm_isp_stats_util_32.h"
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 **done_buf)
{
int rc = -1;
struct msm_isp_buffer *buf;
uint32_t pingpong_bit = 0;
uint32_t bufq_handle = stream_info->bufq_handle;
uint32_t stats_pingpong_offset;
uint32_t stats_idx = STATS_IDX(stream_info->stream_handle);
if (stats_idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type ||
stats_idx >= MSM_ISP_STATS_MAX) {
pr_err("%s Invalid stats index %d", __func__, stats_idx);
return -EINVAL;
}
stats_pingpong_offset =
vfe_dev->hw_info->stats_hw_info->stats_ping_pong_offset[
stats_idx];
pingpong_bit = (~(pingpong_status >> stats_pingpong_offset) & 0x1);
rc = vfe_dev->buf_mgr->ops->get_buf(vfe_dev->buf_mgr,
vfe_dev->pdev->id, bufq_handle,
MSM_ISP_INVALID_BUF_INDEX, &buf);
if (rc < 0) {
vfe_dev->error_info.stats_framedrop_count[stats_idx]++;
return rc;
}
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 +
stream_info->buffer_offset);
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 msm_isp_timestamp *ts)
{
int i, j, rc;
struct msm_isp32_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 comp_stats_type_mask = 0, atomic_stats_mask = 0;
uint32_t stats_comp_mask = 0, stats_irq_mask = 0;
uint32_t num_stats_comp_mask =
vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask;
stats_comp_mask = vfe_dev->hw_info->vfe_ops.stats_ops.
get_comp_mask(irq_status0, irq_status1);
stats_irq_mask = vfe_dev->hw_info->vfe_ops.stats_ops.
get_wm_mask(irq_status0, irq_status1);
if (!(stats_comp_mask || stats_irq_mask))
return;
ISP_DBG("%s: status: 0x%x\n", __func__, irq_status0);
/*
* If any of composite mask is set, clear irq bits from mask,
* they will be restored by comp mask
*/
if (stats_comp_mask) {
for (j = 0; j < num_stats_comp_mask; j++) {
stats_irq_mask &= ~atomic_read(
&vfe_dev->stats_data.stats_comp_mask[j]);
}
}
for (j = 0; j < num_stats_comp_mask; j++) {
atomic_stats_mask = atomic_read(
&vfe_dev->stats_data.stats_comp_mask[j]);
if (!stats_comp_mask) {
stats_irq_mask &= ~atomic_stats_mask;
} else {
/* restore irq bits from composite mask */
if (stats_comp_mask & (1 << j))
stats_irq_mask |= atomic_stats_mask;
}
/* if no irq bits set from this composite mask continue*/
if (!stats_irq_mask)
continue;
memset(&buf_event, 0, sizeof(struct msm_isp32_event_data));
buf_event.timestamp = ts->event_time;
buf_event.frame_id =
vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
buf_event.input_intf = VFE_PIX_0;
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;
stats_irq_mask &= ~(1 << i);
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) {
rc = vfe_dev->buf_mgr->ops->buf_divert(
vfe_dev->buf_mgr, done_buf->bufq_handle,
done_buf->buf_idx, &ts->buf_time,
vfe_dev->axi_data.
src_info[VFE_PIX_0].frame_id);
if (rc != 0)
continue;
stats_event->stats_buf_idxs
[stream_info->stats_type] =
done_buf->buf_idx;
if (!stream_info->composite_flag) {
stats_event->stats_mask =
1 << stream_info->stats_type;
ISP_DBG("%s: stats frameid: 0x%x %d\n",
__func__, buf_event.frame_id,
stream_info->stats_type);
msm_isp_send_event(vfe_dev,
ISP_EVENT_STATS_NOTIFY +
stream_info->stats_type,
&buf_event);
} else {
comp_stats_type_mask |=
1 << stream_info->stats_type;
}
}
}
if (comp_stats_type_mask) {
ISP_DBG("%s: comp_stats frameid: 0x%x, 0x%x\n",
__func__, buf_event.frame_id,
comp_stats_type_mask);
stats_event->stats_mask = comp_stats_type_mask;
msm_isp_send_event(vfe_dev,
ISP_EVENT_COMP_STATS_NOTIFY, &buf_event);
comp_stats_type_mask = 0;
}
}
}
int msm_isp_stats_create_stream(struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream_request_cmd *stream_req_cmd)
{
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 (!(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);
if (stats_idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) {
pr_err("%s Invalid stats index %d", __func__, stats_idx);
return -EINVAL;
}
stream_info = &stats_data->stream_info[stats_idx];
if (stream_info->state != STATS_AVAILABLE) {
pr_err("%s: Stats already requested\n", __func__);
return rc;
}
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;
}
stream_info->session_id = stream_req_cmd->session_id;
stream_info->stream_id = stream_req_cmd->stream_id;
stream_info->composite_flag = stream_req_cmd->composite_flag;
stream_info->stats_type = stream_req_cmd->stats_type;
stream_info->buffer_offset = stream_req_cmd->buffer_offset;
stream_info->framedrop_pattern = stream_req_cmd->framedrop_pattern;
stream_info->init_stats_frame_drop = stream_req_cmd->init_frame_drop;
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 = -1;
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 framedrop_period;
uint32_t stats_idx;
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_idx = STATS_IDX(stream_req_cmd->stream_handle);
if (stats_idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) {
pr_err("%s Invalid stats index %d", __func__, stats_idx);
return -EINVAL;
}
stream_info = &stats_data->stream_info[stats_idx];
framedrop_period = msm_isp_get_framedrop_period(
stream_req_cmd->framedrop_pattern);
if (stream_req_cmd->framedrop_pattern == SKIP_ALL)
stream_info->framedrop_pattern = 0x0;
else
stream_info->framedrop_pattern = 0x1;
stream_info->framedrop_period = framedrop_period - 1;
if (!stream_info->composite_flag)
vfe_dev->hw_info->vfe_ops.stats_ops.
cfg_wm_irq_mask(vfe_dev, stream_info);
if (stream_info->init_stats_frame_drop == 0)
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 = -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 = NULL;
if (stats_idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) {
pr_err("%s Invalid stats index %d", __func__, stats_idx);
return -EINVAL;
}
stream_info = &stats_data->stream_info[stats_idx];
if (stream_info->state == STATS_AVAILABLE) {
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->composite_flag)
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_wm_reg(vfe_dev, stream_info);
memset(stream_info, 0, sizeof(struct msm_vfe_stats_stream));
return 0;
}
static int msm_isp_init_stats_ping_pong_reg(
struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info)
{
int rc = 0;
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 stream: 0x%x\n",
__func__, stream_info->stream_handle);
return -EINVAL;
}
rc = msm_isp_stats_cfg_ping_pong_address(vfe_dev,
stream_info, VFE_PING_FLAG, NULL);
if (rc < 0) {
pr_err("%s: No free buffer for ping\n", __func__);
return rc;
}
rc = msm_isp_stats_cfg_ping_pong_address(vfe_dev,
stream_info, VFE_PONG_FLAG, NULL);
if (rc < 0) {
pr_err("%s: No free buffer for pong\n", __func__);
return rc;
}
return rc;
}
static void msm_isp_deinit_stats_ping_pong_reg(
struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info)
{
int i;
struct msm_isp_buffer *buf;
for (i = 0; i < 2; i++) {
buf = stream_info->buf[i];
if (buf)
vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr,
buf->bufq_handle, buf->buf_idx);
}
}
void msm_isp_update_stats_framedrop_reg(struct vfe_device *vfe_dev)
{
int i;
struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
struct msm_vfe_stats_stream *stream_info = NULL;
for (i = 0; i < vfe_dev->hw_info->stats_hw_info->num_stats_type; i++) {
stream_info = &stats_data->stream_info[i];
if (stream_info->state != STATS_ACTIVE)
continue;
if (stream_info->init_stats_frame_drop) {
stream_info->init_stats_frame_drop--;
if (stream_info->init_stats_frame_drop == 0) {
vfe_dev->hw_info->vfe_ops.stats_ops.cfg_wm_reg(
vfe_dev, stream_info);
}
}
}
}
void msm_isp_stats_stream_update(struct vfe_device *vfe_dev)
{
int i;
uint32_t stats_mask = 0, comp_stats_mask = 0;
uint32_t enable = 0;
struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
for (i = 0; i < vfe_dev->hw_info->stats_hw_info->num_stats_type; i++) {
if (stats_data->stream_info[i].state == STATS_START_PENDING ||
stats_data->stream_info[i].state ==
STATS_STOP_PENDING) {
stats_mask |= i;
enable = stats_data->stream_info[i].state ==
STATS_START_PENDING ? 1 : 0;
stats_data->stream_info[i].state =
stats_data->stream_info[i].state ==
STATS_START_PENDING ?
STATS_STARTING : STATS_STOPPING;
vfe_dev->hw_info->vfe_ops.stats_ops.enable_module(
vfe_dev, BIT(i), enable);
vfe_dev->hw_info->vfe_ops.stats_ops.cfg_comp_mask(
vfe_dev, BIT(i), enable);
} else if (stats_data->stream_info[i].state == STATS_STARTING ||
stats_data->stream_info[i].state == STATS_STOPPING) {
if (stats_data->stream_info[i].composite_flag)
comp_stats_mask |= i;
stats_data->stream_info[i].state =
stats_data->stream_info[i].state ==
STATS_STARTING ? STATS_ACTIVE : STATS_INACTIVE;
}
}
atomic_sub(1, &stats_data->stats_update);
if (!atomic_read(&stats_data->stats_update))
complete(&vfe_dev->stats_config_complete);
}
static int msm_isp_stats_wait_for_cfg_done(struct vfe_device *vfe_dev)
{
int rc;
init_completion(&vfe_dev->stats_config_complete);
atomic_set(&vfe_dev->stats_data.stats_update, 2);
rc = wait_for_completion_timeout(
&vfe_dev->stats_config_complete,
msecs_to_jiffies(VFE_MAX_CFG_TIMEOUT));
if (rc == 0) {
pr_err("%s: wait timeout\n", __func__);
rc = -1;
} else {
rc = 0;
}
return rc;
}
static int msm_isp_stats_update_cgc_override(struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd)
{
int i;
uint32_t stats_mask = 0, idx;
if (stream_cfg_cmd->num_streams > MSM_ISP_STATS_MAX) {
pr_err("%s invalid num_streams %d\n", __func__,
stream_cfg_cmd->num_streams);
return -EINVAL;
}
for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]);
if (idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) {
pr_err("%s Invalid stats index %d", __func__, idx);
return -EINVAL;
}
stats_mask |= 1 << idx;
}
if (vfe_dev->hw_info->vfe_ops.stats_ops.update_cgc_override) {
vfe_dev->hw_info->vfe_ops.stats_ops.update_cgc_override(
vfe_dev, stats_mask, stream_cfg_cmd->enable);
}
return 0;
}
static int msm_isp_start_stats_stream(struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd)
{
int i, rc = 0;
uint32_t stats_mask = 0, idx;
uint32_t comp_stats_mask[MAX_NUM_STATS_COMP_MASK] = {0};
uint32_t num_stats_comp_mask = 0;
struct msm_vfe_stats_stream *stream_info;
struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
if (stream_cfg_cmd->num_streams > MSM_ISP_STATS_MAX) {
pr_err("%s invalid num_streams %d\n", __func__,
stream_cfg_cmd->num_streams);
return -EINVAL;
}
num_stats_comp_mask =
vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask;
rc = vfe_dev->hw_info->vfe_ops.stats_ops.check_streams(
stats_data->stream_info);
if (rc < 0)
return rc;
for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]);
if (idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) {
pr_err("%s Invalid stats index %d", __func__, idx);
return -EINVAL;
}
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",
__func__, stream_cfg_cmd->stream_handle[i]);
continue;
}
if (stream_info->composite_flag > num_stats_comp_mask) {
pr_err("%s: comp grp %d exceed max %d\n",
__func__, stream_info->composite_flag,
num_stats_comp_mask);
return -EINVAL;
}
rc = msm_isp_init_stats_ping_pong_reg(vfe_dev, stream_info);
if (rc < 0) {
pr_err("%s: No buffer for stream%d type:%d stmID:0x%x\n",
__func__, idx, stream_info->stats_type,
stream_info->stream_id);
return rc;
}
if (vfe_dev->axi_data.src_info[VFE_PIX_0].active)
stream_info->state = STATS_START_PENDING;
else
stream_info->state = STATS_ACTIVE;
stats_data->num_active_stream++;
stats_mask |= 1 << idx;
if (stream_info->composite_flag > 0)
comp_stats_mask[stream_info->composite_flag-1] |=
1 << idx;
ISP_DBG("%s: stats_mask %x %x active streams %d\n",
__func__, comp_stats_mask[0],
comp_stats_mask[1],
stats_data->num_active_stream);
}
if (vfe_dev->axi_data.src_info[VFE_PIX_0].active) {
rc = msm_isp_stats_wait_for_cfg_done(vfe_dev);
} else {
vfe_dev->hw_info->vfe_ops.stats_ops.enable_module(
vfe_dev, stats_mask, stream_cfg_cmd->enable);
for (i = 0; i < num_stats_comp_mask; i++) {
vfe_dev->hw_info->vfe_ops.stats_ops.cfg_comp_mask(
vfe_dev, comp_stats_mask[i], 1);
}
}
return rc;
}
static int msm_isp_stop_stats_stream(struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd)
{
int i, rc = 0;
uint32_t stats_mask = 0, idx;
uint32_t comp_stats_mask[MAX_NUM_STATS_COMP_MASK] = {0};
uint32_t num_stats_comp_mask = 0;
struct msm_vfe_stats_stream *stream_info;
struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
num_stats_comp_mask =
vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask;
for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]);
if (idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) {
pr_err("%s Invalid stats index %d", __func__, idx);
return -EINVAL;
}
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",
__func__, stream_cfg_cmd->stream_handle[i]);
continue;
}
if (stream_info->composite_flag > num_stats_comp_mask) {
pr_err("%s: comp grp %d exceed max %d\n",
__func__, stream_info->composite_flag,
num_stats_comp_mask);
return -EINVAL;
}
if (vfe_dev->axi_data.src_info[VFE_PIX_0].active)
stream_info->state = STATS_STOP_PENDING;
else
stream_info->state = STATS_INACTIVE;
stats_data->num_active_stream--;
stats_mask |= 1 << idx;
if (stream_info->composite_flag > 0)
comp_stats_mask[stream_info->composite_flag-1] |=
1 << idx;
ISP_DBG("%s: stats_mask %x %x active streams %d\n",
__func__, comp_stats_mask[0],
comp_stats_mask[1],
stats_data->num_active_stream);
}
if (vfe_dev->axi_data.src_info[VFE_PIX_0].active) {
rc = msm_isp_stats_wait_for_cfg_done(vfe_dev);
} else {
vfe_dev->hw_info->vfe_ops.stats_ops.enable_module(
vfe_dev, stats_mask, stream_cfg_cmd->enable);
for (i = 0; i < num_stats_comp_mask; i++) {
vfe_dev->hw_info->vfe_ops.stats_ops.cfg_comp_mask(
vfe_dev, comp_stats_mask[i], 0);
}
}
for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]);
if (idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) {
pr_err("%s Invalid stats index %d", __func__, idx);
return -EINVAL;
}
stream_info = &stats_data->stream_info[idx];
msm_isp_deinit_stats_ping_pong_reg(vfe_dev, stream_info);
}
return rc;
}
int msm_isp_cfg_stats_stream(struct vfe_device *vfe_dev, void *arg)
{
int rc = 0;
struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd = arg;
if (vfe_dev->stats_data.num_active_stream == 0)
vfe_dev->hw_info->vfe_ops.stats_ops.cfg_ub(vfe_dev);
if (stream_cfg_cmd->num_streams > MSM_ISP_STATS_MAX) {
pr_err("%s invalid num_streams %d\n", __func__,
stream_cfg_cmd->num_streams);
return -EINVAL;
}
if (stream_cfg_cmd->enable) {
msm_isp_stats_update_cgc_override(vfe_dev, stream_cfg_cmd);
rc = msm_isp_start_stats_stream(vfe_dev, stream_cfg_cmd);
} else {
rc = msm_isp_stop_stats_stream(vfe_dev, stream_cfg_cmd);
msm_isp_stats_update_cgc_override(vfe_dev, stream_cfg_cmd);
}
return rc;
}
int msm_isp_update_stats_stream(struct vfe_device *vfe_dev, void *arg)
{
int rc = 0, i;
struct msm_vfe_stats_stream *stream_info;
struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
struct msm_vfe_axi_stream_update_cmd *update_cmd = arg;
struct msm_vfe_axi_stream_cfg_update_info *update_info = NULL;
/*validate request*/
for (i = 0; i < update_cmd->num_streams; i++) {
update_info = &update_cmd->update_info[i];
/*check array reference bounds*/
if (STATS_IDX(update_info->stream_handle)
> vfe_dev->hw_info->stats_hw_info->num_stats_type) {
pr_err("%s: stats idx %d out of bound!", __func__,
STATS_IDX(update_info->stream_handle));
return -EINVAL;
}
}
for (i = 0; i < update_cmd->num_streams; i++) {
update_info = &update_cmd->update_info[i];
stream_info = &stats_data->stream_info[
STATS_IDX(update_info->stream_handle)];
if (stream_info->stream_handle !=
update_info->stream_handle) {
pr_err("%s: stats stream handle %x %x mismatch!\n",
__func__, stream_info->stream_handle,
update_info->stream_handle);
continue;
}
switch (update_cmd->update_type) {
case UPDATE_STREAM_STATS_FRAMEDROP_PATTERN: {
uint32_t framedrop_period =
msm_isp_get_framedrop_period(
update_info->skip_pattern);
if (update_info->skip_pattern == SKIP_ALL)
stream_info->framedrop_pattern = 0x0;
else
stream_info->framedrop_pattern = 0x1;
stream_info->framedrop_period = framedrop_period - 1;
if (stream_info->init_stats_frame_drop == 0)
vfe_dev->hw_info->vfe_ops.stats_ops.cfg_wm_reg(
vfe_dev, stream_info);
break;
}
default:
pr_err("%s: Invalid update type\n", __func__);
return -EINVAL;
}
}
return rc;
}

View file

@ -0,0 +1,29 @@
/* 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
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __MSM_ISP_STATS_UTIL_H__
#define __MSM_ISP_STATS_UTIL_H__
#include "msm_isp_32.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,
struct msm_isp_timestamp *ts);
int msm_isp_stats_create_stream(struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream_request_cmd *stream_req_cmd);
void msm_isp_stats_stream_update(struct vfe_device *vfe_dev);
int msm_isp_cfg_stats_stream(struct vfe_device *vfe_dev, void *arg);
int msm_isp_update_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);
void msm_isp_update_stats_framedrop_reg(struct vfe_device *vfe_dev);
#endif /* __MSM_ISP_STATS_UTIL_H__ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,84 @@
/* 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
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __MSM_ISP_UTIL_H__
#define __MSM_ISP_UTIL_H__
#include "msm_isp_32.h"
#include <soc/qcom/camera2.h>
/* #define CONFIG_MSM_ISP_DBG 1 */
#ifdef CONFIG_MSM_ISP_DBG
#define ISP_DBG(fmt, args...) printk(fmt, ##args)
#else
#define ISP_DBG(fmt, args...) pr_debug(fmt, ##args)
#endif
#define ALT_VECTOR_IDX(x) {x = 3 - x; }
struct msm_isp_bandwidth_mgr {
uint32_t bus_client;
uint32_t bus_vector_active_idx;
uint32_t use_count;
struct msm_isp_bandwidth_info client_info[MAX_ISP_CLIENT];
};
uint32_t msm_isp_get_framedrop_period(
enum msm_vfe_frame_skip_pattern frame_skip_pattern);
void msm_isp_reset_burst_count_and_frame_drop(
struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info);
int msm_isp_init_bandwidth_mgr(enum msm_isp_hw_client client);
int msm_isp_update_bandwidth(enum msm_isp_hw_client client,
uint64_t ab, uint64_t ib);
void msm_isp_util_get_bandwidth_stats(struct vfe_device *vfe_dev,
struct msm_isp_statistics *stats);
void msm_isp_util_update_last_overflow_ab_ib(struct vfe_device *vfe_dev);
void msm_isp_util_update_clk_rate(long clock_rate);
void msm_isp_update_req_history(uint32_t client, uint64_t ab,
uint64_t ib,
struct msm_isp_bandwidth_info *client_info,
unsigned long long ts);
void msm_isp_deinit_bandwidth_mgr(enum msm_isp_hw_client client);
int msm_isp_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
struct v4l2_event_subscription *sub);
int msm_isp_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
struct v4l2_event_subscription *sub);
int msm_isp_proc_cmd(struct vfe_device *vfe_dev, void *arg);
int msm_isp_send_event(struct vfe_device *vfe_dev,
uint32_t type, struct msm_isp32_event_data *event_data);
int msm_isp_cal_word_per_line(uint32_t output_format,
uint32_t pixel_per_line);
int msm_isp_get_bit_per_pixel(uint32_t output_format);
enum msm_isp_pack_fmt msm_isp_get_pack_format(uint32_t output_format);
irqreturn_t msm_isp_process_irq(int irq_num, void *data);
int msm_isp_set_src_state(struct vfe_device *vfe_dev, void *arg);
void msm_isp_do_tasklet(unsigned long data);
void msm_isp_update_error_frame_count(struct vfe_device *vfe_dev);
void msm_isp_process_error_info(struct vfe_device *vfe_dev);
int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh);
int msm_isp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh);
long msm_isp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg);
int msm_isp_get_clk_info(struct vfe_device *vfe_dev,
struct platform_device *pdev, struct msm_cam_clk_info *vfe_clk_info);
void msm_isp_fetch_engine_done_notify(struct vfe_device *vfe_dev,
struct msm_vfe_fetch_engine_info *fetch_engine_info);
void msm_camera_io_dump_2(void __iomem *addr, int size);
void msm_isp_print_fourcc_error(const char *origin, uint32_t fourcc_format);
void msm_isp_get_timestamp(struct msm_isp_timestamp *time_stamp,
struct vfe_device *vfe_dev);
void msm_isp_get_avtimer_ts(struct msm_isp_timestamp *time_stamp);
int msm_isp_cfg_input(struct vfe_device *vfe_dev, void *arg);
#endif /* __MSM_ISP_UTIL_H__ */

View file

@ -1,4 +1,8 @@
ccflags-y += -Idrivers/media/platform/msm/camera_v2
ccflags-y += -Idrivers/media/platform/msm/camera_v2/common
ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
ifeq ($(CONFIG_MSM_ISP_V1),y)
obj-$(CONFIG_MSM_CSID) += msm_ispif_32.o
else
obj-$(CONFIG_MSM_CSID) += msm_ispif.o
endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,69 @@
/* 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
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef MSM_ISPIF_H
#define MSM_ISPIF_H
#include <linux/clk.h>
#include <linux/io.h>
#include <media/v4l2-subdev.h>
#include <media/msmb_ispif.h>
#include "msm_sd.h"
#define ISPIF_CLK_INFO_MAX 24
struct ispif_irq_status {
uint32_t ispifIrqStatus0;
uint32_t ispifIrqStatus1;
uint32_t ispifIrqStatus2;
};
enum msm_ispif_state_t {
ISPIF_POWER_UP,
ISPIF_POWER_DOWN,
};
struct ispif_sof_count {
uint32_t sof_cnt[INTF_MAX];
};
struct ispif_intf_cmd {
uint32_t intf_cmd;
uint32_t intf_cmd1;
};
struct ispif_device {
struct platform_device *pdev;
struct msm_sd_subdev msm_sd;
struct resource *mem;
struct resource *clk_mux_mem;
struct resource *irq;
struct resource *io;
struct resource *clk_mux_io;
void __iomem *base;
void __iomem *clk_mux_base;
struct mutex mutex;
uint8_t start_ack_pending;
uint32_t csid_version;
int enb_dump_reg;
uint32_t open_cnt;
struct ispif_sof_count sof_count[VFE_MAX];
struct ispif_intf_cmd applied_intf_cmd[VFE_MAX];
enum msm_ispif_state_t ispif_state;
struct msm_ispif_vfe_info vfe_info;
struct clk *ahb_clk[ISPIF_CLK_INFO_MAX];
struct completion reset_complete[VFE_MAX];
uint32_t hw_num_isps;
uint32_t num_ahb_clk;
uint32_t clk_idx;
uint32_t ispif_sof_debug;
};
#endif

View file

@ -2077,14 +2077,8 @@ static struct platform_driver msm_actuator_platform_driver = {
static int __init msm_actuator_init_module(void)
{
int32_t rc = 0;
CDBG("Enter\n");
rc = platform_driver_register(&msm_actuator_platform_driver);
if (!rc)
return rc;
CDBG("%s:%d rc %d\n", __func__, __LINE__, rc);
platform_driver_register(&msm_actuator_platform_driver);
return i2c_add_driver(&msm_actuator_i2c_driver);
}

View file

@ -323,8 +323,7 @@ static int msm_csid_config(struct csid_device *csid_dev,
if (!msm_csid_find_max_clk_rate(csid_dev))
pr_err("msm_csid_find_max_clk_rate failed\n");
clk_rate = (csid_params->csi_clk > 0) ?
(csid_params->csi_clk) : csid_dev->csid_max_clk;
clk_rate = csid_dev->csid_max_clk;
clk_rate = msm_camera_clk_set_rate(&csid_dev->pdev->dev,
csid_dev->csid_clk[csid_dev->csid_clk_index], clk_rate);

View file

@ -29,7 +29,6 @@
#include "include/msm_csiphy_5_0_hwreg.h"
#include "include/msm_csiphy_5_0_1_hwreg.h"
#include "include/msm_csiphy_10_0_0_hwreg.h"
#include "cam_hw_ops.h"
#define DBG_CSIPHY 0
@ -1248,9 +1247,7 @@ static int msm_csiphy_lane_config(struct csiphy_device *csiphy_dev,
return rc;
}
clk_rate = (csiphy_params->csiphy_clk > 0)
? csiphy_params->csiphy_clk :
csiphy_dev->csiphy_max_clk;
clk_rate = csiphy_dev->csiphy_max_clk;
clk_rate = msm_camera_clk_set_rate(&csiphy_dev->pdev->dev,
csiphy_dev->csiphy_clk[csiphy_dev->csiphy_clk_index],
clk_rate);

View file

@ -20,7 +20,6 @@
#include "msm_sensor.h"
#undef CDBG
#define MSM_CAMERA_TZ_I2C_VERBOSE
#ifdef CONFIG_MSM_SEC_CCI_DEBUG
#define TZ_I2C_FN_RETURN(ret, i2c_fn, ...) \

Some files were not shown because too many files have changed in this diff Show more