msm: msmb: ISP interface driver and ISP driver implementation
(1) ISP interface(ISPIF) sits between sensor(CSID) and ISP.
It's responsible to mux sensor's output path to
ISP input path. ISPIF driver contains two parts, i.e.,
user space driver and kernel driver. The kernel driver is
mainly for register write and read.
(2) Image signal processing(ISP) driver's responsiblity is to
processed the sensor's raw image to generate the YUV image
for rending/video encoding and snapshot. ISP driver has
following main functional blcoks:
- Image bus(AXI) management and configuration
- ISP processing pipeline configuration and run time update
- ISP input interface(CAMIF) configuration
- Image buffer management
- ISP interrupt handling
- ISP kernel event notification to user space
- ISP hardware start/stop state machine.
This patch implemented the ISP kernel driver.
Change-Id: I5f222c6a2df8b4c26b0948ef3fb2e36e859d0964
Signed-off-by: Kevin Chan <ktchan@codeaurora.org>
This commit is contained in:
committed by
Iliyan Malchev
parent
16e1fe9c61
commit
2ef669253a
@@ -4,6 +4,7 @@ Required properties:
|
||||
- cell-index: vfe hardware core index
|
||||
- compatible :
|
||||
- "qcom,vfe"
|
||||
- "qcom,vfe40"
|
||||
- reg : offset and length of the register set for the device
|
||||
for the vfe operating in compatible mode.
|
||||
- reg-names : should specify relevant names to each reg property defined.
|
||||
|
||||
@@ -10,3 +10,5 @@ obj-$(CONFIG_MSMB_CAMERA) += msm.o
|
||||
obj-$(CONFIG_MSMB_CAMERA) += camera/
|
||||
obj-$(CONFIG_MSMB_CAMERA) += msm_vb2/
|
||||
obj-$(CONFIG_MSMB_CAMERA) += sensor/
|
||||
obj-$(CONFIG_MSMB_CAMERA) += isp/
|
||||
obj-$(CONFIG_MSMB_CAMERA) += ispif/
|
||||
|
||||
4
drivers/media/video/msmb/isp/Makefile
Normal file
4
drivers/media/video/msmb/isp/Makefile
Normal file
@@ -0,0 +1,4 @@
|
||||
ccflags-y += -Idrivers/media/video/msmb
|
||||
ccflags-y += -Idrivers/media/video/msmb/sensor/io
|
||||
obj-$(CONFIG_MSMB_CAMERA) += msm_isp.o msm_buf_mgr.o msm_isp_util.o msm_isp_axi_util.o msm_isp_stats_util.o
|
||||
obj-$(CONFIG_MSMB_CAMERA) += msm_isp40.o
|
||||
604
drivers/media/video/msmb/isp/msm_buf_mgr.c
Normal file
604
drivers/media/video/msmb/isp/msm_buf_mgr.c
Normal file
@@ -0,0 +1,604 @@
|
||||
/* Copyright (c) 2013, 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/workqueue.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/android_pmem.h>
|
||||
|
||||
#include <media/v4l2-dev.h>
|
||||
#include <media/v4l2-ioctl.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/videobuf2-core.h>
|
||||
#include <media/msm_camera.h>
|
||||
#include <media/msm_isp.h>
|
||||
|
||||
#include <mach/iommu.h>
|
||||
|
||||
#include "msm.h"
|
||||
#include "msm_buf_mgr.h"
|
||||
|
||||
/*#define CONFIG_MSM_ISP_DBG*/
|
||||
#undef CDBG
|
||||
#ifdef CONFIG_MSM_ISP_DBG
|
||||
#define CDBG(fmt, args...) pr_err(fmt, ##args)
|
||||
#else
|
||||
#define CDBG(fmt, args...) do { } while (0)
|
||||
#endif
|
||||
|
||||
static struct msm_isp_bufq *msm_isp_get_bufq(
|
||||
struct msm_isp_buf_mgr *buf_mgr,
|
||||
uint32_t bufq_handle)
|
||||
{
|
||||
struct msm_isp_bufq *bufq = NULL;
|
||||
uint32_t bufq_index = bufq_handle & 0xFF;
|
||||
if (bufq_index > buf_mgr->num_buf_q)
|
||||
return bufq;
|
||||
|
||||
bufq = &buf_mgr->bufq[bufq_index];
|
||||
if (bufq->bufq_handle == bufq_handle)
|
||||
return bufq;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct msm_isp_buffer *msm_isp_get_buf_ptr(
|
||||
struct msm_isp_buf_mgr *buf_mgr,
|
||||
uint32_t bufq_handle, uint32_t buf_index)
|
||||
{
|
||||
struct msm_isp_bufq *bufq = NULL;
|
||||
struct msm_isp_buffer *buf_info = NULL;
|
||||
|
||||
bufq = msm_isp_get_bufq(buf_mgr, bufq_handle);
|
||||
if (!bufq) {
|
||||
pr_err("%s: Invalid bufq\n", __func__);
|
||||
return buf_info;
|
||||
}
|
||||
|
||||
if (bufq->num_bufs <= buf_index) {
|
||||
pr_err("%s: Invalid buf index\n", __func__);
|
||||
return buf_info;
|
||||
}
|
||||
buf_info = &bufq->bufs[buf_index];
|
||||
return buf_info;
|
||||
}
|
||||
|
||||
static uint32_t msm_isp_get_buf_handle(
|
||||
struct msm_isp_buf_mgr *buf_mgr)
|
||||
{
|
||||
int i;
|
||||
if ((buf_mgr->buf_handle_cnt << 8) == 0)
|
||||
buf_mgr->buf_handle_cnt++;
|
||||
|
||||
for (i = 0; i < buf_mgr->num_buf_q; i++) {
|
||||
if (buf_mgr->bufq[i].bufq_handle == 0) {
|
||||
memset(&buf_mgr->bufq[i],
|
||||
0, sizeof(struct msm_isp_bufq));
|
||||
buf_mgr->bufq[i].bufq_handle =
|
||||
(++buf_mgr->buf_handle_cnt) << 8 | i;
|
||||
return buf_mgr->bufq[i].bufq_handle;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_isp_free_buf_handle(struct msm_isp_buf_mgr *buf_mgr,
|
||||
uint32_t bufq_handle)
|
||||
{
|
||||
struct msm_isp_bufq *bufq =
|
||||
msm_isp_get_bufq(buf_mgr, bufq_handle);
|
||||
if (!bufq)
|
||||
return -EINVAL;
|
||||
memset(bufq, 0, sizeof(struct msm_isp_bufq));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_isp_prepare_v4l2_buf(struct msm_isp_buf_mgr *buf_mgr,
|
||||
struct msm_isp_buffer *buf_info,
|
||||
struct v4l2_buffer *v4l2_buf)
|
||||
{
|
||||
int i, rc = -1;
|
||||
struct msm_isp_buffer_mapped_info *mapped_info;
|
||||
for (i = 0; i < v4l2_buf->length; i++) {
|
||||
mapped_info = &buf_info->mapped_info[i];
|
||||
mapped_info->handle =
|
||||
ion_import_dma_buf(buf_mgr->client,
|
||||
v4l2_buf->m.planes[i].m.userptr);
|
||||
if (IS_ERR_OR_NULL(mapped_info->handle)) {
|
||||
pr_err("%s: buf has null/error ION handle %p\n",
|
||||
__func__, mapped_info->handle);
|
||||
goto ion_map_error;
|
||||
}
|
||||
if (ion_map_iommu(buf_mgr->client, mapped_info->handle,
|
||||
buf_mgr->iommu_domain_num, 0, SZ_4K,
|
||||
0, &(mapped_info->paddr),
|
||||
&(mapped_info->len), 0, 0) < 0) {
|
||||
rc = -EINVAL;
|
||||
pr_err("%s: cannot map address", __func__);
|
||||
ion_free(buf_mgr->client, mapped_info->handle);
|
||||
goto ion_map_error;
|
||||
}
|
||||
mapped_info->paddr += v4l2_buf->m.planes[i].data_offset;
|
||||
CDBG("%s: plane: %d addr:%lu\n",
|
||||
__func__, i, mapped_info->paddr);
|
||||
}
|
||||
buf_info->num_planes = v4l2_buf->length;
|
||||
return 0;
|
||||
ion_map_error:
|
||||
for (--i; i >= 0; i--) {
|
||||
mapped_info = &buf_info->mapped_info[i];
|
||||
ion_unmap_iommu(buf_mgr->client, mapped_info->handle,
|
||||
buf_mgr->iommu_domain_num, 0);
|
||||
ion_free(buf_mgr->client, mapped_info->handle);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void msm_isp_unprepare_v4l2_buf(
|
||||
struct msm_isp_buf_mgr *buf_mgr,
|
||||
struct msm_isp_buffer *buf_info)
|
||||
{
|
||||
int i;
|
||||
struct msm_isp_buffer_mapped_info *mapped_info;
|
||||
for (i = 0; i < buf_info->num_planes; i++) {
|
||||
mapped_info = &buf_info->mapped_info[i];
|
||||
ion_unmap_iommu(buf_mgr->client, mapped_info->handle,
|
||||
buf_mgr->iommu_domain_num, 0);
|
||||
ion_free(buf_mgr->client, mapped_info->handle);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static int msm_isp_buf_prepare(struct msm_isp_buf_mgr *buf_mgr,
|
||||
struct msm_isp_qbuf_info *info, struct vb2_buffer *vb2_buf)
|
||||
{
|
||||
int rc = -1;
|
||||
struct msm_isp_buffer *buf_info = NULL;
|
||||
struct v4l2_buffer *buf = NULL;
|
||||
struct v4l2_plane *plane = NULL;
|
||||
|
||||
buf_info = msm_isp_get_buf_ptr(buf_mgr,
|
||||
info->handle, info->buf_idx);
|
||||
if (!buf_info) {
|
||||
pr_err("Invalid buffer prepare\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (buf_info->state == MSM_ISP_BUFFER_STATE_UNUSED ||
|
||||
buf_info->state != MSM_ISP_BUFFER_STATE_INITIALIZED) {
|
||||
pr_err("%s: Invalid buffer state: %d\n",
|
||||
__func__, buf_info->state);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (vb2_buf) {
|
||||
buf = &vb2_buf->v4l2_buf;
|
||||
buf_info->vb2_buf = vb2_buf;
|
||||
} else {
|
||||
buf = &info->buffer;
|
||||
plane =
|
||||
kzalloc(sizeof(struct v4l2_plane) * buf->length,
|
||||
GFP_KERNEL);
|
||||
if (!plane) {
|
||||
pr_err("%s: Cannot alloc plane: %d\n",
|
||||
__func__, buf_info->state);
|
||||
return rc;
|
||||
}
|
||||
if (copy_from_user(plane,
|
||||
(void __user *)(buf->m.planes),
|
||||
sizeof(struct v4l2_plane) * buf->length)) {
|
||||
kfree(plane);
|
||||
return rc;
|
||||
}
|
||||
buf->m.planes = plane;
|
||||
}
|
||||
|
||||
rc = msm_isp_prepare_v4l2_buf(buf_mgr, buf_info, buf);
|
||||
if (rc < 0) {
|
||||
pr_err("%s: Prepare buffer error\n", __func__);
|
||||
kfree(plane);
|
||||
return rc;
|
||||
}
|
||||
buf_info->state = MSM_ISP_BUFFER_STATE_PREPARED;
|
||||
kfree(plane);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int msm_isp_buf_unprepare(struct msm_isp_buf_mgr *buf_mgr,
|
||||
uint32_t buf_handle)
|
||||
{
|
||||
int rc = -1, i;
|
||||
struct msm_isp_bufq *bufq = NULL;
|
||||
struct msm_isp_buffer *buf_info = NULL;
|
||||
bufq = msm_isp_get_bufq(buf_mgr, buf_handle);
|
||||
if (!bufq) {
|
||||
pr_err("%s: Invalid bufq\n", __func__);
|
||||
return rc;
|
||||
}
|
||||
|
||||
for (i = 0; i < bufq->num_bufs; i++) {
|
||||
buf_info = msm_isp_get_buf_ptr(buf_mgr, buf_handle, i);
|
||||
if (buf_info->state == MSM_ISP_BUFFER_STATE_UNUSED ||
|
||||
buf_info->state ==
|
||||
MSM_ISP_BUFFER_STATE_INITIALIZED)
|
||||
continue;
|
||||
msm_isp_unprepare_v4l2_buf(buf_mgr, buf_info);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_isp_get_buf(struct msm_isp_buf_mgr *buf_mgr,
|
||||
uint32_t bufq_handle, struct msm_isp_buffer **buf_info)
|
||||
{
|
||||
int rc = -1;
|
||||
struct msm_isp_buffer *temp_buf_info;
|
||||
struct msm_isp_bufq *bufq = NULL;
|
||||
struct vb2_buffer *vb2_buf = NULL;
|
||||
bufq = msm_isp_get_bufq(buf_mgr, bufq_handle);
|
||||
if (!bufq) {
|
||||
pr_err("%s: Invalid bufq\n", __func__);
|
||||
return rc;
|
||||
}
|
||||
|
||||
*buf_info = NULL;
|
||||
if (BUF_SRC(bufq->stream_id)) {
|
||||
list_for_each_entry(temp_buf_info, &bufq->head, list) {
|
||||
if (temp_buf_info->state ==
|
||||
MSM_ISP_BUFFER_STATE_QUEUED) {
|
||||
/* found one buf */
|
||||
list_del_init(&temp_buf_info->list);
|
||||
*buf_info = temp_buf_info;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
vb2_buf = buf_mgr->vb2_ops->get_buf(
|
||||
bufq->session_id, bufq->stream_id);
|
||||
if (vb2_buf) {
|
||||
if (vb2_buf->v4l2_buf.index < bufq->num_bufs) {
|
||||
*buf_info =
|
||||
&bufq->bufs[vb2_buf->v4l2_buf.index];
|
||||
(*buf_info)->vb2_buf = vb2_buf;
|
||||
} else {
|
||||
pr_err("%s: Incorrect buf index %d\n",
|
||||
__func__, vb2_buf->v4l2_buf.index);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(*buf_info)) {
|
||||
pr_err("%s: No free buffer\n", __func__);
|
||||
return rc;
|
||||
}
|
||||
|
||||
(*buf_info)->state = MSM_ISP_BUFFER_STATE_DEQUEUED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_isp_put_buf(struct msm_isp_buf_mgr *buf_mgr,
|
||||
uint32_t bufq_handle, uint32_t buf_index)
|
||||
{
|
||||
int rc = -1;
|
||||
struct msm_isp_bufq *bufq = NULL;
|
||||
struct msm_isp_buffer *buf_info = NULL;
|
||||
|
||||
bufq = msm_isp_get_bufq(buf_mgr, bufq_handle);
|
||||
if (!bufq) {
|
||||
pr_err("%s: Invalid bufq\n", __func__);
|
||||
return rc;
|
||||
}
|
||||
|
||||
buf_info = msm_isp_get_buf_ptr(buf_mgr, bufq_handle, buf_index);
|
||||
if (!buf_info) {
|
||||
pr_err("%s: buf not found\n", __func__);
|
||||
return rc;
|
||||
}
|
||||
|
||||
switch (buf_info->state) {
|
||||
case MSM_ISP_BUFFER_STATE_PREPARED:
|
||||
case MSM_ISP_BUFFER_STATE_DEQUEUED:
|
||||
case MSM_ISP_BUFFER_STATE_DISPATCHED:
|
||||
if (BUF_SRC(bufq->stream_id))
|
||||
list_add_tail(&buf_info->list, &bufq->head);
|
||||
else
|
||||
buf_mgr->vb2_ops->put_buf(buf_info->vb2_buf);
|
||||
buf_info->state = MSM_ISP_BUFFER_STATE_QUEUED;
|
||||
rc = 0;
|
||||
break;
|
||||
default:
|
||||
pr_err("%s: incorrect state = %d",
|
||||
__func__, buf_info->state);
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int msm_isp_buf_done(struct msm_isp_buf_mgr *buf_mgr,
|
||||
uint32_t bufq_handle, uint32_t buf_index,
|
||||
struct timeval *tv, uint32_t frame_id)
|
||||
{
|
||||
int rc = -1;
|
||||
struct msm_isp_bufq *bufq = NULL;
|
||||
struct msm_isp_buffer *buf_info = NULL;
|
||||
|
||||
bufq = msm_isp_get_bufq(buf_mgr, bufq_handle);
|
||||
if (!bufq) {
|
||||
pr_err("Invalid bufq\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
buf_info = msm_isp_get_buf_ptr(buf_mgr, bufq_handle, buf_index);
|
||||
if (!buf_info) {
|
||||
pr_err("%s: buf not found\n", __func__);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (buf_info->state == MSM_ISP_BUFFER_STATE_DEQUEUED) {
|
||||
buf_info->state = MSM_ISP_BUFFER_STATE_DISPATCHED;
|
||||
if (!(BUF_SRC(bufq->stream_id))) {
|
||||
buf_info->vb2_buf->v4l2_buf.timestamp = *tv;
|
||||
buf_info->vb2_buf->v4l2_buf.sequence = frame_id;
|
||||
buf_mgr->vb2_ops->buf_done(buf_info->vb2_buf);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_isp_buf_enqueue(struct msm_isp_buf_mgr *buf_mgr,
|
||||
struct msm_isp_qbuf_info *info)
|
||||
{
|
||||
int rc;
|
||||
struct msm_isp_bufq *bufq = NULL;
|
||||
rc = msm_isp_buf_prepare(buf_mgr, info, NULL);
|
||||
if (rc < 0) {
|
||||
pr_err("%s: Buf prepare failed\n", __func__);
|
||||
return rc;
|
||||
}
|
||||
|
||||
bufq = msm_isp_get_bufq(buf_mgr, info->handle);
|
||||
if (BUF_SRC(bufq->stream_id)) {
|
||||
rc = msm_isp_put_buf(buf_mgr, info->handle, info->buf_idx);
|
||||
if (rc < 0) {
|
||||
pr_err("%s: Buf put failed\n", __func__);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int msm_isp_get_bufq_handle(struct msm_isp_buf_mgr *buf_mgr,
|
||||
uint32_t session_id, uint32_t stream_id)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < buf_mgr->num_buf_q; i++) {
|
||||
if (buf_mgr->bufq[i].session_id == session_id &&
|
||||
buf_mgr->bufq[i].stream_id == stream_id) {
|
||||
return buf_mgr->bufq[i].bufq_handle;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_isp_request_bufq(struct msm_isp_buf_mgr *buf_mgr,
|
||||
struct msm_isp_buf_request *buf_request)
|
||||
{
|
||||
int rc = -1, i;
|
||||
struct msm_isp_bufq *bufq = NULL;
|
||||
CDBG("%s: E\n", __func__);
|
||||
|
||||
if (!buf_request->num_buf) {
|
||||
pr_err("Invalid buffer request\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
buf_request->handle = msm_isp_get_buf_handle(buf_mgr);
|
||||
if (!buf_request->handle) {
|
||||
pr_err("Invalid buffer handle\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
bufq = msm_isp_get_bufq(buf_mgr, buf_request->handle);
|
||||
if (!bufq) {
|
||||
pr_err("Invalid buffer queue\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
bufq->bufs = kzalloc(sizeof(struct msm_isp_buffer) *
|
||||
buf_request->num_buf, GFP_KERNEL);
|
||||
if (!bufq->bufs) {
|
||||
pr_err("No free memory for buf info\n");
|
||||
msm_isp_free_buf_handle(buf_mgr, buf_request->handle);
|
||||
return rc;
|
||||
}
|
||||
|
||||
bufq->bufq_handle = buf_request->handle;
|
||||
bufq->session_id = buf_request->session_id;
|
||||
bufq->stream_id = buf_request->stream_id;
|
||||
bufq->num_bufs = buf_request->num_buf;
|
||||
INIT_LIST_HEAD(&bufq->head);
|
||||
for (i = 0; i < buf_request->num_buf; i++) {
|
||||
bufq->bufs[i].state = MSM_ISP_BUFFER_STATE_INITIALIZED;
|
||||
bufq->bufs[i].bufq_handle = bufq->bufq_handle;
|
||||
bufq->bufs[i].buf_idx = i;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_isp_release_bufq(struct msm_isp_buf_mgr *buf_mgr,
|
||||
uint32_t bufq_handle)
|
||||
{
|
||||
struct msm_isp_bufq *bufq = NULL;
|
||||
int rc = -1;
|
||||
bufq = msm_isp_get_bufq(buf_mgr, bufq_handle);
|
||||
if (!bufq) {
|
||||
pr_err("Invalid bufq release\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
msm_isp_buf_unprepare(buf_mgr, bufq_handle);
|
||||
|
||||
kfree(bufq->bufs);
|
||||
msm_isp_free_buf_handle(buf_mgr, bufq_handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void msm_isp_release_all_bufq(
|
||||
struct msm_isp_buf_mgr *buf_mgr)
|
||||
{
|
||||
struct msm_isp_bufq *bufq = NULL;
|
||||
int i;
|
||||
for (i = 0; i < buf_mgr->num_buf_q; i++) {
|
||||
bufq = &buf_mgr->bufq[i];
|
||||
if (!bufq->bufq_handle)
|
||||
continue;
|
||||
msm_isp_buf_unprepare(buf_mgr, bufq->bufq_handle);
|
||||
kfree(bufq->bufs);
|
||||
msm_isp_free_buf_handle(buf_mgr, bufq->bufq_handle);
|
||||
}
|
||||
}
|
||||
|
||||
static int msm_isp_attach_ctx(struct msm_isp_buf_mgr *buf_mgr,
|
||||
struct device *iommu_ctx)
|
||||
{
|
||||
int rc;
|
||||
rc = iommu_attach_device(buf_mgr->iommu_domain, iommu_ctx);
|
||||
if (rc) {
|
||||
pr_err("%s: Iommu attach error\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void msm_isp_detach_ctx(struct msm_isp_buf_mgr *buf_mgr,
|
||||
struct device *iommu_ctx)
|
||||
{
|
||||
iommu_detach_device(buf_mgr->iommu_domain, iommu_ctx);
|
||||
}
|
||||
|
||||
static int msm_isp_init_isp_buf_mgr(
|
||||
struct msm_isp_buf_mgr *buf_mgr,
|
||||
const char *ctx_name, uint16_t num_buf_q)
|
||||
{
|
||||
int rc = -1;
|
||||
if (!num_buf_q) {
|
||||
pr_err("Invalid buffer queue number\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
CDBG("%s: E\n", __func__);
|
||||
buf_mgr->num_buf_q = num_buf_q;
|
||||
buf_mgr->bufq =
|
||||
kzalloc(sizeof(struct msm_isp_bufq) * num_buf_q,
|
||||
GFP_KERNEL);
|
||||
if (!buf_mgr->bufq) {
|
||||
pr_err("Bufq malloc error\n");
|
||||
goto bufq_error;
|
||||
}
|
||||
buf_mgr->client = msm_ion_client_create(-1, ctx_name);
|
||||
buf_mgr->buf_handle_cnt = 0;
|
||||
|
||||
return 0;
|
||||
bufq_error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int msm_isp_deinit_isp_buf_mgr(
|
||||
struct msm_isp_buf_mgr *buf_mgr)
|
||||
{
|
||||
msm_isp_release_all_bufq(buf_mgr);
|
||||
ion_client_destroy(buf_mgr->client);
|
||||
kfree(buf_mgr->bufq);
|
||||
buf_mgr->num_buf_q = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int msm_isp_proc_buf_cmd(struct msm_isp_buf_mgr *buf_mgr,
|
||||
unsigned int cmd, void *arg)
|
||||
{
|
||||
switch (cmd) {
|
||||
case VIDIOC_MSM_ISP_REQUEST_BUF: {
|
||||
struct msm_isp_buf_request *buf_req = arg;
|
||||
buf_mgr->ops->request_buf(buf_mgr, buf_req);
|
||||
break;
|
||||
}
|
||||
case VIDIOC_MSM_ISP_ENQUEUE_BUF: {
|
||||
struct msm_isp_qbuf_info *qbuf_info = arg;
|
||||
buf_mgr->ops->enqueue_buf(buf_mgr, qbuf_info);
|
||||
break;
|
||||
}
|
||||
case VIDIOC_MSM_ISP_RELEASE_BUF: {
|
||||
struct msm_isp_buf_request *buf_req = arg;
|
||||
buf_mgr->ops->release_buf(buf_mgr, buf_req->handle);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct msm_isp_buf_ops isp_buf_ops = {
|
||||
.request_buf = msm_isp_request_bufq,
|
||||
.enqueue_buf = msm_isp_buf_enqueue,
|
||||
.release_buf = msm_isp_release_bufq,
|
||||
.get_bufq_handle = msm_isp_get_bufq_handle,
|
||||
.get_buf = msm_isp_get_buf,
|
||||
.put_buf = msm_isp_put_buf,
|
||||
.buf_done = msm_isp_buf_done,
|
||||
.attach_ctx = msm_isp_attach_ctx,
|
||||
.detach_ctx = msm_isp_detach_ctx,
|
||||
.buf_mgr_init = msm_isp_init_isp_buf_mgr,
|
||||
.buf_mgr_deinit = msm_isp_deinit_isp_buf_mgr,
|
||||
};
|
||||
|
||||
int msm_isp_create_isp_buf_mgr(
|
||||
struct msm_isp_buf_mgr *buf_mgr,
|
||||
struct msm_sd_req_vb2_q *vb2_ops,
|
||||
struct msm_iova_layout *iova_layout)
|
||||
{
|
||||
int rc = 0;
|
||||
if (buf_mgr->init_done)
|
||||
return rc;
|
||||
|
||||
buf_mgr->iommu_domain_num = msm_register_domain(iova_layout);
|
||||
if (buf_mgr->iommu_domain_num < 0) {
|
||||
pr_err("%s: Invalid iommu domain number\n", __func__);
|
||||
rc = -1;
|
||||
goto iommu_domain_error;
|
||||
}
|
||||
|
||||
buf_mgr->iommu_domain = msm_get_iommu_domain(
|
||||
buf_mgr->iommu_domain_num);
|
||||
if (!buf_mgr->iommu_domain) {
|
||||
pr_err("%s: Invalid iommu domain\n", __func__);
|
||||
rc = -1;
|
||||
goto iommu_domain_error;
|
||||
}
|
||||
|
||||
buf_mgr->ops = &isp_buf_ops;
|
||||
buf_mgr->vb2_ops = vb2_ops;
|
||||
buf_mgr->init_done = 1;
|
||||
buf_mgr->ref_count = 0;
|
||||
return 0;
|
||||
iommu_domain_error:
|
||||
return rc;
|
||||
}
|
||||
123
drivers/media/video/msmb/isp/msm_buf_mgr.h
Normal file
123
drivers/media/video/msmb/isp/msm_buf_mgr.h
Normal file
@@ -0,0 +1,123 @@
|
||||
/* Copyright (c) 2013, 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_BUF_H_
|
||||
#define _MSM_ISP_BUF_H_
|
||||
|
||||
#include <media/msmb_isp.h>
|
||||
#include <mach/iommu_domains.h>
|
||||
#include "msm_sd.h"
|
||||
|
||||
#define BUF_SRC_SHIFT 16
|
||||
/*Buffer source can be from userspace / HAL*/
|
||||
#define BUF_SRC(id) (id >> BUF_SRC_SHIFT)
|
||||
|
||||
struct msm_isp_buf_mgr;
|
||||
|
||||
enum msm_isp_buffer_state {
|
||||
MSM_ISP_BUFFER_STATE_UNUSED, /* not used */
|
||||
MSM_ISP_BUFFER_STATE_INITIALIZED, /* REQBUF done */
|
||||
MSM_ISP_BUFFER_STATE_PREPARED, /* BUF mapped */
|
||||
MSM_ISP_BUFFER_STATE_QUEUED, /* buf queued */
|
||||
MSM_ISP_BUFFER_STATE_DEQUEUED, /* in use in VFE */
|
||||
MSM_ISP_BUFFER_STATE_DISPATCHED, /* sent to userspace */
|
||||
};
|
||||
|
||||
struct msm_isp_buffer_mapped_info {
|
||||
unsigned long len;
|
||||
unsigned long paddr;
|
||||
struct ion_handle *handle;
|
||||
};
|
||||
|
||||
struct msm_isp_buffer {
|
||||
/*Common Data structure*/
|
||||
int num_planes;
|
||||
struct msm_isp_buffer_mapped_info mapped_info[VIDEO_MAX_PLANES];
|
||||
int buf_idx;
|
||||
uint32_t bufq_handle;
|
||||
|
||||
/*Native buffer*/
|
||||
struct list_head list;
|
||||
enum msm_isp_buffer_state state;
|
||||
|
||||
/*Vb2 buffer data*/
|
||||
struct vb2_buffer *vb2_buf;
|
||||
|
||||
};
|
||||
|
||||
struct msm_isp_bufq {
|
||||
uint32_t session_id;
|
||||
uint32_t stream_id;
|
||||
uint32_t num_bufs;
|
||||
uint32_t bufq_handle;
|
||||
struct msm_isp_buffer *bufs;
|
||||
|
||||
/*Native buffer queue*/
|
||||
struct list_head head;
|
||||
};
|
||||
|
||||
struct msm_isp_buf_ops {
|
||||
int (*request_buf) (struct msm_isp_buf_mgr *buf_mgr,
|
||||
struct msm_isp_buf_request *buf_request);
|
||||
|
||||
int (*enqueue_buf) (struct msm_isp_buf_mgr *buf_mgr,
|
||||
struct msm_isp_qbuf_info *info);
|
||||
|
||||
int (*release_buf) (struct msm_isp_buf_mgr *buf_mgr,
|
||||
uint32_t bufq_handle);
|
||||
|
||||
int (*get_bufq_handle) (struct msm_isp_buf_mgr *buf_mgr,
|
||||
uint32_t session_id, uint32_t stream_id);
|
||||
|
||||
int (*get_buf) (struct msm_isp_buf_mgr *buf_mgr,
|
||||
uint32_t bufq_handle, struct msm_isp_buffer **buf_info);
|
||||
|
||||
int (*put_buf) (struct msm_isp_buf_mgr *buf_mgr,
|
||||
uint32_t bufq_handle, uint32_t buf_index);
|
||||
|
||||
int (*buf_done) (struct msm_isp_buf_mgr *buf_mgr,
|
||||
uint32_t bufq_handle, uint32_t buf_index,
|
||||
struct timeval *tv, uint32_t frame_id);
|
||||
int (*attach_ctx) (struct msm_isp_buf_mgr *buf_mgr,
|
||||
struct device *iommu_ctx);
|
||||
void (*detach_ctx) (struct msm_isp_buf_mgr *buf_mgr,
|
||||
struct device *iommu_ctx);
|
||||
int (*buf_mgr_init) (struct msm_isp_buf_mgr *buf_mgr,
|
||||
const char *ctx_name, uint16_t num_buf_q);
|
||||
int (*buf_mgr_deinit) (struct msm_isp_buf_mgr *buf_mgr);
|
||||
};
|
||||
|
||||
struct msm_isp_buf_mgr {
|
||||
int init_done;
|
||||
uint32_t ref_count;
|
||||
spinlock_t lock;
|
||||
uint16_t num_buf_q;
|
||||
struct msm_isp_bufq *bufq;
|
||||
|
||||
struct ion_client *client;
|
||||
struct msm_isp_buf_ops *ops;
|
||||
uint32_t buf_handle_cnt;
|
||||
|
||||
struct msm_sd_req_vb2_q *vb2_ops;
|
||||
|
||||
/*IOMMU specific*/
|
||||
int iommu_domain_num;
|
||||
struct iommu_domain *iommu_domain;
|
||||
};
|
||||
|
||||
int msm_isp_create_isp_buf_mgr(struct msm_isp_buf_mgr *buf_mgr,
|
||||
struct msm_sd_req_vb2_q *vb2_ops, struct msm_iova_layout *iova_layout);
|
||||
|
||||
int msm_isp_proc_buf_cmd(struct msm_isp_buf_mgr *buf_mgr,
|
||||
unsigned int cmd, void *arg);
|
||||
|
||||
#endif /* _MSM_ISP_BUF_H_ */
|
||||
168
drivers/media/video/msmb/isp/msm_isp.c
Normal file
168
drivers/media/video/msmb/isp/msm_isp.c
Normal file
@@ -0,0 +1,168 @@
|
||||
/* Copyright (c) 2013, 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/platform_device.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <mach/board.h>
|
||||
#include <mach/vreg.h>
|
||||
#include <mach/iommu.h>
|
||||
|
||||
#include "msm_isp.h"
|
||||
#include "msm_isp_util.h"
|
||||
#include "msm_isp_axi_util.h"
|
||||
#include "msm_isp_stats_util.h"
|
||||
#include "msm_sd.h"
|
||||
#include "msm_isp40.h"
|
||||
|
||||
static struct msm_sd_req_vb2_q vfe_vb2_ops;
|
||||
|
||||
static const struct of_device_id msm_vfe_dt_match[] = {
|
||||
{
|
||||
.compatible = "qcom,vfe40",
|
||||
.data = &vfe40_hw_info,
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, msm_vfe_dt_match);
|
||||
|
||||
static const struct platform_device_id msm_vfe_dev_id[] = {
|
||||
{"msm_vfe32"},
|
||||
{}
|
||||
};
|
||||
|
||||
static struct msm_isp_buf_mgr vfe_buf_mgr;
|
||||
|
||||
static int __devinit 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;
|
||||
|
||||
struct msm_iova_partition vfe_partition = {
|
||||
.start = SZ_128K,
|
||||
.size = SZ_2G - SZ_128K,
|
||||
};
|
||||
struct msm_iova_layout vfe_layout = {
|
||||
.partitions = &vfe_partition,
|
||||
.npartitions = 1,
|
||||
.client_name = "vfe",
|
||||
.domain_flags = 0,
|
||||
};
|
||||
|
||||
vfe_dev = kzalloc(sizeof(struct vfe_device), GFP_KERNEL);
|
||||
if (!vfe_dev) {
|
||||
pr_err("%s: no enough memory\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
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);
|
||||
vfe_dev->hw_info =
|
||||
(struct msm_vfe_hardware_info *) match_dev->data;
|
||||
} else {
|
||||
vfe_dev->hw_info = platform_get_drvdata(pdev);
|
||||
}
|
||||
|
||||
if (!vfe_dev->hw_info) {
|
||||
pr_err("%s: No vfe hardware info\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
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__);
|
||||
kfree(vfe_dev);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
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->mutex);
|
||||
spin_lock_init(&vfe_dev->tasklet_lock);
|
||||
spin_lock_init(&vfe_dev->shared_data_lock);
|
||||
media_entity_init(&vfe_dev->subdev.sd.entity, 0, NULL, 0);
|
||||
vfe_dev->subdev.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
|
||||
vfe_dev->subdev.sd.entity.group_id = MSM_CAMERA_SUBDEV_VFE;
|
||||
vfe_dev->subdev.sd.entity.name = pdev->name;
|
||||
rc = msm_sd_register(&vfe_dev->subdev);
|
||||
if (rc != 0) {
|
||||
pr_err("%s: msm_sd_register error = %d\n", __func__, rc);
|
||||
kfree(vfe_dev);
|
||||
goto end;
|
||||
}
|
||||
|
||||
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, &vfe_layout);
|
||||
if (rc < 0) {
|
||||
pr_err("%s: Unable to create buffer manager\n", __func__);
|
||||
kfree(vfe_dev);
|
||||
return -EINVAL;
|
||||
}
|
||||
vfe_dev->vfe_open_cnt = 0;
|
||||
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");
|
||||
347
drivers/media/video/msmb/isp/msm_isp.h
Normal file
347
drivers/media/video/msmb/isp/msm_isp.h
Normal file
@@ -0,0 +1,347 @@
|
||||
/* Copyright (c) 2013, 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 <mach/msm_bus.h>
|
||||
#include <mach/msm_bus_board.h>
|
||||
|
||||
#include "msm_buf_mgr.h"
|
||||
|
||||
#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_SUB(a) ((a > 0) ? a-1 : 0)
|
||||
|
||||
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_camif_update_state {
|
||||
NO_UPDATE,
|
||||
ENABLE_CAMIF,
|
||||
DISABLE_CAMIF,
|
||||
DISABLE_CAMIF_IMMEDIATELY
|
||||
};
|
||||
|
||||
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);
|
||||
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);
|
||||
void (*process_axi_irq) (struct vfe_device *vfe_dev,
|
||||
uint32_t irq_status0, uint32_t irq_status1,
|
||||
struct timeval *tv);
|
||||
void (*process_error_irq) (struct vfe_device *vfe_dev,
|
||||
uint32_t irq_status0, uint32_t irq_status1);
|
||||
void (*process_stats_irq) (struct vfe_device *vfe_dev,
|
||||
uint32_t irq_status0, uint32_t irq_status1,
|
||||
struct timeval *tv);
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
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_request_cmd *stream_cfg_cmd,
|
||||
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_request_cmd *stream_cfg_cmd,
|
||||
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_rdi_reg) (struct vfe_device *vfe_dev,
|
||||
struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
|
||||
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, unsigned long 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);
|
||||
long (*halt) (struct vfe_device *vfe_dev);
|
||||
};
|
||||
|
||||
struct msm_vfe_core_ops {
|
||||
void (*epoch_irq) (struct vfe_device *vfe_dev,
|
||||
uint32_t epoch_line0, uint32_t epoch_line1);
|
||||
void (*reg_update) (struct vfe_device *vfe_dev, uint32_t update_mask);
|
||||
long (*reset_hw) (struct vfe_device *vfe_dev);
|
||||
int (*init_hw) (struct vfe_device *vfe_dev);
|
||||
void (*init_hw_reg) (struct vfe_device *vfe_dev);
|
||||
void (*release_hw) (struct vfe_device *vfe_dev);
|
||||
void (*cfg_camif) (struct vfe_device *vfe_dev,
|
||||
struct msm_vfe_pix_cfg *pix_cfg);
|
||||
void (*update_camif_state) (struct vfe_device *vfe_dev,
|
||||
enum msm_isp_camif_update_state update_state);
|
||||
int (*get_platform_data) (struct vfe_device *vfe_dev);
|
||||
};
|
||||
struct msm_vfe_stats_ops {
|
||||
void (*cfg_comp_mask) (struct vfe_device *vfe_dev,
|
||||
struct msm_vfe_stats_stream *stream_info);
|
||||
void (*clear_comp_mask) (struct vfe_device *vfe_dev,
|
||||
struct msm_vfe_stats_stream *stream_info);
|
||||
void (*cfg_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_request_cmd *stream_cfg_cmd);
|
||||
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 (*stats_enable) (struct vfe_device *vfe_dev,
|
||||
uint32_t stats_mask, uint8_t enable);
|
||||
|
||||
void (*update_ping_pong_addr) (struct vfe_device *vfe_dev,
|
||||
enum msm_isp_stats_type stats_type, uint32_t pingpong_status,
|
||||
unsigned long paddr);
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
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 {
|
||||
struct msm_vfe_ops vfe_ops;
|
||||
struct msm_vfe_axi_hardware_info *axi_hw_info;
|
||||
struct v4l2_subdev_internal_ops *subdev_internal_ops;
|
||||
struct v4l2_subdev_ops *subdev_ops;
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
enum msm_vfe_axi_state {
|
||||
AVALIABLE,
|
||||
INACTIVE,
|
||||
ACTIVE,
|
||||
PAUSE,
|
||||
START_PENDING,
|
||||
STOP_PENDING,
|
||||
STOPPING,
|
||||
PAUSE_PENDING,
|
||||
};
|
||||
|
||||
#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];
|
||||
uint8_t rdi[MAX_PLANES_PER_STREAM];
|
||||
uint8_t rdi_master[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 stream_handle;
|
||||
uint8_t buf_divert;
|
||||
enum msm_vfe_axi_stream_type stream_type;
|
||||
|
||||
uint32_t framedrop_pattern;
|
||||
uint32_t init_frame_drop;
|
||||
uint32_t burst_frame_count;/*number of sof before burst stop*/
|
||||
uint8_t auto_trigger_stop;
|
||||
uint8_t framedrop_update;
|
||||
};
|
||||
|
||||
struct msm_vfe_axi_composite_info {
|
||||
uint32_t stream_handle;
|
||||
uint32_t stream_composite_mask;
|
||||
};
|
||||
struct msm_vfe_src_info {
|
||||
unsigned long frame_id;
|
||||
uint8_t active;
|
||||
uint8_t pix_stream_count;
|
||||
uint8_t raw_stream_count;
|
||||
enum msm_vfe_inputmux input_mux;
|
||||
};
|
||||
|
||||
|
||||
struct msm_vfe_stats_stream {
|
||||
uint32_t frame_id;
|
||||
uint8_t enable;
|
||||
enum msm_isp_stats_type stats_type;
|
||||
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 stream_handle;
|
||||
uint32_t framedrop_pattern;
|
||||
};
|
||||
|
||||
struct msm_vfe_stats_composite_info {
|
||||
uint32_t stream_handle;
|
||||
uint32_t stream_composite_mask;
|
||||
};
|
||||
|
||||
enum msm_wm_ub_cfg_type {
|
||||
MSM_WM_UB_CFG_DEFAULT,
|
||||
MSM_WM_UB_EQUAL_SLICING,
|
||||
MSM_WM_UB_CFG_MAX_NUM
|
||||
};
|
||||
struct msm_vfe_axi_shared_data {
|
||||
struct msm_vfe_axi_hardware_info *hw_info;
|
||||
struct msm_vfe_axi_stream stream_info[MAX_NUM_STREAM];
|
||||
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 free_rdi[MAX_NUM_RDI];
|
||||
uint8_t free_rdi_master[MAX_NUM_RDI][MAX_NUM_RDI_MASTER];
|
||||
uint8_t num_used_rdi;
|
||||
uint8_t num_active_stream;
|
||||
struct msm_vfe_axi_composite_info
|
||||
composite_info[MAX_NUM_COMPOSITE_MASK];
|
||||
uint8_t num_used_composite_mask;
|
||||
uint32_t stream_update;
|
||||
struct msm_vfe_src_info src_info[VFE_SRC_MAX];
|
||||
uint16_t stream_handle_cnt;
|
||||
unsigned long event_mask;
|
||||
};
|
||||
|
||||
struct msm_vfe_stats_shared_data {
|
||||
struct msm_vfe_stats_stream stream_info[MSM_ISP_STATS_MAX];
|
||||
struct msm_vfe_stats_composite_info
|
||||
comp_info[MAX_NUM_STATS_COMP_MASK];
|
||||
uint8_t num_active_stream;
|
||||
uint8_t num_used_composite_mask;
|
||||
uint16_t stream_handle_cnt;
|
||||
};
|
||||
struct msm_vfe_tasklet_queue_cmd {
|
||||
struct list_head list;
|
||||
uint32_t vfeInterruptStatus0;
|
||||
uint32_t vfeInterruptStatus1;
|
||||
struct timeval tv;
|
||||
uint8_t cmd_used;
|
||||
};
|
||||
|
||||
#define MSM_VFE_TASKLETQ_SIZE 200
|
||||
|
||||
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;
|
||||
|
||||
struct regulator *fs_vfe;
|
||||
struct clk *vfe_clk[7];
|
||||
|
||||
uint32_t bus_perf_client;
|
||||
|
||||
struct completion reset_complete;
|
||||
struct completion halt_complete;
|
||||
struct completion stream_config_complete;
|
||||
struct mutex 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];
|
||||
|
||||
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_isp_buf_mgr *buf_mgr;
|
||||
int dump_reg;
|
||||
uint32_t vfe_open_cnt;
|
||||
};
|
||||
|
||||
#endif
|
||||
822
drivers/media/video/msmb/isp/msm_isp32.c
Normal file
822
drivers/media/video/msmb/isp/msm_isp32.c
Normal file
@@ -0,0 +1,822 @@
|
||||
/* Copyright (c) 2013, 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/module.h>
|
||||
|
||||
#include "msm_isp32.h"
|
||||
#include "msm_isp_util.h"
|
||||
#include "msm_isp_axi_util.h"
|
||||
#include "msm_isp.h"
|
||||
#include "msm.h"
|
||||
|
||||
#define VFE32_BURST_LEN 4
|
||||
#define VFE32_EQUAL_SLICE_UB 117
|
||||
#define VFE32_WM_BASE(idx) (0x4C + 0x18 * idx)
|
||||
#define VFE32_RDI_BASE(idx) (0x734 + 0x4 * idx)
|
||||
#define VFE32_RDI_MN_BASE(m) (0x734 + 0x4 * m/3)
|
||||
#define VFE32_RDI_MN_SEL_SHIFT(m) (4*(m%3) + 4)
|
||||
#define VFE32_RDI_MN_FB_SHIFT(m) ((m%3) + 16)
|
||||
#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 >> wm) & 0x1)))
|
||||
|
||||
/*Temporary use fixed bus vectors in VFE */
|
||||
static struct msm_bus_vectors msm_vfe32_init_vectors[] = {
|
||||
{
|
||||
.src = MSM_BUS_MASTER_VFE,
|
||||
.dst = MSM_BUS_SLAVE_EBI_CH0,
|
||||
.ab = 0,
|
||||
.ib = 0,
|
||||
},
|
||||
};
|
||||
|
||||
static struct msm_bus_vectors msm_vfe32_preview_vectors[] = {
|
||||
{
|
||||
.src = MSM_BUS_MASTER_VFE,
|
||||
.dst = MSM_BUS_SLAVE_EBI_CH0,
|
||||
.ab = 1027648000,
|
||||
.ib = 1105920000,
|
||||
},
|
||||
};
|
||||
|
||||
static struct msm_bus_paths msm_vfe32_bus_client_config[] = {
|
||||
{
|
||||
ARRAY_SIZE(msm_vfe32_init_vectors),
|
||||
msm_vfe32_init_vectors,
|
||||
},
|
||||
{
|
||||
ARRAY_SIZE(msm_vfe32_preview_vectors),
|
||||
msm_vfe32_preview_vectors,
|
||||
},
|
||||
};
|
||||
|
||||
static struct msm_bus_scale_pdata msm_vfe32_bus_client_pdata = {
|
||||
msm_vfe32_bus_client_config,
|
||||
ARRAY_SIZE(msm_vfe32_bus_client_config),
|
||||
.name = "msm_camera_vfe",
|
||||
};
|
||||
|
||||
static struct msm_cam_clk_info msm_vfe32_clk_info[] = {
|
||||
{"vfe_clk", 228570000},
|
||||
{"vfe_pclk", -1},
|
||||
{"csi_vfe_clk", -1},
|
||||
};
|
||||
|
||||
static int msm_vfe32_init_hardware(struct vfe_device *vfe_dev)
|
||||
{
|
||||
int rc = -1;
|
||||
|
||||
vfe_dev->bus_perf_client =
|
||||
msm_bus_scale_register_client(&msm_vfe32_bus_client_pdata);
|
||||
if (!vfe_dev->bus_perf_client) {
|
||||
pr_err("%s: Registration Failed!\n", __func__);
|
||||
vfe_dev->bus_perf_client = 0;
|
||||
goto bus_scale_register_failed;
|
||||
}
|
||||
msm_bus_scale_client_update_request(vfe_dev->bus_perf_client, 1);
|
||||
|
||||
if (vfe_dev->fs_vfe) {
|
||||
rc = regulator_enable(vfe_dev->fs_vfe);
|
||||
if (rc) {
|
||||
pr_err("%s: Regulator enable failed\n", __func__);
|
||||
goto fs_failed;
|
||||
}
|
||||
}
|
||||
|
||||
rc = msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe32_clk_info,
|
||||
vfe_dev->vfe_clk, ARRAY_SIZE(msm_vfe32_clk_info), 1);
|
||||
if (rc < 0)
|
||||
goto clk_enable_failed;
|
||||
|
||||
vfe_dev->vfe_base = ioremap(vfe_dev->vfe_mem->start,
|
||||
resource_size(vfe_dev->vfe_mem));
|
||||
if (!vfe_dev->vfe_base) {
|
||||
rc = -ENOMEM;
|
||||
pr_err("%s: vfe ioremap failed\n", __func__);
|
||||
goto vfe_remap_failed;
|
||||
}
|
||||
|
||||
rc = request_irq(vfe_dev->vfe_irq->start, msm_isp_process_irq,
|
||||
IRQF_TRIGGER_RISING, "vfe", vfe_dev);
|
||||
if (rc < 0) {
|
||||
pr_err("%s: irq request failed\n", __func__);
|
||||
goto irq_req_failed;
|
||||
}
|
||||
|
||||
return rc;
|
||||
irq_req_failed:
|
||||
iounmap(vfe_dev->vfe_base);
|
||||
vfe_remap_failed:
|
||||
msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe32_clk_info,
|
||||
vfe_dev->vfe_clk, ARRAY_SIZE(msm_vfe32_clk_info), 0);
|
||||
clk_enable_failed:
|
||||
regulator_disable(vfe_dev->fs_vfe);
|
||||
fs_failed:
|
||||
msm_bus_scale_client_update_request(vfe_dev->bus_perf_client, 0);
|
||||
msm_bus_scale_unregister_client(vfe_dev->bus_perf_client);
|
||||
bus_scale_register_failed:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void msm_vfe32_release_hardware(struct vfe_device *vfe_dev)
|
||||
{
|
||||
free_irq(vfe_dev->vfe_irq->start, vfe_dev);
|
||||
tasklet_kill(&vfe_dev->vfe_tasklet);
|
||||
iounmap(vfe_dev->vfe_base);
|
||||
msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe32_clk_info,
|
||||
vfe_dev->vfe_clk, ARRAY_SIZE(msm_vfe32_clk_info), 0);
|
||||
regulator_disable(vfe_dev->fs_vfe);
|
||||
msm_bus_scale_client_update_request(vfe_dev->bus_perf_client, 0);
|
||||
msm_bus_scale_unregister_client(vfe_dev->bus_perf_client);
|
||||
}
|
||||
|
||||
static void msm_vfe32_init_hardware_reg(struct vfe_device *vfe_dev)
|
||||
{
|
||||
/* CGC_OVERRIDE */
|
||||
msm_camera_io_w(0x07FFFFFF, vfe_dev->vfe_base + 0xC);
|
||||
/* BUS_CFG */
|
||||
msm_camera_io_w(0x00000001, vfe_dev->vfe_base + 0x3C);
|
||||
msm_camera_io_w(0x00000025, vfe_dev->vfe_base + 0x1C);
|
||||
msm_camera_io_w_mb(0x1DFFFFFF, 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);
|
||||
}
|
||||
|
||||
static void msm_vfe32_process_reset_irq(struct vfe_device *vfe_dev,
|
||||
uint32_t irq_status0, uint32_t irq_status1)
|
||||
{
|
||||
if (irq_status1 & (1 << 23))
|
||||
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))
|
||||
complete(&vfe_dev->halt_complete);
|
||||
}
|
||||
|
||||
static void msm_vfe32_process_camif_irq(struct vfe_device *vfe_dev,
|
||||
uint32_t irq_status0, uint32_t irq_status1)
|
||||
{
|
||||
if (!(irq_status0 & 0x1F))
|
||||
return;
|
||||
|
||||
if (irq_status0 & (1 << 0)) {
|
||||
ISP_DBG("%s: PIX0 frame id: %lu\n", __func__,
|
||||
vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id);
|
||||
msm_isp_update_framedrop_count(vfe_dev);
|
||||
vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id++;
|
||||
}
|
||||
}
|
||||
|
||||
static void msm_vfe32_process_violation_irq(struct vfe_device *vfe_dev)
|
||||
{
|
||||
uint32_t violation_status;
|
||||
violation_status = msm_camera_io_r(vfe_dev->vfe_base + 0x48);
|
||||
if (!violation_status)
|
||||
return;
|
||||
|
||||
if (violation_status & (1 << 0))
|
||||
pr_err("%s: black violation\n", __func__);
|
||||
if (violation_status & (1 << 1))
|
||||
pr_err("%s: rolloff violation\n", __func__);
|
||||
if (violation_status & (1 << 2))
|
||||
pr_err("%s: demux violation\n", __func__);
|
||||
if (violation_status & (1 << 3))
|
||||
pr_err("%s: demosaic violation\n", __func__);
|
||||
if (violation_status & (1 << 4))
|
||||
pr_err("%s: crop violation\n", __func__);
|
||||
if (violation_status & (1 << 5))
|
||||
pr_err("%s: scale violation\n", __func__);
|
||||
if (violation_status & (1 << 6))
|
||||
pr_err("%s: wb violation\n", __func__);
|
||||
if (violation_status & (1 << 7))
|
||||
pr_err("%s: clf violation\n", __func__);
|
||||
if (violation_status & (1 << 8))
|
||||
pr_err("%s: matrix violation\n", __func__);
|
||||
if (violation_status & (1 << 9))
|
||||
pr_err("%s: rgb lut violation\n", __func__);
|
||||
if (violation_status & (1 << 10))
|
||||
pr_err("%s: la violation\n", __func__);
|
||||
if (violation_status & (1 << 11))
|
||||
pr_err("%s: chroma enhance violation\n", __func__);
|
||||
if (violation_status & (1 << 12))
|
||||
pr_err("%s: chroma supress mce violation\n", __func__);
|
||||
if (violation_status & (1 << 13))
|
||||
pr_err("%s: skin enhance violation\n", __func__);
|
||||
if (violation_status & (1 << 14))
|
||||
pr_err("%s: asf violation\n", __func__);
|
||||
if (violation_status & (1 << 15))
|
||||
pr_err("%s: scale y violation\n", __func__);
|
||||
if (violation_status & (1 << 16))
|
||||
pr_err("%s: scale cbcr violation\n", __func__);
|
||||
if (violation_status & (1 << 17))
|
||||
pr_err("%s: chroma subsample violation\n", __func__);
|
||||
if (violation_status & (1 << 18))
|
||||
pr_err("%s: framedrop enc y violation\n", __func__);
|
||||
if (violation_status & (1 << 19))
|
||||
pr_err("%s: framedrop enc cbcr violation\n", __func__);
|
||||
if (violation_status & (1 << 20))
|
||||
pr_err("%s: framedrop view y violation\n", __func__);
|
||||
if (violation_status & (1 << 21))
|
||||
pr_err("%s: framedrop view cbcr violation\n", __func__);
|
||||
if (violation_status & (1 << 22))
|
||||
pr_err("%s: realign buf y violation\n", __func__);
|
||||
if (violation_status & (1 << 23))
|
||||
pr_err("%s: realign buf cb violation\n", __func__);
|
||||
if (violation_status & (1 << 24))
|
||||
pr_err("%s: realign buf cr violation\n", __func__);
|
||||
}
|
||||
|
||||
static void msm_vfe32_process_error_irq(struct vfe_device *vfe_dev,
|
||||
uint32_t irq_status0, uint32_t irq_status1)
|
||||
{
|
||||
uint32_t camif_status;
|
||||
if (!(irq_status1 & 0x7FFFFF))
|
||||
return;
|
||||
|
||||
if (irq_status1 & (1 << 0)) {
|
||||
camif_status = msm_camera_io_r(vfe_dev->vfe_base + 0x204);
|
||||
pr_err("%s: camif error status: 0x%x\n",
|
||||
__func__, camif_status);
|
||||
}
|
||||
if (irq_status1 & (1 << 1))
|
||||
pr_err("%s: stats bhist overwrite\n", __func__);
|
||||
if (irq_status1 & (1 << 2))
|
||||
pr_err("%s: stats cs overwrite\n", __func__);
|
||||
if (irq_status1 & (1 << 3))
|
||||
pr_err("%s: stats ihist overwrite\n", __func__);
|
||||
if (irq_status1 & (1 << 4))
|
||||
pr_err("%s: realign buf y overflow\n", __func__);
|
||||
if (irq_status1 & (1 << 5))
|
||||
pr_err("%s: realign buf cb overflow\n", __func__);
|
||||
if (irq_status1 & (1 << 6))
|
||||
pr_err("%s: realign buf cr overflow\n", __func__);
|
||||
if (irq_status1 & (1 << 7)) {
|
||||
pr_err("%s: violation\n", __func__);
|
||||
msm_vfe32_process_violation_irq(vfe_dev);
|
||||
}
|
||||
if (irq_status1 & (1 << 8))
|
||||
pr_err("%s: image master 0 bus overflow\n", __func__);
|
||||
if (irq_status1 & (1 << 9))
|
||||
pr_err("%s: image master 1 bus overflow\n", __func__);
|
||||
if (irq_status1 & (1 << 10))
|
||||
pr_err("%s: image master 2 bus overflow\n", __func__);
|
||||
if (irq_status1 & (1 << 11))
|
||||
pr_err("%s: image master 3 bus overflow\n", __func__);
|
||||
if (irq_status1 & (1 << 12))
|
||||
pr_err("%s: image master 4 bus overflow\n", __func__);
|
||||
if (irq_status1 & (1 << 13))
|
||||
pr_err("%s: image master 5 bus overflow\n", __func__);
|
||||
if (irq_status1 & (1 << 14))
|
||||
pr_err("%s: image master 6 bus overflow\n", __func__);
|
||||
if (irq_status1 & (1 << 15))
|
||||
pr_err("%s: status ae/bg bus overflow\n", __func__);
|
||||
if (irq_status1 & (1 << 16))
|
||||
pr_err("%s: status af/bf bus overflow\n", __func__);
|
||||
if (irq_status1 & (1 << 17))
|
||||
pr_err("%s: status awb bus overflow\n", __func__);
|
||||
if (irq_status1 & (1 << 18))
|
||||
pr_err("%s: status rs bus overflow\n", __func__);
|
||||
if (irq_status1 & (1 << 19))
|
||||
pr_err("%s: status cs bus overflow\n", __func__);
|
||||
if (irq_status1 & (1 << 20))
|
||||
pr_err("%s: status ihist bus overflow\n", __func__);
|
||||
if (irq_status1 & (1 << 21))
|
||||
pr_err("%s: status skin bhist bus overflow\n", __func__);
|
||||
if (irq_status1 & (1 << 22))
|
||||
pr_err("%s: axi error\n", __func__);
|
||||
}
|
||||
|
||||
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);
|
||||
msm_camera_io_w(*irq_status0, vfe_dev->vfe_base + 0x24);
|
||||
msm_camera_io_w(*irq_status1, vfe_dev->vfe_base + 0x28);
|
||||
msm_camera_io_w_mb(1, vfe_dev->vfe_base + 0x18);
|
||||
}
|
||||
|
||||
static void msm_vfe32_process_reg_update(struct vfe_device *vfe_dev,
|
||||
uint32_t irq_status0, uint32_t irq_status1)
|
||||
{
|
||||
if (!(irq_status0 & 0x20) && !(irq_status1 & 0x1C000000))
|
||||
return;
|
||||
|
||||
if (vfe_dev->axi_data.stream_update)
|
||||
msm_isp_axi_stream_update(vfe_dev);
|
||||
|
||||
msm_isp_update_framedrop_reg(vfe_dev);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void msm_vfe32_reg_update(
|
||||
struct vfe_device *vfe_dev, uint32_t update_mask)
|
||||
{
|
||||
msm_camera_io_w_mb(update_mask, vfe_dev->vfe_base + 0x260);
|
||||
}
|
||||
|
||||
static long msm_vfe32_reset_hardware(struct vfe_device *vfe_dev)
|
||||
{
|
||||
init_completion(&vfe_dev->reset_complete);
|
||||
msm_camera_io_w_mb(0x3FF, vfe_dev->vfe_base + 0x4);
|
||||
return wait_for_completion_interruptible_timeout(
|
||||
&vfe_dev->reset_complete, msecs_to_jiffies(50));
|
||||
}
|
||||
|
||||
static void msm_vfe32_axi_reload_wm(
|
||||
struct vfe_device *vfe_dev, uint32_t reload_mask)
|
||||
{
|
||||
msm_camera_io_w_mb(reload_mask, vfe_dev->vfe_base + 0x38);
|
||||
}
|
||||
|
||||
static void msm_vfe32_axi_enable_wm(struct vfe_device *vfe_dev,
|
||||
uint8_t wm_idx, uint8_t enable)
|
||||
{
|
||||
if (enable)
|
||||
msm_camera_io_w_mb(0x1,
|
||||
vfe_dev->vfe_base + VFE32_WM_BASE(wm_idx));
|
||||
else
|
||||
msm_camera_io_w_mb(0x0,
|
||||
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;
|
||||
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);
|
||||
comp_mask &= ~(0x7F << (comp_mask_index * 8));
|
||||
comp_mask |= (axi_data->composite_info[comp_mask_index].
|
||||
stream_composite_mask << (comp_mask_index * 8));
|
||||
msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x34);
|
||||
|
||||
irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C);
|
||||
irq_mask |= 1 << (comp_mask_index + 21);
|
||||
msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C);
|
||||
}
|
||||
|
||||
static void msm_vfe32_axi_clear_comp_mask(struct vfe_device *vfe_dev,
|
||||
struct msm_vfe_axi_stream *stream_info)
|
||||
{
|
||||
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);
|
||||
comp_mask &= ~(0x7F << (comp_mask_index * 8));
|
||||
msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x34);
|
||||
|
||||
irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C);
|
||||
irq_mask &= ~(1 << (comp_mask_index + 21));
|
||||
msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C);
|
||||
}
|
||||
|
||||
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;
|
||||
irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C);
|
||||
irq_mask |= 1 << (stream_info->wm[0] + 6);
|
||||
msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C);
|
||||
}
|
||||
|
||||
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;
|
||||
irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C);
|
||||
irq_mask &= ~(1 << (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 = 0;
|
||||
|
||||
if (stream_info->init_frame_drop == 0)
|
||||
framedrop_pattern = stream_info->framedrop_pattern;
|
||||
|
||||
if (stream_info->stream_type == BURST_STREAM &&
|
||||
stream_info->burst_frame_count == 0)
|
||||
framedrop_pattern = 0;
|
||||
|
||||
if (stream_info->stream_src == PIX_ENCODER) {
|
||||
msm_camera_io_w(0x1F, vfe_dev->vfe_base + 0x504);
|
||||
msm_camera_io_w(0x1F, 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(0x1F, vfe_dev->vfe_base + 0x514);
|
||||
msm_camera_io_w(0x1F, 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_dev->vfe_base + 0x260);
|
||||
}
|
||||
|
||||
static void msm_vfe32_clear_framedrop(struct vfe_device *vfe_dev,
|
||||
struct msm_vfe_axi_stream *stream_info)
|
||||
{
|
||||
if (stream_info->stream_src == PIX_ENCODER) {
|
||||
msm_camera_io_w(0, vfe_dev->vfe_base + 0x50C);
|
||||
msm_camera_io_w(0, vfe_dev->vfe_base + 0x510);
|
||||
} else if (stream_info->stream_src == PIX_VIEWFINDER) {
|
||||
msm_camera_io_w(0, vfe_dev->vfe_base + 0x51C);
|
||||
msm_camera_io_w(0, vfe_dev->vfe_base + 0x520);
|
||||
}
|
||||
}
|
||||
|
||||
static void msm_vfe32_cfg_camif(struct vfe_device *vfe_dev,
|
||||
struct msm_vfe_pix_cfg *pix_cfg)
|
||||
{
|
||||
uint16_t first_pixel, last_pixel, first_line, last_line;
|
||||
struct msm_vfe_camif_cfg *camif_cfg = &pix_cfg->camif_cfg;
|
||||
uint32_t val;
|
||||
|
||||
first_pixel = camif_cfg->left_crop;
|
||||
last_pixel = camif_cfg->pixels_per_line -
|
||||
camif_cfg->left_crop -
|
||||
camif_cfg->right_crop;
|
||||
first_line = camif_cfg->left_crop;
|
||||
last_line = camif_cfg->lines_per_frame -
|
||||
camif_cfg->top_crop -
|
||||
camif_cfg->bottom_crop;
|
||||
|
||||
msm_camera_io_w(pix_cfg->input_mux << 16 | pix_cfg->pixel_pattern,
|
||||
vfe_dev->vfe_base + 0x14);
|
||||
|
||||
msm_camera_io_w(camif_cfg->lines_per_frame << 16 |
|
||||
camif_cfg->pixels_per_line,
|
||||
vfe_dev->vfe_base + 0x1EC);
|
||||
|
||||
msm_camera_io_w(ISP_SUB(first_pixel) << 16 | ISP_SUB(last_pixel),
|
||||
vfe_dev->vfe_base + 0x1F0);
|
||||
|
||||
msm_camera_io_w(ISP_SUB(first_line) << 16 | ISP_SUB(last_line),
|
||||
vfe_dev->vfe_base + 0x1F4);
|
||||
|
||||
val = msm_camera_io_r(vfe_dev->vfe_base + 0x6FC);
|
||||
val &= 0xFFFFFFFC;
|
||||
val |= camif_cfg->camif_input;
|
||||
msm_camera_io_w(val, vfe_dev->vfe_base + 0x6FC);
|
||||
}
|
||||
|
||||
static void msm_vfe32_update_camif_state(
|
||||
struct vfe_device *vfe_dev,
|
||||
enum msm_isp_camif_update_state update_state)
|
||||
{
|
||||
uint32_t val;
|
||||
bool bus_en, vfe_en;
|
||||
if (update_state == NO_UPDATE)
|
||||
return;
|
||||
|
||||
val = msm_camera_io_r(vfe_dev->vfe_base + 0x1E4);
|
||||
if (update_state == ENABLE_CAMIF) {
|
||||
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].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(0x1, vfe_dev->vfe_base + 0x1E0);
|
||||
vfe_dev->axi_data.src_info[VFE_PIX_0].active = 1;
|
||||
} else if (update_state == DISABLE_CAMIF) {
|
||||
msm_camera_io_w_mb(0x0, vfe_dev->vfe_base + 0x1E0);
|
||||
vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void msm_vfe32_axi_cfg_wm_reg(
|
||||
struct vfe_device *vfe_dev,
|
||||
struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
|
||||
uint8_t plane_idx)
|
||||
{
|
||||
uint32_t val;
|
||||
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
|
||||
struct msm_vfe_axi_stream *stream_info =
|
||||
&axi_data->stream_info[
|
||||
(stream_cfg_cmd->axi_stream_handle & 0xFF)];
|
||||
uint32_t wm_base = VFE32_WM_BASE(stream_info->wm[plane_idx]);
|
||||
|
||||
/*WR_IMAGE_SIZE*/
|
||||
val =
|
||||
((msm_isp_cal_word_per_line(stream_cfg_cmd->output_format,
|
||||
stream_cfg_cmd->plane_cfg[
|
||||
plane_idx].output_width)+1)/2 - 1) << 16 |
|
||||
(stream_cfg_cmd->plane_cfg[plane_idx].output_height - 1);
|
||||
msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x10);
|
||||
|
||||
/*WR_BUFFER_CFG*/
|
||||
val =
|
||||
msm_isp_cal_word_per_line(stream_cfg_cmd->output_format,
|
||||
stream_cfg_cmd->plane_cfg[plane_idx].output_width) << 16 |
|
||||
(stream_cfg_cmd->plane_cfg[
|
||||
plane_idx].output_scan_lines - 1) << 4 |
|
||||
VFE32_BURST_LEN >> 2;
|
||||
msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14);
|
||||
return;
|
||||
}
|
||||
|
||||
static void msm_vfe32_axi_clear_wm_reg(
|
||||
struct vfe_device *vfe_dev,
|
||||
struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx)
|
||||
{
|
||||
uint32_t val = 0;
|
||||
uint32_t wm_base = VFE32_WM_BASE(stream_info->wm[plane_idx]);
|
||||
/*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_rdi_reg(
|
||||
struct vfe_device *vfe_dev,
|
||||
struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
|
||||
uint8_t plane_idx)
|
||||
{
|
||||
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
|
||||
struct msm_vfe_axi_stream *stream_info =
|
||||
&axi_data->stream_info[(stream_cfg_cmd->axi_stream_handle & 0xFF)];
|
||||
struct msm_vfe_axi_plane_cfg *plane_cfg =
|
||||
&stream_cfg_cmd->plane_cfg[plane_idx];
|
||||
uint8_t rdi = stream_info->rdi[plane_idx];
|
||||
uint8_t rdi_master = stream_info->rdi_master[plane_idx];
|
||||
uint32_t rdi_reg_cfg;
|
||||
|
||||
rdi_reg_cfg = msm_camera_io_r(vfe_dev->vfe_base + VFE32_RDI_BASE(rdi));
|
||||
rdi_reg_cfg = (rdi_reg_cfg & 0xFFFFFFF) | rdi_master << 28;
|
||||
msm_camera_io_w(rdi_reg_cfg, vfe_dev->vfe_base + VFE32_RDI_BASE(rdi));
|
||||
|
||||
rdi_reg_cfg = msm_camera_io_r(
|
||||
vfe_dev->vfe_base + VFE32_RDI_MN_BASE(rdi_master));
|
||||
rdi_reg_cfg &= ~((0xF << VFE32_RDI_MN_SEL_SHIFT(rdi_master)) |
|
||||
(0x1 << VFE32_RDI_MN_FB_SHIFT(rdi_master)));
|
||||
rdi_reg_cfg |= (plane_cfg->rdi_cid <<
|
||||
VFE32_RDI_MN_SEL_SHIFT(rdi_master) |
|
||||
(stream_cfg_cmd->frame_base <<
|
||||
VFE32_RDI_MN_FB_SHIFT(rdi_master)));
|
||||
msm_camera_io_w(rdi_reg_cfg,
|
||||
vfe_dev->vfe_base +
|
||||
VFE32_RDI_MN_BASE(rdi_master));
|
||||
}
|
||||
|
||||
static void msm_vfe32_axi_cfg_wm_xbar_reg(
|
||||
struct vfe_device *vfe_dev,
|
||||
struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
|
||||
uint8_t plane_idx)
|
||||
{
|
||||
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
|
||||
struct msm_vfe_axi_stream *stream_info =
|
||||
&axi_data->stream_info[(stream_cfg_cmd->axi_stream_handle & 0xFF)];
|
||||
struct msm_vfe_axi_plane_cfg *plane_cfg =
|
||||
&stream_cfg_cmd->plane_cfg[plane_idx];
|
||||
uint8_t wm = stream_info->wm[plane_idx];
|
||||
uint32_t xbar_cfg = 0;
|
||||
uint32_t xbar_reg_cfg = 0;
|
||||
|
||||
switch (stream_cfg_cmd->stream_src) {
|
||||
case PIX_ENCODER:
|
||||
case PIX_VIEWFINDER: {
|
||||
if (plane_cfg->output_plane_format
|
||||
!= CRCB_PLANE) {
|
||||
/*SINGLE_STREAM_SEL*/
|
||||
xbar_cfg |= plane_cfg->output_plane_format << 5;
|
||||
} else {
|
||||
switch (stream_cfg_cmd->output_format) {
|
||||
case V4L2_PIX_FMT_NV12:
|
||||
case V4L2_PIX_FMT_NV16:
|
||||
xbar_cfg |= 0x3 << 3; /*PAIR_STREAM_SWAP_CTRL*/
|
||||
break;
|
||||
}
|
||||
xbar_cfg |= 0x1 << 1; /*PAIR_STREAM_EN*/
|
||||
}
|
||||
if (stream_cfg_cmd->stream_src == PIX_VIEWFINDER)
|
||||
xbar_cfg |= 0x1; /*VIEW_STREAM_EN*/
|
||||
break;
|
||||
}
|
||||
case CAMIF_RAW:
|
||||
xbar_cfg = 0x60;
|
||||
break;
|
||||
case IDEAL_RAW:
|
||||
xbar_cfg = 0x80;
|
||||
break;
|
||||
case RDI:
|
||||
if (stream_info->rdi[plane_idx] == 0)
|
||||
xbar_cfg = 0xA0;
|
||||
else if (stream_info->rdi[plane_idx] == 1)
|
||||
xbar_cfg = 0xC0;
|
||||
else if (stream_info->rdi[plane_idx] == 2)
|
||||
xbar_cfg = 0xE0;
|
||||
break;
|
||||
default:
|
||||
pr_err("%s: Invalid stream src\n", __func__);
|
||||
}
|
||||
xbar_reg_cfg = msm_camera_io_r(vfe_dev->vfe_base + VFE32_XBAR_BASE(wm));
|
||||
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)
|
||||
{
|
||||
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));
|
||||
xbar_reg_cfg &= ~(0xFF << VFE32_XBAR_SHIFT(wm));
|
||||
msm_camera_io_w(xbar_reg_cfg, vfe_dev->vfe_base + VFE32_XBAR_BASE(wm));
|
||||
}
|
||||
|
||||
static void msm_vfe32_cfg_axi_ub(struct vfe_device *vfe_dev)
|
||||
{
|
||||
int i;
|
||||
uint32_t ub_offset = 0;
|
||||
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
|
||||
for (i = 0; i < axi_data->hw_info->num_wm; i++) {
|
||||
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_update_ping_pong_addr(struct vfe_device *vfe_dev,
|
||||
uint8_t wm_idx, uint32_t pingpong_status, unsigned long paddr)
|
||||
{
|
||||
msm_camera_io_w(paddr, vfe_dev->vfe_base +
|
||||
VFE32_PING_PONG_BASE(wm_idx, pingpong_status));
|
||||
}
|
||||
|
||||
static long msm_vfe32_axi_halt(struct vfe_device *vfe_dev)
|
||||
{
|
||||
uint32_t halt_mask;
|
||||
halt_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x20);
|
||||
halt_mask |= (1 << 24);
|
||||
msm_camera_io_w_mb(halt_mask, vfe_dev->vfe_base + 0x20);
|
||||
init_completion(&vfe_dev->halt_complete);
|
||||
/*TD: Need to fix crashes with this*/
|
||||
/*msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x1D8);*/
|
||||
return wait_for_completion_interruptible_timeout(
|
||||
&vfe_dev->halt_complete, msecs_to_jiffies(500));
|
||||
}
|
||||
|
||||
static uint32_t msm_vfe32_get_wm_mask(
|
||||
uint32_t irq_status0, uint32_t irq_status1)
|
||||
{
|
||||
return (irq_status0 >> 6) & 0x7F;
|
||||
}
|
||||
|
||||
static uint32_t msm_vfe32_get_comp_mask(
|
||||
uint32_t irq_status0, uint32_t irq_status1)
|
||||
{
|
||||
return (irq_status0 >> 21) & 0x7;
|
||||
}
|
||||
|
||||
static uint32_t msm_vfe32_get_pingpong_status(struct vfe_device *vfe_dev)
|
||||
{
|
||||
return msm_camera_io_r(vfe_dev->vfe_base + 0x180);
|
||||
}
|
||||
|
||||
static int msm_vfe32_get_platform_data(struct vfe_device *vfe_dev)
|
||||
{
|
||||
int rc = 0;
|
||||
vfe_dev->vfe_mem = platform_get_resource_byname(vfe_dev->pdev,
|
||||
IORESOURCE_MEM, "vfe");
|
||||
if (!vfe_dev->vfe_mem) {
|
||||
pr_err("%s: no mem resource?\n", __func__);
|
||||
rc = -ENODEV;
|
||||
goto vfe_no_resource;
|
||||
}
|
||||
|
||||
vfe_dev->vfe_irq = platform_get_resource_byname(vfe_dev->pdev,
|
||||
IORESOURCE_IRQ, "vfe");
|
||||
if (!vfe_dev->vfe_irq) {
|
||||
pr_err("%s: no irq resource?\n", __func__);
|
||||
rc = -ENODEV;
|
||||
goto vfe_no_resource;
|
||||
}
|
||||
|
||||
vfe_dev->fs_vfe = regulator_get(&vfe_dev->pdev->dev, "vdd");
|
||||
if (IS_ERR(vfe_dev->fs_vfe)) {
|
||||
pr_err("%s: Regulator get failed %ld\n", __func__,
|
||||
PTR_ERR(vfe_dev->fs_vfe));
|
||||
vfe_dev->fs_vfe = NULL;
|
||||
rc = -ENODEV;
|
||||
goto vfe_no_resource;
|
||||
}
|
||||
|
||||
vfe_dev->iommu_ctx[0] = msm_iommu_get_ctx("vfe_imgwr");
|
||||
if (!vfe_dev->iommu_ctx[0]) {
|
||||
pr_err("%s: no iommux ctx resource?\n", __func__);
|
||||
rc = -ENODEV;
|
||||
goto vfe_no_resource;
|
||||
}
|
||||
|
||||
vfe_dev->iommu_ctx[1] = msm_iommu_get_ctx("vfe_misc");
|
||||
if (!vfe_dev->iommu_ctx[1]) {
|
||||
pr_err("%s: no iommux ctx resource?\n", __func__);
|
||||
rc = -ENODEV;
|
||||
goto vfe_no_resource;
|
||||
}
|
||||
vfe_dev->num_ctx = 2;
|
||||
|
||||
vfe_no_resource:
|
||||
return rc;
|
||||
}
|
||||
|
||||
struct msm_vfe_axi_hardware_info msm_vfe32_axi_hw_info = {
|
||||
.num_wm = 7,
|
||||
.num_comp_mask = 3,
|
||||
.num_rdi = 3,
|
||||
.num_rdi_master = 3,
|
||||
};
|
||||
|
||||
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 = {
|
||||
.vfe_ops = {
|
||||
.irq_ops = {
|
||||
.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_reset_irq = msm_vfe32_process_reset_irq,
|
||||
.process_error_irq = msm_vfe32_process_error_irq,
|
||||
.process_reg_update = msm_vfe32_process_reg_update,
|
||||
.process_axi_irq = msm_isp_process_axi_irq,
|
||||
},
|
||||
.axi_ops = {
|
||||
.reload_wm = msm_vfe32_axi_reload_wm,
|
||||
.enable_wm = msm_vfe32_axi_enable_wm,
|
||||
.cfg_comp_mask = msm_vfe32_axi_cfg_comp_mask,
|
||||
.clear_comp_mask = msm_vfe32_axi_clear_comp_mask,
|
||||
.cfg_wm_irq_mask = msm_vfe32_axi_cfg_wm_irq_mask,
|
||||
.clear_wm_irq_mask = msm_vfe32_axi_clear_wm_irq_mask,
|
||||
.cfg_framedrop = msm_vfe32_cfg_framedrop,
|
||||
.clear_framedrop = msm_vfe32_clear_framedrop,
|
||||
.cfg_wm_reg = msm_vfe32_axi_cfg_wm_reg,
|
||||
.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_rdi_reg = msm_vfe32_axi_cfg_rdi_reg,
|
||||
.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,
|
||||
},
|
||||
.core_ops = {
|
||||
.reg_update = msm_vfe32_reg_update,
|
||||
.cfg_camif = msm_vfe32_cfg_camif,
|
||||
.update_camif_state = msm_vfe32_update_camif_state,
|
||||
.reset_hw = msm_vfe32_reset_hardware,
|
||||
.init_hw = msm_vfe32_init_hardware,
|
||||
.init_hw_reg = msm_vfe32_init_hardware_reg,
|
||||
.release_hw = msm_vfe32_release_hardware,
|
||||
.get_platform_data = msm_vfe32_get_platform_data,
|
||||
},
|
||||
},
|
||||
.axi_hw_info = &msm_vfe32_axi_hw_info,
|
||||
.subdev_ops = &msm_vfe32_subdev_ops,
|
||||
.subdev_internal_ops = &msm_vfe32_internal_ops,
|
||||
};
|
||||
EXPORT_SYMBOL(vfe32_hw_info);
|
||||
17
drivers/media/video/msmb/isp/msm_isp32.h
Normal file
17
drivers/media/video/msmb/isp/msm_isp32.h
Normal file
@@ -0,0 +1,17 @@
|
||||
/* Copyright (c) 2013, 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_ISP32_H__
|
||||
#define __MSM_ISP32_H__
|
||||
|
||||
extern struct msm_vfe_hardware_info vfe32_hw_info;
|
||||
#endif /* __MSM_ISP32_H__ */
|
||||
1128
drivers/media/video/msmb/isp/msm_isp40.c
Normal file
1128
drivers/media/video/msmb/isp/msm_isp40.c
Normal file
File diff suppressed because it is too large
Load Diff
17
drivers/media/video/msmb/isp/msm_isp40.h
Normal file
17
drivers/media/video/msmb/isp/msm_isp40.h
Normal file
@@ -0,0 +1,17 @@
|
||||
/* Copyright (c) 2013, 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_ISP40_H__
|
||||
#define __MSM_ISP40_H__
|
||||
|
||||
extern struct msm_vfe_hardware_info vfe40_hw_info;
|
||||
#endif /* __MSM_ISP40_H__ */
|
||||
968
drivers/media/video/msmb/isp/msm_isp_axi_util.c
Normal file
968
drivers/media/video/msmb/isp/msm_isp_axi_util.c
Normal file
@@ -0,0 +1,968 @@
|
||||
/* Copyright (c) 2013, 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 <media/v4l2-subdev.h>
|
||||
#include "msm_isp_util.h"
|
||||
#include "msm_isp_axi_util.h"
|
||||
|
||||
int msm_isp_axi_create_stream(
|
||||
struct msm_vfe_axi_shared_data *axi_data,
|
||||
struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
|
||||
{
|
||||
int i, rc = -1;
|
||||
for (i = 0; i < MAX_NUM_STREAM; i++) {
|
||||
if (axi_data->stream_info[i].state == AVALIABLE)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == MAX_NUM_STREAM) {
|
||||
pr_err("%s: No free stream\n", __func__);
|
||||
return rc;
|
||||
}
|
||||
|
||||
axi_data->stream_info[i].session_id = stream_cfg_cmd->session_id;
|
||||
axi_data->stream_info[i].stream_id = stream_cfg_cmd->stream_id;
|
||||
axi_data->stream_info[i].buf_divert = stream_cfg_cmd->buf_divert;
|
||||
axi_data->stream_info[i].state = INACTIVE;
|
||||
|
||||
if ((axi_data->stream_handle_cnt << 8) == 0)
|
||||
axi_data->stream_handle_cnt++;
|
||||
|
||||
stream_cfg_cmd->axi_stream_handle =
|
||||
(++axi_data->stream_handle_cnt) << 8 | i;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void msm_isp_axi_destroy_stream(
|
||||
struct msm_vfe_axi_shared_data *axi_data, int stream_idx)
|
||||
{
|
||||
if (axi_data->stream_info[stream_idx].state != AVALIABLE)
|
||||
axi_data->stream_info[stream_idx].state = AVALIABLE;
|
||||
else
|
||||
pr_err("%s: stream does not exist\n", __func__);
|
||||
}
|
||||
|
||||
int msm_isp_validate_axi_request(struct msm_vfe_axi_shared_data *axi_data,
|
||||
struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
|
||||
{
|
||||
int rc = -1;
|
||||
struct msm_vfe_axi_stream *stream_info =
|
||||
&axi_data->stream_info[
|
||||
(stream_cfg_cmd->axi_stream_handle & 0xFF)];
|
||||
|
||||
switch (stream_cfg_cmd->output_format) {
|
||||
case V4L2_PIX_FMT_SBGGR8:
|
||||
case V4L2_PIX_FMT_SGBRG8:
|
||||
case V4L2_PIX_FMT_SGRBG8:
|
||||
case V4L2_PIX_FMT_SRGGB8:
|
||||
case V4L2_PIX_FMT_SBGGR10:
|
||||
case V4L2_PIX_FMT_SGBRG10:
|
||||
case V4L2_PIX_FMT_SGRBG10:
|
||||
case V4L2_PIX_FMT_SRGGB10:
|
||||
case V4L2_PIX_FMT_SBGGR12:
|
||||
case V4L2_PIX_FMT_SGBRG12:
|
||||
case V4L2_PIX_FMT_SGRBG12:
|
||||
case V4L2_PIX_FMT_SRGGB12:
|
||||
stream_info->num_planes = 1;
|
||||
break;
|
||||
case V4L2_PIX_FMT_NV12:
|
||||
case V4L2_PIX_FMT_NV21:
|
||||
stream_info->num_planes = 2;
|
||||
break;
|
||||
/*TD: Add more image format*/
|
||||
default:
|
||||
pr_err("%s: Invalid output format\n", __func__);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (axi_data->hw_info->num_wm - axi_data->num_used_wm <
|
||||
stream_info->num_planes) {
|
||||
pr_err("%s: No free write masters\n", __func__);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if ((stream_info->num_planes > 1) &&
|
||||
(axi_data->hw_info->num_comp_mask -
|
||||
axi_data->num_used_composite_mask < 1)) {
|
||||
pr_err("%s: No free composite mask\n", __func__);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (stream_cfg_cmd->stream_src == RDI) {
|
||||
if (axi_data->hw_info->num_rdi -
|
||||
axi_data->num_used_rdi < stream_info->num_planes) {
|
||||
pr_err("%s: No free RDI\n", __func__);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
if (stream_cfg_cmd->init_frame_drop >= MAX_INIT_FRAME_DROP) {
|
||||
pr_err("%s: Invalid skip pattern\n", __func__);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (stream_cfg_cmd->frame_skip_pattern >= MAX_SKIP) {
|
||||
pr_err("%s: Invalid skip pattern\n", __func__);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t msm_isp_axi_get_plane_size(
|
||||
struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd, int plane_idx)
|
||||
{
|
||||
uint32_t size = 0;
|
||||
struct msm_vfe_axi_plane_cfg *plane_cfg = stream_cfg_cmd->plane_cfg;
|
||||
switch (stream_cfg_cmd->output_format) {
|
||||
case V4L2_PIX_FMT_SBGGR8:
|
||||
case V4L2_PIX_FMT_SGBRG8:
|
||||
case V4L2_PIX_FMT_SGRBG8:
|
||||
case V4L2_PIX_FMT_SRGGB8:
|
||||
size = plane_cfg[plane_idx].output_height *
|
||||
plane_cfg[plane_idx].output_width;
|
||||
break;
|
||||
case V4L2_PIX_FMT_SBGGR10:
|
||||
case V4L2_PIX_FMT_SGBRG10:
|
||||
case V4L2_PIX_FMT_SGRBG10:
|
||||
case V4L2_PIX_FMT_SRGGB10:
|
||||
/* TODO: fix me */
|
||||
size = plane_cfg[plane_idx].output_height *
|
||||
plane_cfg[plane_idx].output_width;
|
||||
break;
|
||||
case V4L2_PIX_FMT_SBGGR12:
|
||||
case V4L2_PIX_FMT_SGBRG12:
|
||||
case V4L2_PIX_FMT_SGRBG12:
|
||||
case V4L2_PIX_FMT_SRGGB12:
|
||||
/* TODO: fix me */
|
||||
size = plane_cfg[plane_idx].output_height *
|
||||
plane_cfg[plane_idx].output_width;
|
||||
break;
|
||||
case V4L2_PIX_FMT_NV12:
|
||||
case V4L2_PIX_FMT_NV21:
|
||||
if (plane_cfg[plane_idx].output_plane_format == Y_PLANE)
|
||||
size = plane_cfg[plane_idx].output_height *
|
||||
plane_cfg[plane_idx].output_width;
|
||||
else
|
||||
size = plane_cfg[plane_idx].output_height *
|
||||
plane_cfg[plane_idx].output_width / 2;
|
||||
break;
|
||||
/*TD: Add more image format*/
|
||||
default:
|
||||
pr_err("%s: Invalid output format\n", __func__);
|
||||
break;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
void msm_isp_axi_reserve_wm(struct msm_vfe_axi_shared_data *axi_data,
|
||||
struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
|
||||
{
|
||||
int i, j;
|
||||
struct msm_vfe_axi_stream *stream_info =
|
||||
&axi_data->stream_info[
|
||||
(stream_cfg_cmd->axi_stream_handle & 0xFF)];
|
||||
|
||||
for (i = 0; i < stream_info->num_planes; i++) {
|
||||
for (j = 0; j < axi_data->hw_info->num_wm; j++) {
|
||||
if (!axi_data->free_wm[j]) {
|
||||
axi_data->free_wm[j] =
|
||||
stream_cfg_cmd->axi_stream_handle;
|
||||
axi_data->wm_image_size[j] =
|
||||
msm_isp_axi_get_plane_size(
|
||||
stream_cfg_cmd, i);
|
||||
axi_data->num_used_wm++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
stream_info->wm[i] = j;
|
||||
}
|
||||
}
|
||||
|
||||
void msm_isp_axi_free_wm(struct msm_vfe_axi_shared_data *axi_data,
|
||||
struct msm_vfe_axi_stream *stream_info)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < stream_info->num_planes; i++) {
|
||||
axi_data->free_wm[stream_info->wm[i]] = 0;
|
||||
axi_data->num_used_wm--;
|
||||
}
|
||||
}
|
||||
|
||||
void msm_isp_axi_reserve_rdi(struct msm_vfe_axi_shared_data *axi_data,
|
||||
struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
|
||||
{
|
||||
int i, j;
|
||||
struct msm_vfe_axi_stream *stream_info =
|
||||
&axi_data->stream_info[(stream_cfg_cmd->axi_stream_handle & 0xFF)];
|
||||
|
||||
for (i = 0; i < stream_info->num_planes; i++) {
|
||||
uint8_t csid = stream_cfg_cmd->plane_cfg[i].csid_src;
|
||||
|
||||
for (j = 0; j < axi_data->hw_info->num_rdi; j++) {
|
||||
if (!axi_data->free_rdi[j]) {
|
||||
axi_data->free_rdi[j] = 1;
|
||||
axi_data->num_used_rdi++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
stream_info->rdi[i] = j;
|
||||
|
||||
for (j = 0; j < axi_data->hw_info->num_rdi; j++) {
|
||||
if (!axi_data->free_rdi_master[csid][j]) {
|
||||
axi_data->free_rdi_master[csid][j] = 1;
|
||||
axi_data->num_used_rdi++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
stream_info->rdi_master[i] =
|
||||
csid * axi_data->hw_info->num_rdi_master + j;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void msm_isp_axi_reserve_comp_mask(
|
||||
struct msm_vfe_axi_shared_data *axi_data,
|
||||
struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
|
||||
{
|
||||
int i;
|
||||
uint8_t comp_mask = 0;
|
||||
struct msm_vfe_axi_stream *stream_info =
|
||||
&axi_data->stream_info[
|
||||
(stream_cfg_cmd->axi_stream_handle & 0xFF)];
|
||||
for (i = 0; i < stream_info->num_planes; i++)
|
||||
comp_mask |= 1 << stream_info->wm[i];
|
||||
|
||||
for (i = 0; i < axi_data->hw_info->num_comp_mask; i++) {
|
||||
if (!axi_data->composite_info[i].stream_handle) {
|
||||
axi_data->composite_info[i].stream_handle =
|
||||
stream_cfg_cmd->axi_stream_handle;
|
||||
axi_data->composite_info[i].
|
||||
stream_composite_mask = comp_mask;
|
||||
axi_data->num_used_composite_mask++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
stream_info->comp_mask_index = i;
|
||||
return;
|
||||
}
|
||||
|
||||
void msm_isp_axi_free_comp_mask(struct msm_vfe_axi_shared_data *axi_data,
|
||||
struct msm_vfe_axi_stream *stream_info)
|
||||
{
|
||||
axi_data->composite_info[stream_info->comp_mask_index].
|
||||
stream_composite_mask = 0;
|
||||
axi_data->composite_info[stream_info->comp_mask_index].
|
||||
stream_handle = 0;
|
||||
axi_data->num_used_composite_mask--;
|
||||
}
|
||||
|
||||
int msm_isp_axi_check_stream_state(
|
||||
struct vfe_device *vfe_dev,
|
||||
struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd)
|
||||
{
|
||||
int rc = 0, i, j;
|
||||
uint8_t src_state;
|
||||
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
|
||||
struct msm_vfe_axi_stream *stream_info;
|
||||
enum msm_vfe_axi_state valid_state =
|
||||
(stream_cfg_cmd->cmd == START_STREAM) ? INACTIVE : ACTIVE;
|
||||
|
||||
for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
|
||||
stream_info = &axi_data->stream_info[
|
||||
(stream_cfg_cmd->stream_handle[i] & 0xFF)];
|
||||
if (stream_info->state != valid_state) {
|
||||
pr_err("%s: Invalid stream state\n", __func__);
|
||||
rc = -EINVAL;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* For RDI stream, if multiple RDIs are used
|
||||
* check if all the RDI srcs are in the same state, on/off
|
||||
*/
|
||||
if (stream_info->stream_src == RDI) {
|
||||
src_state = axi_data->src_info[
|
||||
stream_info->rdi[0]+1].active;
|
||||
for (j = 0; j < stream_info->num_planes; j++) {
|
||||
if (src_state !=
|
||||
axi_data->src_info[
|
||||
stream_info->rdi[j]+1].active) {
|
||||
pr_err("%s: RDI stream has inconsistent state\n",
|
||||
__func__);
|
||||
rc = -EINVAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (stream_cfg_cmd->cmd == START_STREAM) {
|
||||
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: Stream has no valid buffer queue\n",
|
||||
__func__);
|
||||
rc = -EINVAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
void msm_isp_update_framedrop_reg(struct vfe_device *vfe_dev)
|
||||
{
|
||||
int i;
|
||||
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
|
||||
struct msm_vfe_axi_stream *stream_info;
|
||||
for (i = 0; i < MAX_NUM_STREAM; i++) {
|
||||
stream_info = &axi_data->stream_info[i];
|
||||
if (stream_info->framedrop_update) {
|
||||
if (stream_info->init_frame_drop == 0) {
|
||||
stream_info->framedrop_update = 0;
|
||||
vfe_dev->hw_info->vfe_ops.axi_ops.
|
||||
cfg_framedrop(vfe_dev, stream_info);
|
||||
}
|
||||
}
|
||||
if (stream_info->stream_type == BURST_STREAM) {
|
||||
if (stream_info->burst_frame_count == 0 &&
|
||||
stream_info->state == ACTIVE) {
|
||||
vfe_dev->hw_info->vfe_ops.axi_ops.
|
||||
cfg_framedrop(vfe_dev, stream_info);
|
||||
if (stream_info->stream_src == RDI) {
|
||||
uint32_t wm_reload_mask = 0,
|
||||
reg_update_mask = 0;
|
||||
stream_info->state = STOP_PENDING;
|
||||
msm_isp_axi_stream_enable_cfg(
|
||||
vfe_dev, stream_info,
|
||||
&wm_reload_mask,
|
||||
®_update_mask);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void msm_isp_update_framedrop_count(
|
||||
struct vfe_device *vfe_dev)
|
||||
{
|
||||
int i;
|
||||
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
|
||||
struct msm_vfe_axi_stream *stream_info;
|
||||
for (i = 0; i < MAX_NUM_STREAM; i++) {
|
||||
stream_info = &axi_data->stream_info[i];
|
||||
if (stream_info->framedrop_update) {
|
||||
stream_info->init_frame_drop--;
|
||||
if (stream_info->init_frame_drop == 1) {
|
||||
vfe_dev->hw_info->vfe_ops.core_ops.
|
||||
reg_update(vfe_dev, 0xF);
|
||||
}
|
||||
}
|
||||
if (stream_info->stream_type == BURST_STREAM) {
|
||||
stream_info->burst_frame_count--;
|
||||
if (stream_info->burst_frame_count == 1) {
|
||||
vfe_dev->hw_info->vfe_ops.core_ops.
|
||||
reg_update(vfe_dev, 0xF);
|
||||
} else if (stream_info->burst_frame_count == 0) {
|
||||
if (stream_info->stream_src != RDI) {
|
||||
vfe_dev->hw_info->vfe_ops.core_ops.
|
||||
update_camif_state(vfe_dev,
|
||||
DISABLE_CAMIF);
|
||||
pr_err("%s: pending burst_cnt = %d, disable camif\n",
|
||||
__func__,
|
||||
stream_info->burst_frame_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void msm_isp_new_frame_notify(struct vfe_device *vfe_dev,
|
||||
enum msm_vfe_input_src frame_src) {
|
||||
switch (frame_src) {
|
||||
case VFE_PIX_0:
|
||||
ISP_DBG("%s: PIX0 frame id: %lu\n", __func__,
|
||||
vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id);
|
||||
msm_isp_update_framedrop_count(vfe_dev);
|
||||
vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id++;
|
||||
if (vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id == 0)
|
||||
vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id = 1;
|
||||
break;
|
||||
case VFE_RAW_0:
|
||||
case VFE_RAW_1:
|
||||
case VFE_RAW_2:
|
||||
break;
|
||||
default:
|
||||
pr_err("%s: invalid frame src %d received\n",
|
||||
__func__, frame_src);
|
||||
break;
|
||||
}
|
||||
}
|
||||
void msm_isp_calculate_framedrop(
|
||||
struct msm_vfe_axi_shared_data *axi_data,
|
||||
struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
|
||||
{
|
||||
struct msm_vfe_axi_stream *stream_info =
|
||||
&axi_data->stream_info[
|
||||
(stream_cfg_cmd->axi_stream_handle & 0xFF)];
|
||||
uint32_t framedrop_period = 1;
|
||||
|
||||
switch (stream_cfg_cmd->frame_skip_pattern) {
|
||||
case NO_SKIP:
|
||||
stream_info->framedrop_pattern = VFE_NO_DROP;
|
||||
framedrop_period = 1;
|
||||
break;
|
||||
case EVERY_2FRAME:
|
||||
stream_info->framedrop_pattern = VFE_DROP_EVERY_2FRAME;
|
||||
framedrop_period = 2;
|
||||
break;
|
||||
case EVERY_4FRAME:
|
||||
stream_info->framedrop_pattern = VFE_DROP_EVERY_4FRAME;
|
||||
framedrop_period = 4;
|
||||
break;
|
||||
case EVERY_8FRAME:
|
||||
stream_info->framedrop_pattern = VFE_DROP_EVERY_8FRAME;
|
||||
framedrop_period = 8;
|
||||
break;
|
||||
case EVERY_16FRAME:
|
||||
stream_info->framedrop_pattern = VFE_DROP_EVERY_16FRAME;
|
||||
framedrop_period = 16;
|
||||
break;
|
||||
case EVERY_32FRAME:
|
||||
stream_info->framedrop_pattern = VFE_DROP_EVERY_32FRAME;
|
||||
framedrop_period = 32;
|
||||
break;
|
||||
default:
|
||||
stream_info->framedrop_pattern = VFE_NO_DROP;
|
||||
framedrop_period = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (stream_cfg_cmd->init_frame_drop < framedrop_period) {
|
||||
stream_info->framedrop_pattern <<=
|
||||
stream_cfg_cmd->init_frame_drop;
|
||||
stream_info->init_frame_drop = 0;
|
||||
stream_info->framedrop_update = 0;
|
||||
} else {
|
||||
stream_info->init_frame_drop = stream_cfg_cmd->init_frame_drop;
|
||||
stream_info->framedrop_update = 1;
|
||||
}
|
||||
|
||||
if (stream_cfg_cmd->burst_count > 0) {
|
||||
stream_info->stream_type = BURST_STREAM;
|
||||
stream_info->burst_frame_count =
|
||||
stream_cfg_cmd->init_frame_drop +
|
||||
(stream_cfg_cmd->burst_count - 1) *
|
||||
framedrop_period + 1;
|
||||
} else {
|
||||
stream_info->stream_type = CONTINUOUS_STREAM;
|
||||
stream_info->burst_frame_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int msm_isp_request_axi_stream(struct vfe_device *vfe_dev, void *arg)
|
||||
{
|
||||
int rc = 0, i;
|
||||
struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd = arg;
|
||||
struct msm_vfe_axi_stream *stream_info;
|
||||
|
||||
rc = msm_isp_axi_create_stream(
|
||||
&vfe_dev->axi_data, stream_cfg_cmd);
|
||||
if (rc) {
|
||||
pr_err("%s: create stream failed\n", __func__);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = msm_isp_validate_axi_request(
|
||||
&vfe_dev->axi_data, stream_cfg_cmd);
|
||||
if (rc) {
|
||||
pr_err("%s: Request validation failed\n", __func__);
|
||||
msm_isp_axi_destroy_stream(&vfe_dev->axi_data,
|
||||
(stream_cfg_cmd->axi_stream_handle & 0xFF));
|
||||
return rc;
|
||||
}
|
||||
|
||||
msm_isp_axi_reserve_wm(&vfe_dev->axi_data, stream_cfg_cmd);
|
||||
if (stream_cfg_cmd->stream_src == RDI)
|
||||
msm_isp_axi_reserve_rdi(&vfe_dev->axi_data, stream_cfg_cmd);
|
||||
|
||||
stream_info =
|
||||
&vfe_dev->axi_data.
|
||||
stream_info[(stream_cfg_cmd->axi_stream_handle & 0xFF)];
|
||||
|
||||
msm_isp_calculate_framedrop(&vfe_dev->axi_data, stream_cfg_cmd);
|
||||
vfe_dev->hw_info->vfe_ops.axi_ops.cfg_framedrop(vfe_dev, stream_info);
|
||||
|
||||
if (stream_info->num_planes > 1) {
|
||||
msm_isp_axi_reserve_comp_mask(
|
||||
&vfe_dev->axi_data, stream_cfg_cmd);
|
||||
vfe_dev->hw_info->vfe_ops.axi_ops.
|
||||
cfg_comp_mask(vfe_dev, stream_info);
|
||||
} else {
|
||||
vfe_dev->hw_info->vfe_ops.axi_ops.
|
||||
cfg_wm_irq_mask(vfe_dev, stream_info);
|
||||
}
|
||||
|
||||
for (i = 0; i < stream_info->num_planes; i++) {
|
||||
vfe_dev->hw_info->vfe_ops.axi_ops.
|
||||
cfg_wm_reg(vfe_dev, stream_cfg_cmd, i);
|
||||
|
||||
vfe_dev->hw_info->vfe_ops.axi_ops.
|
||||
cfg_wm_xbar_reg(vfe_dev, stream_cfg_cmd, i);
|
||||
|
||||
if (stream_cfg_cmd->stream_src == RDI)
|
||||
vfe_dev->hw_info->vfe_ops.axi_ops.
|
||||
cfg_rdi_reg(vfe_dev, stream_cfg_cmd, i);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int msm_isp_release_axi_stream(struct vfe_device *vfe_dev, void *arg)
|
||||
{
|
||||
int rc = 0, i;
|
||||
struct msm_vfe_axi_stream_release_cmd *stream_release_cmd = arg;
|
||||
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
|
||||
struct msm_vfe_axi_stream *stream_info =
|
||||
&axi_data->stream_info[
|
||||
(stream_release_cmd->stream_handle & 0xFF)];
|
||||
struct msm_vfe_axi_stream_cfg_cmd stream_cfg;
|
||||
|
||||
if (stream_info->state == AVALIABLE) {
|
||||
pr_err("%s: Stream already released\n", __func__);
|
||||
return -EINVAL;
|
||||
} else if (stream_info->state != INACTIVE) {
|
||||
stream_cfg.cmd = STOP_STREAM;
|
||||
stream_cfg.num_streams = 1;
|
||||
stream_cfg.stream_handle[0] = stream_release_cmd->stream_handle;
|
||||
msm_isp_cfg_axi_stream(vfe_dev, (void *) &stream_cfg);
|
||||
}
|
||||
|
||||
for (i = 0; i < stream_info->num_planes; i++) {
|
||||
vfe_dev->hw_info->vfe_ops.axi_ops.
|
||||
clear_wm_reg(vfe_dev, stream_info, i);
|
||||
|
||||
vfe_dev->hw_info->vfe_ops.axi_ops.
|
||||
clear_wm_xbar_reg(vfe_dev, stream_info, i);
|
||||
}
|
||||
|
||||
if (stream_info->num_planes > 1) {
|
||||
msm_isp_axi_free_comp_mask(&vfe_dev->axi_data, stream_info);
|
||||
vfe_dev->hw_info->vfe_ops.axi_ops.
|
||||
clear_comp_mask(vfe_dev, stream_info);
|
||||
} else {
|
||||
vfe_dev->hw_info->vfe_ops.axi_ops.
|
||||
clear_wm_irq_mask(vfe_dev, stream_info);
|
||||
}
|
||||
|
||||
vfe_dev->hw_info->vfe_ops.axi_ops.clear_framedrop(vfe_dev, stream_info);
|
||||
msm_isp_axi_free_wm(axi_data, stream_info);
|
||||
|
||||
msm_isp_axi_destroy_stream(&vfe_dev->axi_data,
|
||||
(stream_release_cmd->stream_handle & 0xFF));
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void msm_isp_axi_stream_enable_cfg(
|
||||
struct vfe_device *vfe_dev,
|
||||
struct msm_vfe_axi_stream *stream_info,
|
||||
uint32_t *wm_reload_mask, uint32_t *reg_update_mask)
|
||||
{
|
||||
int i;
|
||||
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
|
||||
if (stream_info->state == INACTIVE)
|
||||
return;
|
||||
for (i = 0; i < stream_info->num_planes; i++) {
|
||||
/*TD: Frame base command*/
|
||||
if (stream_info->state == START_PENDING)
|
||||
vfe_dev->hw_info->vfe_ops.axi_ops.
|
||||
enable_wm(vfe_dev, stream_info->wm[i], 1);
|
||||
else
|
||||
vfe_dev->hw_info->vfe_ops.axi_ops.
|
||||
enable_wm(vfe_dev, stream_info->wm[i], 0);
|
||||
|
||||
*wm_reload_mask |= (1 << stream_info->wm[i]);
|
||||
if (stream_info->stream_src == RDI)
|
||||
*reg_update_mask |= (1 << stream_info->rdi[i]);
|
||||
}
|
||||
if (stream_info->state == START_PENDING) {
|
||||
axi_data->num_active_stream++;
|
||||
stream_info->state = ACTIVE;
|
||||
} else {
|
||||
axi_data->num_active_stream--;
|
||||
stream_info->state = INACTIVE;
|
||||
}
|
||||
}
|
||||
|
||||
void msm_isp_axi_stream_update(struct vfe_device *vfe_dev)
|
||||
{
|
||||
int i;
|
||||
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
|
||||
uint32_t wm_reload_mask = 0x0, reg_update_mask = 0x1;
|
||||
int send_update_complete = 0;
|
||||
for (i = 0; i < MAX_NUM_STREAM; i++) {
|
||||
if (axi_data->stream_info[i].state == START_PENDING ||
|
||||
axi_data->stream_info[i].state ==
|
||||
STOP_PENDING) {
|
||||
msm_isp_axi_stream_enable_cfg(
|
||||
vfe_dev, &axi_data->stream_info[i],
|
||||
&wm_reload_mask, ®_update_mask);
|
||||
if (axi_data->stream_info[i].state == STOP_PENDING)
|
||||
axi_data->stream_info[i].state = STOPPING;
|
||||
} else if (axi_data->stream_info[i].state == STOPPING) {
|
||||
send_update_complete = 1;
|
||||
axi_data->stream_info[i].state = INACTIVE;
|
||||
}
|
||||
}
|
||||
/*Reload AXI*/
|
||||
vfe_dev->hw_info->vfe_ops.axi_ops.
|
||||
reload_wm(vfe_dev, wm_reload_mask);
|
||||
/*Reg update per src*/
|
||||
vfe_dev->hw_info->vfe_ops.core_ops.
|
||||
reg_update(vfe_dev, reg_update_mask);
|
||||
if (send_update_complete) {
|
||||
ISP_DBG("%s: send update complete\n", __func__);
|
||||
vfe_dev->axi_data.stream_update = 0;
|
||||
complete(&vfe_dev->stream_config_complete);
|
||||
}
|
||||
}
|
||||
|
||||
#define VFE_PING_FLAG 0xFFFFFFFF
|
||||
#define VFE_PONG_FLAG 0x0
|
||||
|
||||
int msm_isp_cfg_ping_pong_address(struct vfe_device *vfe_dev,
|
||||
struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status,
|
||||
struct timeval *tv)
|
||||
{
|
||||
int i, rc = -1;
|
||||
struct msm_isp_buffer *buf;
|
||||
struct msm_isp_event_data buf_event;
|
||||
uint32_t pingpong_bit = 0;
|
||||
uint32_t bufq_handle = stream_info->bufq_handle;
|
||||
|
||||
pingpong_bit = (~(pingpong_status >> stream_info->wm[0]) & 0x1);
|
||||
rc = vfe_dev->buf_mgr->ops->get_buf(
|
||||
vfe_dev->buf_mgr, bufq_handle, &buf);
|
||||
if (rc < 0) {
|
||||
if (stream_info->stream_type == BURST_STREAM &&
|
||||
stream_info->burst_frame_count <= 1) {
|
||||
rc = 0;
|
||||
if (pingpong_bit)
|
||||
buf = stream_info->buf[0];
|
||||
else
|
||||
buf = stream_info->buf[1];
|
||||
} else {
|
||||
pr_err("%s: No free buffer, stream_type = %d, burst_cnt = %d\n",
|
||||
__func__, stream_info->stream_type,
|
||||
stream_info->burst_frame_count);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
if (buf->num_planes != stream_info->num_planes) {
|
||||
pr_err("%s: Invalid buffer\n", __func__);
|
||||
rc = -EINVAL;
|
||||
goto buf_error;
|
||||
}
|
||||
for (i = 0; i < stream_info->num_planes; i++) {
|
||||
if (pingpong_bit !=
|
||||
(~(pingpong_status >> stream_info->wm[i]) & 0x1)) {
|
||||
pr_warn("%s: Write master ping pong mismatch. Status: 0x%x\n",
|
||||
__func__, pingpong_status);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < stream_info->num_planes; i++)
|
||||
vfe_dev->hw_info->vfe_ops.axi_ops.update_ping_pong_addr(
|
||||
vfe_dev, stream_info->wm[i],
|
||||
pingpong_status, buf->mapped_info[i].paddr);
|
||||
|
||||
if (stream_info->buf[pingpong_bit]) {
|
||||
if (stream_info->buf_divert) {
|
||||
buf_event.frame_id = stream_info->frame_id;
|
||||
buf_event.timestamp = *tv;
|
||||
buf_event.u.buf_done.session_id =
|
||||
stream_info->session_id;
|
||||
buf_event.u.buf_done.stream_id =
|
||||
stream_info->stream_id;
|
||||
buf_event.u.buf_done.handle =
|
||||
stream_info->bufq_handle;
|
||||
buf_event.u.buf_done.buf_idx =
|
||||
stream_info->buf[pingpong_bit]->buf_idx;
|
||||
msm_isp_send_event(
|
||||
vfe_dev, ISP_EVENT_BUF_DIVERT, &buf_event);
|
||||
} else {
|
||||
vfe_dev->buf_mgr->ops->buf_done(vfe_dev->buf_mgr,
|
||||
stream_info->buf[pingpong_bit]->bufq_handle,
|
||||
stream_info->buf[pingpong_bit]->buf_idx,
|
||||
tv, stream_info->frame_id);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
enum msm_isp_camif_update_state
|
||||
msm_isp_update_camif_output_count(
|
||||
struct vfe_device *vfe_dev,
|
||||
struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd)
|
||||
{
|
||||
int i;
|
||||
struct msm_vfe_axi_stream *stream_info;
|
||||
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
|
||||
uint8_t cur_pix_count = axi_data->src_info[VFE_PIX_0].
|
||||
pix_stream_count;
|
||||
uint8_t cur_raw_count = axi_data->src_info[VFE_PIX_0].
|
||||
raw_stream_count;
|
||||
uint8_t pix_stream_cnt = 0;
|
||||
for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
|
||||
stream_info =
|
||||
&axi_data->stream_info[
|
||||
(stream_cfg_cmd->stream_handle[i] & 0xFF)];
|
||||
if (stream_info->stream_src != RDI)
|
||||
pix_stream_cnt++;
|
||||
if (stream_info->stream_src == PIX_ENCODER ||
|
||||
stream_info->stream_src == PIX_VIEWFINDER) {
|
||||
if (stream_cfg_cmd->cmd == START_STREAM)
|
||||
vfe_dev->axi_data.src_info[VFE_PIX_0].
|
||||
pix_stream_count++;
|
||||
else
|
||||
vfe_dev->axi_data.src_info[VFE_PIX_0].
|
||||
pix_stream_count--;
|
||||
} else if (stream_info->stream_src == CAMIF_RAW ||
|
||||
stream_info->stream_src == IDEAL_RAW) {
|
||||
if (stream_cfg_cmd->cmd == START_STREAM)
|
||||
vfe_dev->axi_data.src_info[VFE_PIX_0].
|
||||
raw_stream_count++;
|
||||
else
|
||||
vfe_dev->axi_data.src_info[VFE_PIX_0].
|
||||
raw_stream_count--;
|
||||
}
|
||||
}
|
||||
if (pix_stream_cnt) {
|
||||
if ((cur_pix_count + cur_raw_count == 0) &&
|
||||
(axi_data->src_info[VFE_PIX_0].
|
||||
pix_stream_count +
|
||||
axi_data->src_info[VFE_PIX_0].
|
||||
raw_stream_count != 0)) {
|
||||
return ENABLE_CAMIF;
|
||||
}
|
||||
|
||||
if ((cur_pix_count + cur_raw_count != 0) &&
|
||||
(axi_data->src_info[VFE_PIX_0].
|
||||
pix_stream_count +
|
||||
axi_data->src_info[VFE_PIX_0].
|
||||
raw_stream_count == 0)) {
|
||||
return DISABLE_CAMIF;
|
||||
}
|
||||
}
|
||||
|
||||
return NO_UPDATE;
|
||||
}
|
||||
|
||||
void msm_camera_io_dump_2(void __iomem *addr, int size)
|
||||
{
|
||||
char line_str[128], *p_str;
|
||||
int i;
|
||||
u32 *p = (u32 *) addr;
|
||||
u32 data;
|
||||
ISP_DBG("%s: %p %d\n", __func__, addr, size);
|
||||
line_str[0] = '\0';
|
||||
p_str = line_str;
|
||||
for (i = 0; i < size/4; i++) {
|
||||
if (i % 4 == 0) {
|
||||
snprintf(p_str, 12, "%08x: ", (u32) p);
|
||||
p_str += 10;
|
||||
}
|
||||
data = readl_relaxed(p++);
|
||||
snprintf(p_str, 12, "%08x ", data);
|
||||
p_str += 9;
|
||||
if ((i + 1) % 4 == 0) {
|
||||
ISP_DBG("%s\n", line_str);
|
||||
line_str[0] = '\0';
|
||||
p_str = line_str;
|
||||
}
|
||||
}
|
||||
if (line_str[0] != '\0')
|
||||
ISP_DBG("%s\n", line_str);
|
||||
}
|
||||
|
||||
int msm_isp_cfg_axi_stream(struct vfe_device *vfe_dev, void *arg)
|
||||
{
|
||||
int rc = 0, i;
|
||||
struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd = arg;
|
||||
uint32_t wm_reload_mask = 0x0, reg_update_mask = 0x1;
|
||||
struct msm_vfe_axi_stream *stream_info;
|
||||
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
|
||||
uint8_t src_state;
|
||||
enum msm_isp_camif_update_state camif_update;
|
||||
uint8_t wait_for_complete = 0;
|
||||
rc = msm_isp_axi_check_stream_state(vfe_dev, stream_cfg_cmd);
|
||||
if (rc < 0) {
|
||||
pr_err("%s: Invalid stream state\n", __func__);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (axi_data->num_active_stream == 0) {
|
||||
/*Configure UB*/
|
||||
vfe_dev->hw_info->vfe_ops.axi_ops.cfg_ub(vfe_dev);
|
||||
}
|
||||
|
||||
camif_update =
|
||||
msm_isp_update_camif_output_count(vfe_dev, stream_cfg_cmd);
|
||||
|
||||
if (camif_update == DISABLE_CAMIF)
|
||||
vfe_dev->hw_info->vfe_ops.core_ops.
|
||||
update_camif_state(vfe_dev, DISABLE_CAMIF_IMMEDIATELY);
|
||||
|
||||
/*
|
||||
* Stream start either immediately or at reg update
|
||||
* Depends on whether the stream src is active
|
||||
* If source is on, start and stop have to be done during reg update
|
||||
* If source is off, start can happen immediately or during reg update
|
||||
* stop has to be done immediately.
|
||||
*/
|
||||
for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
|
||||
stream_info =
|
||||
&axi_data->stream_info[
|
||||
(stream_cfg_cmd->stream_handle[i] & 0xFF)];
|
||||
|
||||
|
||||
if (stream_info->stream_src == RDI)
|
||||
src_state =
|
||||
axi_data->src_info[
|
||||
stream_info->rdi[0]+1].active;
|
||||
else
|
||||
src_state = axi_data->src_info[0].active;
|
||||
|
||||
stream_info->state = (stream_cfg_cmd->cmd == START_STREAM) ?
|
||||
START_PENDING : STOP_PENDING;
|
||||
|
||||
if (stream_cfg_cmd->cmd == START_STREAM) {
|
||||
/*Set address for both PING & PONG register */
|
||||
rc = msm_isp_cfg_ping_pong_address(vfe_dev,
|
||||
stream_info, VFE_PING_FLAG, NULL);
|
||||
rc = msm_isp_cfg_ping_pong_address(vfe_dev,
|
||||
stream_info, VFE_PONG_FLAG, NULL);
|
||||
}
|
||||
if (src_state && camif_update != DISABLE_CAMIF) {
|
||||
/*On the fly stream start/stop */
|
||||
wait_for_complete = 1;
|
||||
reg_update_mask = 0xF; /*TD: Maybe set this per src*/
|
||||
} else {
|
||||
if (vfe_dev->dump_reg)
|
||||
msm_camera_io_dump_2(vfe_dev->vfe_base, 0x900);
|
||||
/*Configure AXI start bits to start immediately*/
|
||||
msm_isp_axi_stream_enable_cfg(
|
||||
vfe_dev, stream_info,
|
||||
&wm_reload_mask, ®_update_mask);
|
||||
}
|
||||
}
|
||||
if (!wait_for_complete) {
|
||||
/*Reload AXI*/
|
||||
vfe_dev->hw_info->vfe_ops.axi_ops.
|
||||
reload_wm(vfe_dev, wm_reload_mask);
|
||||
/*Reg update per src*/
|
||||
vfe_dev->hw_info->vfe_ops.core_ops.
|
||||
reg_update(vfe_dev, reg_update_mask);
|
||||
|
||||
if (camif_update == ENABLE_CAMIF)
|
||||
vfe_dev->hw_info->vfe_ops.core_ops.
|
||||
update_camif_state(vfe_dev, camif_update);
|
||||
} else {
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&vfe_dev->shared_data_lock, flags);
|
||||
init_completion(&vfe_dev->stream_config_complete);
|
||||
axi_data->stream_update = 1;
|
||||
spin_unlock_irqrestore(&vfe_dev->shared_data_lock, flags);
|
||||
/*Reload AXI*/
|
||||
vfe_dev->hw_info->vfe_ops.axi_ops.
|
||||
reload_wm(vfe_dev, wm_reload_mask);
|
||||
/*Reg update per src*/
|
||||
vfe_dev->hw_info->vfe_ops.core_ops.
|
||||
reg_update(vfe_dev, reg_update_mask);
|
||||
rc = wait_for_completion_interruptible_timeout(
|
||||
&vfe_dev->stream_config_complete,
|
||||
msecs_to_jiffies(500));
|
||||
if (rc == 0) {
|
||||
pr_err("%s: wait timeout\n", __func__);
|
||||
rc = -1;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
void msm_isp_process_axi_irq(struct vfe_device *vfe_dev,
|
||||
uint32_t irq_status0, uint32_t irq_status1,
|
||||
struct timeval *tv)
|
||||
{
|
||||
int i;
|
||||
uint32_t comp_mask = 0, wm_mask = 0;
|
||||
uint32_t pingpong_status, stream_idx;
|
||||
struct msm_vfe_axi_stream *stream_info;
|
||||
struct msm_vfe_axi_composite_info *comp_info;
|
||||
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
|
||||
|
||||
ISP_DBG("%s: status: 0x%x\n", __func__, irq_status0);
|
||||
comp_mask = vfe_dev->hw_info->vfe_ops.axi_ops.
|
||||
get_comp_mask(irq_status0, irq_status1);
|
||||
wm_mask = vfe_dev->hw_info->vfe_ops.axi_ops.
|
||||
get_wm_mask(irq_status0, irq_status1);
|
||||
if (!(comp_mask || wm_mask))
|
||||
return;
|
||||
|
||||
pingpong_status =
|
||||
vfe_dev->hw_info->vfe_ops.axi_ops.get_pingpong_status(vfe_dev);
|
||||
|
||||
for (i = 0; i < axi_data->hw_info->num_comp_mask; i++) {
|
||||
comp_info = &axi_data->composite_info[i];
|
||||
if (comp_mask & (1 << i)) {
|
||||
if (!comp_info->stream_handle) {
|
||||
pr_err("%s: Invalid handle for composite irq\n",
|
||||
__func__);
|
||||
} else {
|
||||
stream_idx = comp_info->stream_handle & 0xFF;
|
||||
stream_info =
|
||||
&axi_data->stream_info[stream_idx];
|
||||
ISP_DBG("%s: stream%d frame id: 0x%x\n",
|
||||
__func__,
|
||||
stream_idx, stream_info->frame_id);
|
||||
stream_info->frame_id++;
|
||||
msm_isp_cfg_ping_pong_address(vfe_dev,
|
||||
stream_info, pingpong_status, tv);
|
||||
}
|
||||
}
|
||||
wm_mask &= ~(comp_info->stream_composite_mask);
|
||||
}
|
||||
|
||||
for (i = 0; i < axi_data->hw_info->num_wm; i++) {
|
||||
if (wm_mask & (1 << i)) {
|
||||
if (!axi_data->free_wm[i]) {
|
||||
pr_err("%s: Invalid handle for wm irq\n",
|
||||
__func__);
|
||||
continue;
|
||||
}
|
||||
stream_idx = axi_data->free_wm[i] & 0xFF;
|
||||
stream_info = &axi_data->stream_info[stream_idx];
|
||||
stream_info->frame_id++;
|
||||
msm_isp_cfg_ping_pong_address(vfe_dev,
|
||||
stream_info, pingpong_status, tv);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
65
drivers/media/video/msmb/isp/msm_isp_axi_util.h
Normal file
65
drivers/media/video/msmb/isp/msm_isp_axi_util.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/* Copyright (c) 2013, 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.h"
|
||||
|
||||
int msm_isp_axi_create_stream(
|
||||
struct msm_vfe_axi_shared_data *axi_data,
|
||||
struct msm_vfe_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_vfe_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_request_cmd *stream_cfg_cmd);
|
||||
|
||||
void msm_isp_axi_reserve_rdi(
|
||||
struct msm_vfe_axi_shared_data *axi_data,
|
||||
struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd);
|
||||
|
||||
void msm_isp_axi_reserve_comp_mask(
|
||||
struct msm_vfe_axi_shared_data *axi_data,
|
||||
struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd);
|
||||
|
||||
int msm_isp_axi_check_stream_state(
|
||||
struct vfe_device *vfe_dev,
|
||||
struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd);
|
||||
|
||||
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);
|
||||
|
||||
void msm_isp_axi_stream_enable_cfg(struct vfe_device *vfe_dev,
|
||||
struct msm_vfe_axi_stream *stream_info,
|
||||
uint32_t *wm_reload_mask, uint32_t *reg_update_mask);
|
||||
|
||||
void msm_isp_axi_stream_update(struct vfe_device *vfe_dev);
|
||||
|
||||
int msm_isp_cfg_ping_pong_address(struct vfe_device *vfe_dev,
|
||||
struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status,
|
||||
struct timeval *tv);
|
||||
|
||||
void msm_isp_update_framedrop_reg(struct vfe_device *vfe_dev);
|
||||
void msm_isp_update_framedrop_count(struct vfe_device *vfe_dev);
|
||||
void msm_isp_new_frame_notify(struct vfe_device *vfe_dev,
|
||||
enum msm_vfe_input_src frame_src);
|
||||
void msm_isp_process_axi_irq(struct vfe_device *vfe_dev,
|
||||
uint32_t irq_status0, uint32_t irq_status1,
|
||||
struct timeval *tv);
|
||||
#endif /* __MSM_ISP_AXI_UTIL_H__ */
|
||||
69
drivers/media/video/msmb/isp/msm_isp_stats_util.c
Normal file
69
drivers/media/video/msmb/isp/msm_isp_stats_util.c
Normal file
@@ -0,0 +1,69 @@
|
||||
/* Copyright (c) 2013, 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 <media/v4l2-subdev.h>
|
||||
#include "msm_isp_util.h"
|
||||
#include "msm_isp_stats_util.h"
|
||||
|
||||
void msm_isp_process_stats_irq(struct vfe_device *vfe_dev,
|
||||
uint32_t irq_status0, uint32_t irq_status1,
|
||||
struct timeval *tv)
|
||||
{
|
||||
uint32_t frame_id;
|
||||
uint32_t stats_comp_mask = 0, stats_mask = 0;
|
||||
ISP_DBG("%s: status: 0x%x\n", __func__, irq_status0);
|
||||
stats_comp_mask = vfe_dev->hw_info->vfe_ops.stats_ops.
|
||||
get_comp_mask(irq_status0, irq_status1);
|
||||
stats_mask = vfe_dev->hw_info->vfe_ops.stats_ops.
|
||||
get_wm_mask(irq_status0, irq_status1);
|
||||
if (!(stats_comp_mask || stats_mask))
|
||||
return;
|
||||
frame_id = vfe_dev->hw_info->vfe_ops.stats_ops.get_frame_id(vfe_dev);
|
||||
/* TD: process comp/non comp stats */
|
||||
}
|
||||
|
||||
int msm_isp_request_stats_stream(struct vfe_device *vfe_dev, void *arg)
|
||||
{
|
||||
int rc = 0;
|
||||
/*To Do*/
|
||||
return rc;
|
||||
}
|
||||
|
||||
int msm_isp_release_stats_stream(struct vfe_device *vfe_dev, void *arg)
|
||||
{
|
||||
int rc = 0;
|
||||
struct msm_vfe_stats_stream_release_cmd *stream_release_cmd = arg;
|
||||
struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
|
||||
struct msm_vfe_stats_stream *stream_info =
|
||||
&stats_data->stream_info[
|
||||
(stream_release_cmd->stream_handle & 0xFF)];
|
||||
|
||||
if (stream_info == NULL)
|
||||
rc = -1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
int msm_isp_cfg_stats_stream(struct vfe_device *vfe_dev, void *arg)
|
||||
{
|
||||
int rc = 0;
|
||||
uint32_t stats_mask = 0;
|
||||
uint8_t enable = 0;
|
||||
uint32_t pingpong_status = 0;
|
||||
struct msm_isp_buffer *buf = NULL;
|
||||
enum msm_isp_stats_type stats_type = MSM_ISP_STATS_BE;
|
||||
vfe_dev->hw_info->vfe_ops.stats_ops.
|
||||
stats_enable(vfe_dev, stats_mask, enable);
|
||||
vfe_dev->hw_info->vfe_ops.stats_ops.
|
||||
update_ping_pong_addr(vfe_dev, stats_type,
|
||||
pingpong_status, buf->mapped_info[0].paddr);
|
||||
return rc;
|
||||
}
|
||||
23
drivers/media/video/msmb/isp/msm_isp_stats_util.h
Normal file
23
drivers/media/video/msmb/isp/msm_isp_stats_util.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/* Copyright (c) 2013, 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.h"
|
||||
|
||||
void msm_isp_process_stats_irq(struct vfe_device *vfe_dev,
|
||||
uint32_t irq_status0, uint32_t irq_status1,
|
||||
struct timeval *tv);
|
||||
int msm_isp_cfg_stats_stream(struct vfe_device *vfe_dev, void *arg);
|
||||
int msm_isp_release_stats_stream(struct vfe_device *vfe_dev, void *arg);
|
||||
int msm_isp_request_stats_stream(struct vfe_device *vfe_dev, void *arg);
|
||||
#endif /* __MSM_ISP_STATS_UTIL_H__ */
|
||||
462
drivers/media/video/msmb/isp/msm_isp_util.c
Normal file
462
drivers/media/video/msmb/isp/msm_isp_util.c
Normal file
@@ -0,0 +1,462 @@
|
||||
/* Copyright (c) 2013, 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 <media/v4l2-subdev.h>
|
||||
|
||||
#include "msm.h"
|
||||
#include "msm_isp_util.h"
|
||||
#include "msm_isp_axi_util.h"
|
||||
#include "msm_isp_stats_util.h"
|
||||
#include "msm_camera_io_util.h"
|
||||
|
||||
#define MAX_ISP_V4l2_EVENTS 100
|
||||
|
||||
void msm_isp_gettimeofday(struct timeval *tv)
|
||||
{
|
||||
struct timespec ts;
|
||||
|
||||
ktime_get_ts(&ts);
|
||||
tv->tv_sec = ts.tv_sec;
|
||||
tv->tv_usec = ts.tv_nsec/1000;
|
||||
}
|
||||
|
||||
int msm_isp_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
|
||||
struct v4l2_event_subscription *sub)
|
||||
{
|
||||
struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd);
|
||||
int rc = 0;
|
||||
rc = v4l2_event_subscribe(fh, sub, MAX_ISP_V4l2_EVENTS);
|
||||
if (rc == 0) {
|
||||
if (sub->type == V4L2_EVENT_ALL) {
|
||||
int i;
|
||||
|
||||
vfe_dev->axi_data.event_mask = 0;
|
||||
for (i = 0; i < ISP_EVENT_MAX; i++)
|
||||
vfe_dev->axi_data.event_mask |= (1 << i);
|
||||
} else {
|
||||
int event_idx = sub->type - ISP_EVENT_BASE;
|
||||
|
||||
vfe_dev->axi_data.event_mask |= (1 << event_idx);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int msm_isp_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
|
||||
struct v4l2_event_subscription *sub)
|
||||
{
|
||||
struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd);
|
||||
int rc = 0;
|
||||
|
||||
rc = v4l2_event_unsubscribe(fh, sub);
|
||||
if (sub->type == V4L2_EVENT_ALL) {
|
||||
vfe_dev->axi_data.event_mask = 0;
|
||||
} else {
|
||||
int event_idx = sub->type - ISP_EVENT_BASE;
|
||||
|
||||
vfe_dev->axi_data.event_mask &= ~(1 << event_idx);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int msm_isp_cfg_pix(struct vfe_device *vfe_dev,
|
||||
struct msm_vfe_pix_cfg *pix_cfg)
|
||||
{
|
||||
int rc = 0;
|
||||
/*TD Validate config info
|
||||
* should check if all streams are off */
|
||||
|
||||
vfe_dev->axi_data.src_info[VFE_PIX_0].input_mux = pix_cfg->input_mux;
|
||||
|
||||
vfe_dev->hw_info->vfe_ops.core_ops.cfg_camif(vfe_dev, pix_cfg);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int msm_isp_cfg_input(struct vfe_device *vfe_dev, void *arg)
|
||||
{
|
||||
int rc = 0;
|
||||
struct msm_vfe_input_cfg *input_cfg = arg;
|
||||
|
||||
switch (input_cfg->input_src) {
|
||||
case VFE_PIX_0:
|
||||
msm_isp_cfg_pix(vfe_dev, &input_cfg->d.pix_cfg);
|
||||
break;
|
||||
case VFE_RAW_0:
|
||||
case VFE_RAW_1:
|
||||
case VFE_RAW_2:
|
||||
case VFE_SRC_MAX:
|
||||
break;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
long msm_isp_ioctl(struct v4l2_subdev *sd,
|
||||
unsigned int cmd, void *arg)
|
||||
{
|
||||
struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd);
|
||||
|
||||
mutex_lock(&vfe_dev->mutex);
|
||||
ISP_DBG("%s cmd: %d\n", __func__, cmd);
|
||||
|
||||
switch (cmd) {
|
||||
case VIDIOC_MSM_VFE_REG_CFG: {
|
||||
msm_isp_proc_cmd(vfe_dev, arg);
|
||||
break;
|
||||
}
|
||||
case VIDIOC_MSM_ISP_REQUEST_BUF:
|
||||
case VIDIOC_MSM_ISP_ENQUEUE_BUF:
|
||||
case VIDIOC_MSM_ISP_RELEASE_BUF: {
|
||||
msm_isp_proc_buf_cmd(vfe_dev->buf_mgr, cmd, arg);
|
||||
break;
|
||||
}
|
||||
case VIDIOC_MSM_ISP_REQUEST_STREAM:
|
||||
msm_isp_request_axi_stream(vfe_dev, arg);
|
||||
break;
|
||||
case VIDIOC_MSM_ISP_RELEASE_STREAM:
|
||||
msm_isp_release_axi_stream(vfe_dev, arg);
|
||||
break;
|
||||
case VIDIOC_MSM_ISP_CFG_STREAM:
|
||||
msm_isp_cfg_axi_stream(vfe_dev, arg);
|
||||
break;
|
||||
case VIDIOC_MSM_ISP_INPUT_CFG:
|
||||
msm_isp_cfg_input(vfe_dev, arg);
|
||||
break;
|
||||
case VIDIOC_MSM_ISP_SET_SRC_STATE:
|
||||
msm_isp_set_src_state(vfe_dev, arg);
|
||||
break;
|
||||
case VIDIOC_MSM_ISP_REQUEST_STATS_STREAM:
|
||||
msm_isp_request_stats_stream(vfe_dev, arg);
|
||||
break;
|
||||
case VIDIOC_MSM_ISP_RELEASE_STATS_STREAM:
|
||||
msm_isp_release_stats_stream(vfe_dev, arg);
|
||||
break;
|
||||
case VIDIOC_MSM_ISP_CFG_STATS_STREAM:
|
||||
msm_isp_cfg_stats_stream(vfe_dev, arg);
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&vfe_dev->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev,
|
||||
struct msm_vfe_reg_cfg_cmd *reg_cfg_cmd, uint32_t *cfg_data)
|
||||
{
|
||||
switch (reg_cfg_cmd->cmd_type) {
|
||||
case VFE_WRITE: {
|
||||
if (resource_size(vfe_dev->vfe_mem) <
|
||||
(reg_cfg_cmd->reg_offset + reg_cfg_cmd->len)) {
|
||||
pr_err("%s: Invalid length\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
msm_camera_io_memcpy(vfe_dev->vfe_base +
|
||||
reg_cfg_cmd->reg_offset,
|
||||
cfg_data + reg_cfg_cmd->cmd_data/4, reg_cfg_cmd->len);
|
||||
break;
|
||||
}
|
||||
case VFE_WRITE_MB: {
|
||||
uint32_t *data_ptr = cfg_data + reg_cfg_cmd->cmd_data/4;
|
||||
msm_camera_io_w_mb(*data_ptr, vfe_dev->vfe_base +
|
||||
reg_cfg_cmd->reg_offset);
|
||||
break;
|
||||
}
|
||||
case VFE_WRITE_MASK: {
|
||||
uint32_t temp;
|
||||
temp = msm_camera_io_r(vfe_dev->vfe_base +
|
||||
reg_cfg_cmd->reg_offset);
|
||||
temp |= reg_cfg_cmd->cmd_data;
|
||||
msm_camera_io_w(temp, vfe_dev->vfe_base +
|
||||
reg_cfg_cmd->reg_offset);
|
||||
break;
|
||||
}
|
||||
case VFE_CLEAR_MASK: {
|
||||
uint32_t temp;
|
||||
temp = msm_camera_io_r(vfe_dev->vfe_base +
|
||||
reg_cfg_cmd->reg_offset);
|
||||
temp &= ~reg_cfg_cmd->cmd_data;
|
||||
msm_camera_io_w(temp, vfe_dev->vfe_base +
|
||||
reg_cfg_cmd->reg_offset);
|
||||
break;
|
||||
}
|
||||
case VFE_WRITE_AUTO_INCREMENT: {
|
||||
int i;
|
||||
uint32_t *data_ptr = cfg_data + reg_cfg_cmd->cmd_data/4;
|
||||
for (i = 0; i < reg_cfg_cmd->len/4; i++)
|
||||
msm_camera_io_w(*data_ptr++,
|
||||
vfe_dev->vfe_base + reg_cfg_cmd->reg_offset);
|
||||
break;
|
||||
}
|
||||
case VFE_READ: {
|
||||
int i;
|
||||
uint32_t *data_ptr = cfg_data + reg_cfg_cmd->cmd_data/4;
|
||||
for (i = 0; i < reg_cfg_cmd->len/4; i++)
|
||||
*data_ptr++ = msm_camera_io_r(
|
||||
vfe_dev->vfe_base + reg_cfg_cmd->reg_offset++);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int msm_isp_proc_cmd(struct vfe_device *vfe_dev, void *arg)
|
||||
{
|
||||
int rc = 0, i;
|
||||
struct msm_vfe_cfg_cmd2 *proc_cmd = arg;
|
||||
struct msm_vfe_reg_cfg_cmd *reg_cfg_cmd;
|
||||
uint32_t *cfg_data;
|
||||
|
||||
reg_cfg_cmd = kzalloc(sizeof(struct msm_vfe_reg_cfg_cmd)*
|
||||
proc_cmd->num_cfg, GFP_KERNEL);
|
||||
if (!reg_cfg_cmd) {
|
||||
pr_err("%s: reg_cfg alloc failed\n", __func__);
|
||||
rc = -ENOMEM;
|
||||
goto reg_cfg_failed;
|
||||
}
|
||||
|
||||
cfg_data = kzalloc(proc_cmd->cmd_len, GFP_KERNEL);
|
||||
if (!cfg_data) {
|
||||
pr_err("%s: cfg_data alloc failed\n", __func__);
|
||||
rc = -ENOMEM;
|
||||
goto cfg_data_failed;
|
||||
}
|
||||
|
||||
if (copy_from_user(reg_cfg_cmd,
|
||||
(void __user *)(proc_cmd->cfg_cmd),
|
||||
sizeof(struct msm_vfe_reg_cfg_cmd) * proc_cmd->num_cfg)) {
|
||||
rc = -EFAULT;
|
||||
goto copy_cmd_failed;
|
||||
}
|
||||
|
||||
if (copy_from_user(cfg_data,
|
||||
(void __user *)(proc_cmd->cfg_data),
|
||||
proc_cmd->cmd_len)) {
|
||||
rc = -EFAULT;
|
||||
goto copy_cmd_failed;
|
||||
}
|
||||
|
||||
for (i = 0; i < proc_cmd->num_cfg; i++)
|
||||
msm_isp_send_hw_cmd(vfe_dev, ®_cfg_cmd[i], cfg_data);
|
||||
|
||||
if (copy_to_user(proc_cmd->cfg_data,
|
||||
cfg_data, proc_cmd->cmd_len)) {
|
||||
rc = -EFAULT;
|
||||
goto copy_cmd_failed;
|
||||
}
|
||||
|
||||
copy_cmd_failed:
|
||||
kfree(cfg_data);
|
||||
cfg_data_failed:
|
||||
kfree(reg_cfg_cmd);
|
||||
reg_cfg_failed:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int msm_isp_send_event(struct vfe_device *vfe_dev,
|
||||
uint32_t event_type,
|
||||
struct msm_isp_event_data *event_data)
|
||||
{
|
||||
struct v4l2_event isp_event;
|
||||
memset(&isp_event, 0, sizeof(struct v4l2_event));
|
||||
isp_event.id = 0;
|
||||
isp_event.type = event_type;
|
||||
memcpy(&isp_event.u.data[0], event_data,
|
||||
sizeof(struct msm_isp_event_data));
|
||||
v4l2_event_queue(vfe_dev->subdev.sd.devnode, &isp_event);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define CAL_WORD(width, M, N) ((width * M + N - 1) / N)
|
||||
|
||||
int msm_isp_cal_word_per_line(uint32_t output_format,
|
||||
uint32_t pixel_per_line)
|
||||
{
|
||||
int val = -1;
|
||||
switch (output_format) {
|
||||
case V4L2_PIX_FMT_SBGGR8:
|
||||
case V4L2_PIX_FMT_SGBRG8:
|
||||
case V4L2_PIX_FMT_SGRBG8:
|
||||
case V4L2_PIX_FMT_SRGGB8:
|
||||
val = CAL_WORD(pixel_per_line, 1, 8);
|
||||
break;
|
||||
case V4L2_PIX_FMT_SBGGR10:
|
||||
case V4L2_PIX_FMT_SGBRG10:
|
||||
case V4L2_PIX_FMT_SGRBG10:
|
||||
case V4L2_PIX_FMT_SRGGB10:
|
||||
val = CAL_WORD(pixel_per_line, 1, 6);
|
||||
break;
|
||||
case V4L2_PIX_FMT_SBGGR12:
|
||||
case V4L2_PIX_FMT_SGBRG12:
|
||||
case V4L2_PIX_FMT_SGRBG12:
|
||||
case V4L2_PIX_FMT_SRGGB12:
|
||||
val = CAL_WORD(pixel_per_line, 1, 5);
|
||||
break;
|
||||
case V4L2_PIX_FMT_NV12:
|
||||
case V4L2_PIX_FMT_NV21:
|
||||
val = CAL_WORD(pixel_per_line, 1, 8);
|
||||
break;
|
||||
/*TD: Add more image format*/
|
||||
default:
|
||||
pr_err("%s: Invalid output format\n", __func__);
|
||||
break;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
irqreturn_t msm_isp_process_irq(int irq_num, void *data)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct msm_vfe_tasklet_queue_cmd *queue_cmd;
|
||||
struct vfe_device *vfe_dev = (struct vfe_device *) data;
|
||||
uint32_t irq_status0, irq_status1;
|
||||
|
||||
vfe_dev->hw_info->vfe_ops.irq_ops.
|
||||
read_irq_status(vfe_dev, &irq_status0, &irq_status1);
|
||||
if ((irq_status0 == 0) && (irq_status1 == 0)) {
|
||||
ISP_DBG("%s: irq_status0 & 1 are both 0!\n", __func__);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&vfe_dev->tasklet_lock, flags);
|
||||
queue_cmd = &vfe_dev->tasklet_queue_cmd[vfe_dev->taskletq_idx];
|
||||
if (queue_cmd->cmd_used) {
|
||||
pr_err("%s: Tasklet queue overflow\n", __func__);
|
||||
list_del(&queue_cmd->list);
|
||||
} else {
|
||||
atomic_add(1, &vfe_dev->irq_cnt);
|
||||
}
|
||||
queue_cmd->vfeInterruptStatus0 = irq_status0;
|
||||
queue_cmd->vfeInterruptStatus1 = irq_status1;
|
||||
msm_isp_gettimeofday(&queue_cmd->tv);
|
||||
queue_cmd->cmd_used = 1;
|
||||
vfe_dev->taskletq_idx =
|
||||
(vfe_dev->taskletq_idx + 1) % MSM_VFE_TASKLETQ_SIZE;
|
||||
list_add_tail(&queue_cmd->list, &vfe_dev->tasklet_q);
|
||||
spin_unlock_irqrestore(&vfe_dev->tasklet_lock, flags);
|
||||
tasklet_schedule(&vfe_dev->vfe_tasklet);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
void msm_isp_do_tasklet(unsigned long data)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct vfe_device *vfe_dev = (struct vfe_device *) data;
|
||||
struct msm_vfe_irq_ops *irq_ops = &vfe_dev->hw_info->vfe_ops.irq_ops;
|
||||
struct msm_vfe_tasklet_queue_cmd *queue_cmd;
|
||||
struct timeval tv;
|
||||
uint32_t irq_status0, irq_status1;
|
||||
while (atomic_read(&vfe_dev->irq_cnt)) {
|
||||
spin_lock_irqsave(&vfe_dev->tasklet_lock, flags);
|
||||
queue_cmd = list_first_entry(&vfe_dev->tasklet_q,
|
||||
struct msm_vfe_tasklet_queue_cmd, list);
|
||||
if (!queue_cmd) {
|
||||
atomic_set(&vfe_dev->irq_cnt, 0);
|
||||
spin_unlock_irqrestore(&vfe_dev->tasklet_lock, flags);
|
||||
return;
|
||||
}
|
||||
atomic_sub(1, &vfe_dev->irq_cnt);
|
||||
list_del(&queue_cmd->list);
|
||||
queue_cmd->cmd_used = 0;
|
||||
irq_status0 = queue_cmd->vfeInterruptStatus0;
|
||||
irq_status1 = queue_cmd->vfeInterruptStatus1;
|
||||
tv = queue_cmd->tv;
|
||||
spin_unlock_irqrestore(&vfe_dev->tasklet_lock, flags);
|
||||
ISP_DBG("%s: status0: 0x%x status1: 0x%x\n",
|
||||
__func__, irq_status0, irq_status1);
|
||||
irq_ops->process_reset_irq(vfe_dev,
|
||||
irq_status0, irq_status1);
|
||||
irq_ops->process_halt_irq(vfe_dev,
|
||||
irq_status0, irq_status1);
|
||||
irq_ops->process_camif_irq(vfe_dev,
|
||||
irq_status0, irq_status1);
|
||||
irq_ops->process_error_irq(vfe_dev,
|
||||
irq_status0, irq_status1);
|
||||
irq_ops->process_axi_irq(vfe_dev,
|
||||
irq_status0, irq_status1, &tv);
|
||||
irq_ops->process_stats_irq(vfe_dev,
|
||||
irq_status0, irq_status1, &tv);
|
||||
irq_ops->process_reg_update(vfe_dev, irq_status0, irq_status1);
|
||||
}
|
||||
}
|
||||
|
||||
void msm_isp_set_src_state(struct vfe_device *vfe_dev, void *arg)
|
||||
{
|
||||
struct msm_vfe_axi_src_state *src_state = arg;
|
||||
vfe_dev->axi_data.src_info[src_state->input_src].active =
|
||||
src_state->src_active;
|
||||
}
|
||||
|
||||
int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
|
||||
{
|
||||
struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd);
|
||||
long rc;
|
||||
ISP_DBG("%s\n", __func__);
|
||||
|
||||
mutex_lock(&vfe_dev->mutex);
|
||||
if (vfe_dev->vfe_open_cnt == 1) {
|
||||
pr_err("VFE already open\n");
|
||||
mutex_unlock(&vfe_dev->mutex);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (vfe_dev->hw_info->vfe_ops.core_ops.init_hw(vfe_dev) < 0) {
|
||||
pr_err("%s: init hardware failed\n", __func__);
|
||||
mutex_unlock(&vfe_dev->mutex);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
rc = vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev);
|
||||
if (rc <= 0) {
|
||||
pr_err("%s: reset timeout\n", __func__);
|
||||
mutex_unlock(&vfe_dev->mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
vfe_dev->hw_info->vfe_ops.core_ops.init_hw_reg(vfe_dev);
|
||||
|
||||
vfe_dev->buf_mgr->ops->attach_ctx(vfe_dev->buf_mgr, vfe_dev->iommu_ctx);
|
||||
vfe_dev->buf_mgr->ops->buf_mgr_init(vfe_dev->buf_mgr, "msm_isp", 14);
|
||||
|
||||
memset(&vfe_dev->axi_data, 0, sizeof(struct msm_vfe_axi_shared_data));
|
||||
vfe_dev->axi_data.hw_info = vfe_dev->hw_info->axi_hw_info;
|
||||
|
||||
ISP_DBG("%s: HW Version: 0x%x\n",
|
||||
__func__, msm_camera_io_r(vfe_dev->vfe_base));
|
||||
|
||||
vfe_dev->vfe_open_cnt++;
|
||||
vfe_dev->taskletq_idx = 0;
|
||||
mutex_unlock(&vfe_dev->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int msm_isp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
|
||||
{
|
||||
long rc;
|
||||
struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd);
|
||||
ISP_DBG("%s\n", __func__);
|
||||
mutex_lock(&vfe_dev->mutex);
|
||||
if (vfe_dev->vfe_open_cnt == 0) {
|
||||
pr_err("%s: Invalid close\n", __func__);
|
||||
mutex_unlock(&vfe_dev->mutex);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
rc = vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev);
|
||||
if (rc <= 0)
|
||||
pr_err("%s: halt timeout\n", __func__);
|
||||
|
||||
vfe_dev->buf_mgr->ops->buf_mgr_deinit(vfe_dev->buf_mgr);
|
||||
vfe_dev->buf_mgr->ops->detach_ctx(vfe_dev->buf_mgr, vfe_dev->iommu_ctx);
|
||||
vfe_dev->hw_info->vfe_ops.core_ops.release_hw(vfe_dev);
|
||||
|
||||
vfe_dev->vfe_open_cnt--;
|
||||
mutex_unlock(&vfe_dev->mutex);
|
||||
return 0;
|
||||
}
|
||||
45
drivers/media/video/msmb/isp/msm_isp_util.h
Normal file
45
drivers/media/video/msmb/isp/msm_isp_util.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/* Copyright (c) 2013, 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.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
|
||||
|
||||
void msm_isp_gettimeofday(struct timeval *tv);
|
||||
|
||||
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_isp_event_data *event_data);
|
||||
int msm_isp_cal_word_per_line(uint32_t output_format,
|
||||
uint32_t pixel_per_line);
|
||||
irqreturn_t msm_isp_process_irq(int irq_num, void *data);
|
||||
void msm_isp_set_src_state(struct vfe_device *vfe_dev, void *arg);
|
||||
void msm_isp_do_tasklet(unsigned long data);
|
||||
|
||||
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);
|
||||
#endif /* __MSM_ISP_UTIL_H__ */
|
||||
3
drivers/media/video/msmb/ispif/Makefile
Normal file
3
drivers/media/video/msmb/ispif/Makefile
Normal file
@@ -0,0 +1,3 @@
|
||||
ccflags-y += -Idrivers/media/video/msmb
|
||||
ccflags-y += -Idrivers/media/video/msmb/sensor/io
|
||||
obj-$(CONFIG_MSM_CSID) += msm_ispif.o
|
||||
954
drivers/media/video/msmb/ispif/msm_ispif.c
Normal file
954
drivers/media/video/msmb/ispif/msm_ispif.c
Normal file
@@ -0,0 +1,954 @@
|
||||
/* Copyright (c) 2013, 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/jiffies.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include "msm_ispif.h"
|
||||
#include "msm.h"
|
||||
#include "msm_ispif_hwreg.h"
|
||||
#include "msm_sd.h"
|
||||
#include "msm_camera_io_util.h"
|
||||
|
||||
#define V4L2_IDENT_ISPIF 50001
|
||||
#define MSM_ISPIF_DRV_NAME "msm_ispif"
|
||||
#define DUMP_BUFF_SIZE_128 128
|
||||
|
||||
#define ISPIF_INTF_CMD_ENABLE_FRAME_BOUNDARY 0x01
|
||||
#define ISPIF_INTF_CMD_DISABLE_FRAME_BOUNDARY 0x00
|
||||
#define ISPIF_INTF_CMD_DISABLE_IMMEDIATELY 0x02
|
||||
|
||||
#define CONFIG_MSMB_CAMERA_DEBUG
|
||||
#undef CDBG
|
||||
#ifdef CONFIG_MSMB_CAMERA_DEBUG
|
||||
#define CDBG(fmt, args...) pr_debug(fmt, ##args)
|
||||
#else
|
||||
#define CDBG(fmt, args...) do { } while (0)
|
||||
#endif
|
||||
|
||||
static void msm_ispif_io_dump(void __iomem *addr, int size)
|
||||
{
|
||||
char line_str[DUMP_BUFF_SIZE_128], *p_str;
|
||||
int i;
|
||||
u32 *p = (u32 *) addr;
|
||||
u32 data;
|
||||
|
||||
|
||||
CDBG("%s: %p %d\n", __func__, addr, size);
|
||||
line_str[0] = '\0';
|
||||
p_str = line_str;
|
||||
for (i = 0; i < size/4; i++) {
|
||||
if (i % 4 == 0) {
|
||||
snprintf(p_str, 12, "%08x: ", (u32) p);
|
||||
p_str += 10;
|
||||
}
|
||||
data = readl_relaxed(p++);
|
||||
snprintf(p_str, 12, "%08x ", data);
|
||||
p_str += 9;
|
||||
if ((i + 1) % 4 == 0) {
|
||||
CDBG("%s\n", line_str);
|
||||
line_str[0] = '\0';
|
||||
p_str = line_str;
|
||||
}
|
||||
}
|
||||
if (line_str[0] != '\0')
|
||||
CDBG("%s\n", line_str);
|
||||
}
|
||||
|
||||
static void msm_ispif_io_dump_reg(struct ispif_device *ispif)
|
||||
{
|
||||
int size;
|
||||
|
||||
if (!ispif->enb_dump_reg)
|
||||
return;
|
||||
size = 0x250;
|
||||
msm_ispif_io_dump(ispif->base+0x100, size);
|
||||
}
|
||||
|
||||
static int msm_ispif_intf_reset(struct ispif_device *ispif,
|
||||
struct msm_ispif_param_data *params)
|
||||
{
|
||||
|
||||
int i, rc = 0;
|
||||
enum msm_ispif_intftype intf_type;
|
||||
uint32_t data = (0x1 << STROBED_RST_EN);
|
||||
|
||||
for (i = 0; i < params->num; i++) {
|
||||
intf_type = params->entries[i].intftype;
|
||||
ispif->sof_count[params->vfe_intf].sof_cnt[intf_type] = 0;
|
||||
switch (intf_type) {
|
||||
case PIX0:
|
||||
data |= (0x1 << PIX_0_VFE_RST_STB) |
|
||||
(0x1 << PIX_0_CSID_RST_STB);
|
||||
break;
|
||||
case RDI0:
|
||||
data |= (0x1 << RDI_0_VFE_RST_STB) |
|
||||
(0x1 << RDI_0_CSID_RST_STB);
|
||||
break;
|
||||
case PIX1:
|
||||
data |= (0x1 << PIX_1_VFE_RST_STB) |
|
||||
(0x1 << PIX_1_CSID_RST_STB);
|
||||
break;
|
||||
case RDI1:
|
||||
data |= (0x1 << RDI_1_VFE_RST_STB) |
|
||||
(0x1 << RDI_1_CSID_RST_STB);
|
||||
break;
|
||||
case RDI2:
|
||||
data |= (0x1 << RDI_2_VFE_RST_STB) |
|
||||
(0x1 << RDI_2_CSID_RST_STB);
|
||||
break;
|
||||
default:
|
||||
rc = -EINVAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (data > 0x1) {
|
||||
unsigned long jiffes = msecs_to_jiffies(500);
|
||||
long lrc = 0;
|
||||
if (params->vfe_intf == VFE0)
|
||||
msm_camera_io_w(data, ispif->base + ISPIF_RST_CMD_ADDR);
|
||||
else
|
||||
msm_camera_io_w(data, ispif->base +
|
||||
ISPIF_RST_CMD_1_ADDR);
|
||||
lrc = wait_for_completion_interruptible_timeout(
|
||||
&ispif->reset_complete, jiffes);
|
||||
if (lrc < 0 || !lrc) {
|
||||
pr_err("%s: wait timeout ret = %ld\n", __func__, lrc);
|
||||
rc = -EIO;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int msm_ispif_reset(struct ispif_device *ispif)
|
||||
{
|
||||
int rc = 0;
|
||||
unsigned long jiffes = msecs_to_jiffies(500);
|
||||
long lrc = 0;
|
||||
|
||||
memset(ispif->sof_count, 0, sizeof(ispif->sof_count));
|
||||
msm_camera_io_w(ISPIF_RST_CMD_MASK, ispif->base + ISPIF_RST_CMD_ADDR);
|
||||
if (ispif->csid_version == CSID_VERSION_V3)
|
||||
msm_camera_io_w_mb(ISPIF_RST_CMD_1_MASK, ispif->base +
|
||||
ISPIF_RST_CMD_1_ADDR);
|
||||
CDBG("%s: Sending reset\n", __func__);
|
||||
lrc = wait_for_completion_interruptible_timeout(
|
||||
&ispif->reset_complete, jiffes);
|
||||
if (lrc < 0 || !lrc) {
|
||||
pr_err("%s: wait timeout ret = %ld\n", __func__, lrc);
|
||||
rc = -EIO;
|
||||
}
|
||||
CDBG("%s: reset returned\n", __func__);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int msm_ispif_subdev_g_chip_ident(struct v4l2_subdev *sd,
|
||||
struct v4l2_dbg_chip_ident *chip)
|
||||
{
|
||||
BUG_ON(!chip);
|
||||
chip->ident = V4L2_IDENT_ISPIF;
|
||||
chip->revision = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void msm_ispif_sel_csid_core(struct ispif_device *ispif,
|
||||
uint8_t intftype, uint8_t csid, uint8_t vfe_intf)
|
||||
{
|
||||
int rc = 0;
|
||||
uint32_t data = 0;
|
||||
|
||||
if (ispif->csid_version <= CSID_VERSION_V2) {
|
||||
if (ispif->ispif_clk[intftype] == NULL) {
|
||||
CDBG("%s: ispif NULL clk\n", __func__);
|
||||
return;
|
||||
}
|
||||
rc = clk_set_rate(ispif->ispif_clk[intftype], csid);
|
||||
if (rc < 0)
|
||||
pr_err("%s: clk_set_rate failed %d\n", __func__, rc);
|
||||
return;
|
||||
}
|
||||
data = msm_camera_io_r(ispif->base + ISPIF_INPUT_SEL_ADDR +
|
||||
(0x200 * vfe_intf));
|
||||
switch (intftype) {
|
||||
case PIX0:
|
||||
data &= ~(0x3); /* clear old setting */
|
||||
data |= csid; /* add new setting */
|
||||
break;
|
||||
case RDI0:
|
||||
data &= ~(0x3 << 4); /* clear old setting */
|
||||
data |= (csid << 4); /* add new setting */
|
||||
break;
|
||||
case PIX1:
|
||||
data &= ~(0x3 << 8); /* clear old setting */
|
||||
data |= (csid << 8); /* add new setting */
|
||||
break;
|
||||
case RDI1:
|
||||
data &= ~(0x3 << 12); /* clear old setting */
|
||||
data |= (csid << 12); /* add new setting */
|
||||
break;
|
||||
case RDI2:
|
||||
data &= ~(0x3 << 20); /* clear old setting */
|
||||
data |= (csid << 20); /* add new setting */
|
||||
break;
|
||||
}
|
||||
if (data) {
|
||||
msm_camera_io_w_mb(data, ispif->base + ISPIF_INPUT_SEL_ADDR +
|
||||
(0x200 * vfe_intf));
|
||||
}
|
||||
}
|
||||
|
||||
static void msm_ispif_enable_intf_cids(struct ispif_device *ispif,
|
||||
uint8_t intftype, uint16_t cid_mask,
|
||||
uint8_t vfe_intf, uint8_t enable)
|
||||
{
|
||||
uint32_t data = 0;
|
||||
|
||||
switch (intftype) {
|
||||
case PIX0:
|
||||
data = msm_camera_io_r(ispif->base +
|
||||
ISPIF_PIX_0_INTF_CID_MASK_ADDR + (0x200 * vfe_intf));
|
||||
if (enable)
|
||||
data |= cid_mask; /* add new config */
|
||||
else
|
||||
data &= ~cid_mask; /* remove CID bit */
|
||||
msm_camera_io_w_mb(data, ispif->base +
|
||||
ISPIF_PIX_0_INTF_CID_MASK_ADDR + (0x200 * vfe_intf));
|
||||
break;
|
||||
case RDI0:
|
||||
data = msm_camera_io_r(ispif->base +
|
||||
ISPIF_RDI_0_INTF_CID_MASK_ADDR + (0x200 * vfe_intf));
|
||||
if (enable)
|
||||
data |= cid_mask; /* add new config */
|
||||
else
|
||||
data &= ~cid_mask; /* remove CID bit */
|
||||
msm_camera_io_w_mb(data, ispif->base +
|
||||
ISPIF_RDI_0_INTF_CID_MASK_ADDR + (0x200 * vfe_intf));
|
||||
break;
|
||||
case PIX1:
|
||||
data = msm_camera_io_r(ispif->base +
|
||||
ISPIF_PIX_1_INTF_CID_MASK_ADDR + (0x200 * vfe_intf));
|
||||
if (enable)
|
||||
data |= cid_mask; /* add new config */
|
||||
else
|
||||
data &= ~cid_mask; /* remove CID bit */
|
||||
msm_camera_io_w_mb(data, ispif->base +
|
||||
ISPIF_PIX_1_INTF_CID_MASK_ADDR + (0x200 * vfe_intf));
|
||||
break;
|
||||
case RDI1:
|
||||
data = msm_camera_io_r(ispif->base +
|
||||
ISPIF_RDI_1_INTF_CID_MASK_ADDR + (0x200 * vfe_intf));
|
||||
if (enable)
|
||||
data |= cid_mask; /* add new config */
|
||||
else
|
||||
data &= ~cid_mask; /* remove CID bit */
|
||||
msm_camera_io_w_mb(data, ispif->base +
|
||||
ISPIF_RDI_1_INTF_CID_MASK_ADDR + (0x200 * vfe_intf));
|
||||
break;
|
||||
case RDI2:
|
||||
data = msm_camera_io_r(ispif->base +
|
||||
ISPIF_RDI_2_INTF_CID_MASK_ADDR + (0x200 * vfe_intf));
|
||||
if (enable)
|
||||
data |= cid_mask; /* add new config */
|
||||
else
|
||||
data &= ~cid_mask; /* remove CID bit */
|
||||
msm_camera_io_w_mb(data, ispif->base +
|
||||
ISPIF_RDI_2_INTF_CID_MASK_ADDR + (0x200 * vfe_intf));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t msm_ispif_validate_intf_status(struct ispif_device *ispif,
|
||||
uint8_t intftype, uint8_t vfe_intf)
|
||||
{
|
||||
int32_t rc = 0;
|
||||
uint32_t data = 0;
|
||||
switch (intftype) {
|
||||
case PIX0:
|
||||
data = msm_camera_io_r(ispif->base +
|
||||
ISPIF_PIX_0_STATUS_ADDR + (0x200 * vfe_intf));
|
||||
break;
|
||||
case RDI0:
|
||||
data = msm_camera_io_r(ispif->base +
|
||||
ISPIF_RDI_0_STATUS_ADDR + (0x200 * vfe_intf));
|
||||
break;
|
||||
case PIX1:
|
||||
data = msm_camera_io_r(ispif->base +
|
||||
ISPIF_PIX_1_STATUS_ADDR + (0x200 * vfe_intf));
|
||||
break;
|
||||
case RDI1:
|
||||
data = msm_camera_io_r(ispif->base +
|
||||
ISPIF_RDI_1_STATUS_ADDR + (0x200 * vfe_intf));
|
||||
break;
|
||||
case RDI2:
|
||||
data = msm_camera_io_r(ispif->base +
|
||||
ISPIF_RDI_2_STATUS_ADDR + (0x200 * vfe_intf));
|
||||
break;
|
||||
}
|
||||
if ((data & 0xf) != 0xf)
|
||||
rc = -EBUSY;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static uint16_t msm_ispif_get_cids_mask_from_cfg(
|
||||
struct msm_ispif_params_entry *entry)
|
||||
{
|
||||
int i;
|
||||
uint16_t cids_mask = 0;
|
||||
|
||||
for (i = 0; i < entry->num_cids; i++)
|
||||
cids_mask |= (1 << entry->cids[i]);
|
||||
return cids_mask;
|
||||
}
|
||||
|
||||
static int msm_ispif_config(struct ispif_device *ispif,
|
||||
struct msm_ispif_param_data *params)
|
||||
{
|
||||
int rc = 0, i = 0;
|
||||
enum msm_ispif_intftype intftype;
|
||||
enum msm_ispif_vfe_intf vfe_intf = params->vfe_intf;
|
||||
uint16_t cid_mask;
|
||||
|
||||
msm_camera_io_w(0x00000000, ispif->base + ISPIF_IRQ_MASK_ADDR);
|
||||
msm_camera_io_w(0x00000000, ispif->base + ISPIF_IRQ_MASK_1_ADDR);
|
||||
msm_camera_io_w_mb(0x00000000, ispif->base + ISPIF_IRQ_MASK_2_ADDR);
|
||||
for (i = 0; i < params->num; i++) {
|
||||
intftype = params->entries[i].intftype;
|
||||
vfe_intf = params->vfe_intf;
|
||||
CDBG("%s intftype %x, vfe_intf %d, csid %d\n", __func__,
|
||||
intftype, vfe_intf, params->entries[i].csid);
|
||||
if ((intftype >= INTF_MAX) ||
|
||||
(ispif->csid_version <= CSID_VERSION_V2 &&
|
||||
vfe_intf > VFE0) ||
|
||||
(ispif->csid_version == CSID_VERSION_V3 &&
|
||||
vfe_intf >= VFE_MAX)) {
|
||||
pr_err("%s: VFEID %d and CSID version %d mismatch\n",
|
||||
__func__, vfe_intf, ispif->csid_version);
|
||||
return -EINVAL;
|
||||
}
|
||||
rc = msm_ispif_validate_intf_status(ispif, intftype, vfe_intf);
|
||||
if (rc < 0) {
|
||||
pr_err("%s:validate_intf_status failed, rc = %d\n",
|
||||
__func__, rc);
|
||||
return rc;
|
||||
}
|
||||
msm_ispif_sel_csid_core(ispif, intftype,
|
||||
params->entries[i].csid, vfe_intf);
|
||||
cid_mask = msm_ispif_get_cids_mask_from_cfg(
|
||||
¶ms->entries[i]);
|
||||
msm_ispif_enable_intf_cids(ispif, intftype,
|
||||
cid_mask, vfe_intf, 1);
|
||||
}
|
||||
|
||||
msm_camera_io_w(ISPIF_IRQ_STATUS_MASK, ispif->base +
|
||||
ISPIF_IRQ_MASK_ADDR);
|
||||
|
||||
msm_camera_io_w(ISPIF_IRQ_STATUS_MASK, ispif->base +
|
||||
ISPIF_IRQ_CLEAR_ADDR);
|
||||
|
||||
msm_camera_io_w(ISPIF_IRQ_STATUS_1_MASK, ispif->base +
|
||||
ISPIF_IRQ_MASK_1_ADDR);
|
||||
|
||||
msm_camera_io_w(ISPIF_IRQ_STATUS_1_MASK, ispif->base +
|
||||
ISPIF_IRQ_CLEAR_1_ADDR);
|
||||
|
||||
msm_camera_io_w(ISPIF_IRQ_STATUS_2_MASK, ispif->base +
|
||||
ISPIF_IRQ_MASK_2_ADDR);
|
||||
|
||||
msm_camera_io_w(ISPIF_IRQ_STATUS_2_MASK, ispif->base +
|
||||
ISPIF_IRQ_CLEAR_2_ADDR);
|
||||
|
||||
msm_camera_io_w_mb(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base +
|
||||
ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void msm_ispif_intf_cmd(struct ispif_device *ispif,
|
||||
uint32_t cmd_bits,
|
||||
struct msm_ispif_param_data *params)
|
||||
{
|
||||
uint8_t vc = 0;
|
||||
int i, k;
|
||||
enum msm_ispif_intftype intf_type;
|
||||
enum msm_ispif_cid cid;
|
||||
enum msm_ispif_vfe_intf vfe_intf = params->vfe_intf;
|
||||
|
||||
for (i = 0; i < params->num; i++) {
|
||||
intf_type = params->entries[i].intftype;
|
||||
for (k = 0; k < params->entries[i].num_cids; k++) {
|
||||
cid = params->entries[i].cids[k];
|
||||
vc = cid % 4;
|
||||
if (intf_type == RDI2) {
|
||||
/* zero out two bits */
|
||||
ispif->applied_intf_cmd[vfe_intf].intf_cmd1 &=
|
||||
~(0x3 << (vc * 2 + 8));
|
||||
ispif->applied_intf_cmd[vfe_intf].intf_cmd1 |=
|
||||
(cmd_bits << (vc * 2 + 8)); /* set cmd bits */
|
||||
} else {
|
||||
/* zero 2 bits */
|
||||
ispif->applied_intf_cmd[vfe_intf].intf_cmd &=
|
||||
~(0x3 << (vc * 2 + vfe_intf * 8));
|
||||
/* set cmd bits */
|
||||
ispif->applied_intf_cmd[vfe_intf].intf_cmd |=
|
||||
(cmd_bits << (vc * 2 + vfe_intf * 8));
|
||||
}
|
||||
}
|
||||
}
|
||||
/* cmd for PIX0, PIX1, RDI0, RDI1 */
|
||||
if (ispif->applied_intf_cmd[vfe_intf].intf_cmd != 0xFFFFFFFF) {
|
||||
msm_camera_io_w_mb(ispif->applied_intf_cmd[vfe_intf].intf_cmd,
|
||||
ispif->base + ISPIF_INTF_CMD_ADDR +
|
||||
(0x200 * vfe_intf));
|
||||
}
|
||||
/* cmd for RDI2 */
|
||||
if (ispif->applied_intf_cmd[vfe_intf].intf_cmd1 != 0xFFFFFFFF)
|
||||
msm_camera_io_w_mb(ispif->applied_intf_cmd[vfe_intf].intf_cmd1,
|
||||
ispif->base + ISPIF_INTF_CMD_1_ADDR +
|
||||
(0x200 * vfe_intf));
|
||||
}
|
||||
|
||||
static int msm_ispif_stop_immediately(struct ispif_device *ispif,
|
||||
struct msm_ispif_param_data *params)
|
||||
{
|
||||
int i, rc = 0;
|
||||
uint16_t cid_mask = 0;
|
||||
|
||||
msm_ispif_intf_cmd(ispif, ISPIF_INTF_CMD_DISABLE_IMMEDIATELY, params);
|
||||
|
||||
/* after stop the interface we need to unmask the CID enable bits */
|
||||
for (i = 0; i < params->num; i++) {
|
||||
cid_mask = msm_ispif_get_cids_mask_from_cfg(
|
||||
¶ms->entries[i]);
|
||||
msm_ispif_enable_intf_cids(ispif, params->entries[i].intftype,
|
||||
cid_mask, params->vfe_intf, 0);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int msm_ispif_start_frame_boundary(struct ispif_device *ispif,
|
||||
struct msm_ispif_param_data *params)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
rc = msm_ispif_intf_reset(ispif, params);
|
||||
msm_ispif_intf_cmd(ispif, ISPIF_INTF_CMD_ENABLE_FRAME_BOUNDARY, params);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int msm_ispif_stop_frame_boundary(struct ispif_device *ispif,
|
||||
struct msm_ispif_param_data *params)
|
||||
{
|
||||
int i, rc = 0;
|
||||
uint16_t cid_mask = 0;
|
||||
|
||||
msm_ispif_intf_cmd(ispif,
|
||||
ISPIF_INTF_CMD_DISABLE_FRAME_BOUNDARY, params);
|
||||
for (i = 0; i < params->num; i++) {
|
||||
cid_mask =
|
||||
msm_ispif_get_cids_mask_from_cfg(
|
||||
¶ms->entries[i]);
|
||||
switch (params->entries[i].intftype) {
|
||||
case PIX0:
|
||||
while ((msm_camera_io_r(ispif->base +
|
||||
ISPIF_PIX_0_STATUS_ADDR +
|
||||
(0x200 * params->vfe_intf)) & 0xf) != 0xf) {
|
||||
CDBG("Wait for pix0 Idle\n");
|
||||
}
|
||||
break;
|
||||
case RDI0:
|
||||
while ((msm_camera_io_r(ispif->base +
|
||||
ISPIF_RDI_0_STATUS_ADDR +
|
||||
(0x200 * params->vfe_intf)) & 0xf) != 0xf) {
|
||||
CDBG("Wait for rdi0 Idle\n");
|
||||
}
|
||||
break;
|
||||
case PIX1:
|
||||
while ((msm_camera_io_r(ispif->base +
|
||||
ISPIF_PIX_1_STATUS_ADDR +
|
||||
(0x200 * params->vfe_intf)) & 0xf) != 0xf) {
|
||||
CDBG("Wait for pix1 Idle\n");
|
||||
}
|
||||
break;
|
||||
case RDI1:
|
||||
while ((msm_camera_io_r(ispif->base +
|
||||
ISPIF_RDI_1_STATUS_ADDR +
|
||||
(0x200 * params->vfe_intf)) & 0xf) != 0xf) {
|
||||
CDBG("Wait for rdi1 Idle\n");
|
||||
}
|
||||
break;
|
||||
case RDI2:
|
||||
while ((msm_camera_io_r(ispif->base +
|
||||
ISPIF_RDI_2_STATUS_ADDR +
|
||||
(0x200 * params->vfe_intf)) & 0xf) != 0xf) {
|
||||
CDBG("Wait for rdi2 Idle\n");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/* disable CIDs in CID_MASK register */
|
||||
msm_ispif_enable_intf_cids(ispif, params->entries[i].intftype,
|
||||
cid_mask, params->vfe_intf, 0);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void ispif_process_irq(struct ispif_device *ispif,
|
||||
struct ispif_irq_status *out, enum msm_ispif_vfe_intf vfe_id)
|
||||
{
|
||||
if (out[vfe_id].ispifIrqStatus0 &
|
||||
ISPIF_IRQ_STATUS_PIX_SOF_MASK) {
|
||||
ispif->sof_count[vfe_id].sof_cnt[PIX0]++;
|
||||
}
|
||||
if (out[vfe_id].ispifIrqStatus0 &
|
||||
ISPIF_IRQ_STATUS_RDI0_SOF_MASK) {
|
||||
ispif->sof_count[vfe_id].sof_cnt[RDI0]++;
|
||||
}
|
||||
if (out[vfe_id].ispifIrqStatus1 &
|
||||
ISPIF_IRQ_STATUS_RDI1_SOF_MASK) {
|
||||
ispif->sof_count[vfe_id].sof_cnt[RDI1]++;
|
||||
}
|
||||
if (out[vfe_id].ispifIrqStatus2 &
|
||||
ISPIF_IRQ_STATUS_RDI2_SOF_MASK) {
|
||||
ispif->sof_count[vfe_id].sof_cnt[RDI2]++;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void msm_ispif_read_irq_status(struct ispif_irq_status *out,
|
||||
void *data)
|
||||
{
|
||||
struct ispif_device *ispif = (struct ispif_device *)data;
|
||||
|
||||
out[VFE0].ispifIrqStatus0 = msm_camera_io_r(ispif->base +
|
||||
ISPIF_IRQ_STATUS_ADDR);
|
||||
out[VFE0].ispifIrqStatus1 = msm_camera_io_r(ispif->base +
|
||||
ISPIF_IRQ_STATUS_1_ADDR);
|
||||
out[VFE0].ispifIrqStatus2 = msm_camera_io_r(ispif->base +
|
||||
ISPIF_IRQ_STATUS_2_ADDR);
|
||||
msm_camera_io_w(out[VFE0].ispifIrqStatus0,
|
||||
ispif->base + ISPIF_IRQ_CLEAR_ADDR);
|
||||
msm_camera_io_w(out[VFE0].ispifIrqStatus1,
|
||||
ispif->base + ISPIF_IRQ_CLEAR_1_ADDR);
|
||||
msm_camera_io_w_mb(out[VFE0].ispifIrqStatus2,
|
||||
ispif->base + ISPIF_IRQ_CLEAR_2_ADDR);
|
||||
|
||||
if (out[VFE0].ispifIrqStatus0 & ISPIF_IRQ_STATUS_MASK) {
|
||||
if (out[VFE0].ispifIrqStatus0 & (0x1 <<
|
||||
RESET_DONE_IRQ))
|
||||
complete(&ispif->reset_complete);
|
||||
if (out[VFE0].ispifIrqStatus0 & (0x1 <<
|
||||
PIX_INTF_0_OVERFLOW_IRQ))
|
||||
pr_err("%s: VFE0 pix0 overflow.\n", __func__);
|
||||
if (out[VFE0].ispifIrqStatus0 & (0x1 <<
|
||||
RAW_INTF_0_OVERFLOW_IRQ))
|
||||
pr_err("%s: VFE0 rdi0 overflow.\n", __func__);
|
||||
if (out[VFE0].ispifIrqStatus1 & (0x1 <<
|
||||
RAW_INTF_1_OVERFLOW_IRQ))
|
||||
pr_err("%s: VFE0 rdi1 overflow.\n", __func__);
|
||||
if (out[VFE0].ispifIrqStatus2 & (0x1 <<
|
||||
RAW_INTF_2_OVERFLOW_IRQ))
|
||||
pr_err("%s: VFE0 rdi2 overflow.\n", __func__);
|
||||
if ((out[VFE0].ispifIrqStatus0 &
|
||||
ISPIF_IRQ_STATUS_SOF_MASK) ||
|
||||
(out[VFE0].ispifIrqStatus1 &
|
||||
ISPIF_IRQ_STATUS_SOF_MASK) ||
|
||||
(out[VFE0].ispifIrqStatus2 &
|
||||
ISPIF_IRQ_STATUS_RDI2_SOF_MASK))
|
||||
ispif_process_irq(ispif, out, VFE0);
|
||||
}
|
||||
if (ispif->csid_version == CSID_VERSION_V3) {
|
||||
out[VFE1].ispifIrqStatus0 = msm_camera_io_r(ispif->base +
|
||||
ISPIF_IRQ_STATUS_ADDR + 0x200);
|
||||
msm_camera_io_w(out[VFE1].ispifIrqStatus0,
|
||||
ispif->base + ISPIF_IRQ_CLEAR_ADDR + 0x200);
|
||||
out[VFE1].ispifIrqStatus1 = msm_camera_io_r(ispif->base +
|
||||
ISPIF_IRQ_STATUS_1_ADDR + 0x200);
|
||||
msm_camera_io_w(out[VFE1].ispifIrqStatus1,
|
||||
ispif->base + ISPIF_IRQ_CLEAR_1_ADDR + 0x200);
|
||||
out[VFE1].ispifIrqStatus2 = msm_camera_io_r(ispif->base +
|
||||
ISPIF_IRQ_STATUS_2_ADDR + 0x200);
|
||||
msm_camera_io_w_mb(out[VFE1].ispifIrqStatus2,
|
||||
ispif->base + ISPIF_IRQ_CLEAR_2_ADDR + 0x200);
|
||||
if (out[VFE1].ispifIrqStatus0 & (0x1 <<
|
||||
PIX_INTF_0_OVERFLOW_IRQ))
|
||||
pr_err("%s: VFE1 pix0 overflow.\n", __func__);
|
||||
if (out[VFE1].ispifIrqStatus0 & (0x1 <<
|
||||
RAW_INTF_0_OVERFLOW_IRQ))
|
||||
pr_err("%s: VFE1 rdi0 overflow.\n", __func__);
|
||||
if (out[VFE1].ispifIrqStatus1 & (0x1 <<
|
||||
RAW_INTF_1_OVERFLOW_IRQ))
|
||||
pr_err("%s: VFE1 rdi1 overflow.\n", __func__);
|
||||
if (out[VFE1].ispifIrqStatus2 & (0x1 <<
|
||||
RAW_INTF_2_OVERFLOW_IRQ))
|
||||
pr_err("%s: VFE1 rdi2 overflow.\n", __func__);
|
||||
if ((out[VFE1].ispifIrqStatus0 & ISPIF_IRQ_STATUS_SOF_MASK) ||
|
||||
(out[VFE1].ispifIrqStatus1 &
|
||||
ISPIF_IRQ_STATUS_SOF_MASK) ||
|
||||
(out[VFE1].ispifIrqStatus2 &
|
||||
ISPIF_IRQ_STATUS_RDI2_SOF_MASK))
|
||||
ispif_process_irq(ispif, out, VFE1);
|
||||
}
|
||||
msm_camera_io_w_mb(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base +
|
||||
ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR);
|
||||
}
|
||||
|
||||
static irqreturn_t msm_io_ispif_irq(int irq_num, void *data)
|
||||
{
|
||||
struct ispif_irq_status irq[VFE_MAX];
|
||||
|
||||
msm_ispif_read_irq_status(irq, data);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static struct msm_cam_clk_info ispif_8960_clk_info[] = {
|
||||
{"csi_pix_clk", 0},
|
||||
{"csi_rdi_clk", 0},
|
||||
{"csi_pix1_clk", 0},
|
||||
{"csi_rdi1_clk", 0},
|
||||
{"csi_rdi2_clk", 0},
|
||||
};
|
||||
static struct msm_cam_clk_info ispif_8974_clk_info[] = {
|
||||
{"camss_vfe_vfe_clk", -1},
|
||||
{"camss_csi_vfe_clk", -1},
|
||||
{"camss_vfe_vfe_clk1", -1},
|
||||
{"camss_csi_vfe_clk1", -1},
|
||||
};
|
||||
|
||||
static int msm_ispif_init(struct ispif_device *ispif,
|
||||
uint32_t csid_version)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (ispif->ispif_state == ISPIF_POWER_UP) {
|
||||
CDBG("%s: ispif already initted state = %d\n", __func__,
|
||||
ispif->ispif_state);
|
||||
rc = -EAGAIN;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* can we set to zero? */
|
||||
ispif->applied_intf_cmd[VFE0].intf_cmd = 0xFFFFFFFF;
|
||||
ispif->applied_intf_cmd[VFE0].intf_cmd1 = 0xFFFFFFFF;
|
||||
ispif->applied_intf_cmd[VFE1].intf_cmd = 0xFFFFFFFF;
|
||||
ispif->applied_intf_cmd[VFE1].intf_cmd1 = 0xFFFFFFFF;
|
||||
memset(ispif->sof_count, 0, sizeof(ispif->sof_count));
|
||||
|
||||
ispif->csid_version = csid_version;
|
||||
if (ispif->csid_version < CSID_VERSION_V2) {
|
||||
rc = msm_cam_clk_enable(&ispif->pdev->dev, ispif_8960_clk_info,
|
||||
ispif->ispif_clk, 2, 1);
|
||||
if (rc < 0) {
|
||||
pr_err("%s: cannot enable clock, error = %d\n",
|
||||
__func__, rc);
|
||||
goto end;
|
||||
}
|
||||
} else if (ispif->csid_version == CSID_VERSION_V2) {
|
||||
rc = msm_cam_clk_enable(&ispif->pdev->dev, ispif_8960_clk_info,
|
||||
ispif->ispif_clk, ARRAY_SIZE(ispif_8960_clk_info), 1);
|
||||
if (rc < 0) {
|
||||
pr_err("%s: cannot enable clock, error = %d\n",
|
||||
__func__, rc);
|
||||
goto end;
|
||||
}
|
||||
} else {
|
||||
rc = msm_cam_clk_enable(&ispif->pdev->dev, ispif_8974_clk_info,
|
||||
ispif->ispif_clk, ARRAY_SIZE(ispif_8974_clk_info), 1);
|
||||
if (rc < 0) {
|
||||
pr_err("%s: cannot enable clock, error = %d\n",
|
||||
__func__, rc);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
ispif->base = ioremap(ispif->mem->start,
|
||||
resource_size(ispif->mem));
|
||||
if (!ispif->base) {
|
||||
rc = -ENOMEM;
|
||||
pr_err("%s: nomem\n", __func__);
|
||||
goto error_clk;
|
||||
}
|
||||
rc = request_irq(ispif->irq->start, msm_io_ispif_irq,
|
||||
IRQF_TRIGGER_RISING, "ispif", ispif);
|
||||
init_completion(&ispif->reset_complete);
|
||||
if (rc < 0) {
|
||||
pr_err("%s: request_irq error = %d\n", __func__, rc);
|
||||
goto error_irq;
|
||||
}
|
||||
rc = msm_ispif_reset(ispif);
|
||||
if (rc == 0) {
|
||||
ispif->ispif_state = ISPIF_POWER_UP;
|
||||
CDBG("%s: power up done\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
free_irq(ispif->irq->start, ispif);
|
||||
error_irq:
|
||||
iounmap(ispif->base);
|
||||
error_clk:
|
||||
if (ispif->csid_version < CSID_VERSION_V2) {
|
||||
msm_cam_clk_enable(&ispif->pdev->dev, ispif_8960_clk_info,
|
||||
ispif->ispif_clk, 2, 0);
|
||||
} else if (ispif->csid_version == CSID_VERSION_V2) {
|
||||
msm_cam_clk_enable(&ispif->pdev->dev, ispif_8960_clk_info,
|
||||
ispif->ispif_clk, ARRAY_SIZE(ispif_8960_clk_info), 0);
|
||||
}
|
||||
end:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void msm_ispif_release(struct ispif_device *ispif)
|
||||
{
|
||||
if (ispif->ispif_state != ISPIF_POWER_UP) {
|
||||
pr_err("%s: ispif invalid state %d\n", __func__,
|
||||
ispif->ispif_state);
|
||||
return;
|
||||
}
|
||||
/* make sure no streaming going on */
|
||||
msm_ispif_reset(ispif);
|
||||
free_irq(ispif->irq->start, ispif);
|
||||
iounmap(ispif->base);
|
||||
if (ispif->csid_version < CSID_VERSION_V2) {
|
||||
msm_cam_clk_enable(&ispif->pdev->dev, ispif_8960_clk_info,
|
||||
ispif->ispif_clk, 2, 0);
|
||||
} else if (ispif->csid_version == CSID_VERSION_V2) {
|
||||
msm_cam_clk_enable(&ispif->pdev->dev, ispif_8960_clk_info,
|
||||
ispif->ispif_clk, ARRAY_SIZE(ispif_8960_clk_info), 0);
|
||||
}
|
||||
ispif->ispif_state = ISPIF_POWER_DOWN;
|
||||
}
|
||||
|
||||
static int msm_ispif_clk_enable(struct ispif_device *ispif,
|
||||
uint32_t csid_version, int enable)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (csid_version != CSID_VERSION_V3)
|
||||
goto end;
|
||||
rc = msm_cam_clk_enable(&ispif->pdev->dev, ispif_8974_clk_info,
|
||||
ispif->ispif_clk, ARRAY_SIZE(ispif_8974_clk_info), enable);
|
||||
if (rc < 0)
|
||||
pr_err("%s: cannot enable clock, error = %d\n", __func__, rc);
|
||||
end:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static long msm_ispif_cmd(struct v4l2_subdev *sd, void *arg)
|
||||
{
|
||||
long rc = 0;
|
||||
struct ispif_cfg_data *pcdata = (struct ispif_cfg_data *)arg;
|
||||
struct ispif_device *ispif =
|
||||
(struct ispif_device *)v4l2_get_subdevdata(sd);
|
||||
mutex_lock(&ispif->mutex);
|
||||
switch (pcdata->cfg_type) {
|
||||
case ISPIF_CLK_ENABLE:
|
||||
rc = msm_ispif_clk_enable(ispif, pcdata->csid_version, 1);
|
||||
break;
|
||||
case ISPIF_CLK_DISABLE:
|
||||
rc = msm_ispif_clk_enable(ispif, pcdata->csid_version, 0);
|
||||
break;
|
||||
case ISPIF_ENABLE_REG_DUMP:
|
||||
ispif->enb_dump_reg = pcdata->reg_dump; /* save dump config */
|
||||
break;
|
||||
case ISPIF_INIT:
|
||||
/* need to move back to CDBG */
|
||||
rc = msm_ispif_init(ispif, pcdata->csid_version);
|
||||
msm_ispif_io_dump_reg(ispif);
|
||||
break;
|
||||
case ISPIF_CFG:
|
||||
rc = msm_ispif_config(ispif, &pcdata->params);
|
||||
msm_ispif_io_dump_reg(ispif);
|
||||
break;
|
||||
case ISPIF_START_FRAME_BOUNDARY:
|
||||
rc = msm_ispif_start_frame_boundary(ispif, &pcdata->params);
|
||||
msm_ispif_io_dump_reg(ispif);
|
||||
break;
|
||||
case ISPIF_STOP_FRAME_BOUNDARY:
|
||||
rc = msm_ispif_stop_frame_boundary(ispif, &pcdata->params);
|
||||
msm_ispif_io_dump_reg(ispif);
|
||||
break;
|
||||
case ISPIF_STOP_IMMEDIATELY:
|
||||
rc = msm_ispif_stop_immediately(ispif, &pcdata->params);
|
||||
msm_ispif_io_dump_reg(ispif);
|
||||
break;
|
||||
case ISPIF_RELEASE:
|
||||
msm_ispif_release(ispif);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&ispif->mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static long msm_ispif_subdev_ioctl(struct v4l2_subdev *sd,
|
||||
unsigned int cmd, void *arg)
|
||||
{
|
||||
switch (cmd) {
|
||||
case VIDIOC_MSM_ISPIF_CFG:
|
||||
return msm_ispif_cmd(sd, arg);
|
||||
default:
|
||||
pr_err("%s: invalid cmd received\n", __func__);
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
}
|
||||
|
||||
static int ispif_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
|
||||
{
|
||||
struct ispif_device *ispif = v4l2_get_subdevdata(sd);
|
||||
int rc = 0;
|
||||
|
||||
mutex_lock(&ispif->mutex);
|
||||
if (ispif->open_cnt > 0) {
|
||||
CDBG("%s: dev already open\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
/* mem remap is done in init when the clock is on */
|
||||
ispif->open_cnt++;
|
||||
end:
|
||||
mutex_unlock(&ispif->mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int ispif_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
|
||||
{
|
||||
struct ispif_device *ispif = v4l2_get_subdevdata(sd);
|
||||
int rc = 0;
|
||||
|
||||
CDBG("%s\n", __func__);
|
||||
mutex_lock(&ispif->mutex);
|
||||
if (ispif->open_cnt == 0) {
|
||||
pr_err("Invalid close\n");
|
||||
rc = -ENODEV;
|
||||
goto end;
|
||||
}
|
||||
ispif->open_cnt--;
|
||||
if (ispif->open_cnt == 0)
|
||||
msm_ispif_release(ispif);
|
||||
end:
|
||||
mutex_unlock(&ispif->mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static struct v4l2_subdev_core_ops msm_ispif_subdev_core_ops = {
|
||||
.g_chip_ident = &msm_ispif_subdev_g_chip_ident,
|
||||
.ioctl = &msm_ispif_subdev_ioctl,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_ops msm_ispif_subdev_ops = {
|
||||
.core = &msm_ispif_subdev_core_ops,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_internal_ops msm_ispif_internal_ops = {
|
||||
.open = ispif_open_node,
|
||||
.close = ispif_close_node,
|
||||
};
|
||||
static int __devinit ispif_probe(struct platform_device *pdev)
|
||||
{
|
||||
int rc = 0;
|
||||
struct ispif_device *ispif;
|
||||
|
||||
CDBG("%s\n", __func__);
|
||||
ispif = kzalloc(sizeof(struct ispif_device), GFP_KERNEL);
|
||||
if (!ispif) {
|
||||
pr_err("%s: no enough memory\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
v4l2_subdev_init(&ispif->msm_sd.sd, &msm_ispif_subdev_ops);
|
||||
ispif->msm_sd.sd.internal_ops = &msm_ispif_internal_ops;
|
||||
ispif->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
|
||||
|
||||
snprintf(ispif->msm_sd.sd.name,
|
||||
ARRAY_SIZE(ispif->msm_sd.sd.name), "msm_ispif");
|
||||
v4l2_set_subdevdata(&ispif->msm_sd.sd, ispif);
|
||||
platform_set_drvdata(pdev, &ispif->msm_sd.sd);
|
||||
mutex_init(&ispif->mutex);
|
||||
ispif->pdev = pdev;
|
||||
media_entity_init(&ispif->msm_sd.sd.entity, 0, NULL, 0);
|
||||
ispif->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
|
||||
ispif->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_ISPIF;
|
||||
ispif->msm_sd.sd.entity.name = pdev->name;
|
||||
rc = msm_sd_register(&ispif->msm_sd);
|
||||
if (rc != 0) {
|
||||
pr_err("%s: msm_sd_register error = %d\n", __func__, rc);
|
||||
goto error;
|
||||
}
|
||||
if (pdev->dev.of_node)
|
||||
of_property_read_u32((&pdev->dev)->of_node,
|
||||
"cell-index", &pdev->id);
|
||||
|
||||
ispif->mem = platform_get_resource_byname(pdev,
|
||||
IORESOURCE_MEM, "ispif");
|
||||
if (!ispif->mem) {
|
||||
pr_err("%s: no mem resource?\n", __func__);
|
||||
rc = -ENODEV;
|
||||
goto error;
|
||||
}
|
||||
ispif->irq = platform_get_resource_byname(pdev,
|
||||
IORESOURCE_IRQ, "ispif");
|
||||
if (!ispif->irq) {
|
||||
pr_err("%s: no irq resource?\n", __func__);
|
||||
rc = -ENODEV;
|
||||
goto error;
|
||||
}
|
||||
ispif->io = request_mem_region(ispif->mem->start,
|
||||
resource_size(ispif->mem), pdev->name);
|
||||
if (!ispif->io) {
|
||||
pr_err("%s: no valid mem region\n", __func__);
|
||||
rc = -EBUSY;
|
||||
goto error;
|
||||
}
|
||||
ispif->pdev = pdev;
|
||||
ispif->ispif_state = ISPIF_POWER_DOWN;
|
||||
ispif->open_cnt = 0;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
mutex_destroy(&ispif->mutex);
|
||||
kfree(ispif);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static const struct of_device_id msm_ispif_dt_match[] = {
|
||||
{.compatible = "qcom,ispif"},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, msm_ispif_dt_match);
|
||||
|
||||
static struct platform_driver ispif_driver = {
|
||||
.probe = ispif_probe,
|
||||
.driver = {
|
||||
.name = MSM_ISPIF_DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = msm_ispif_dt_match,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init msm_ispif_init_module(void)
|
||||
{
|
||||
return platform_driver_register(&ispif_driver);
|
||||
}
|
||||
|
||||
static void __exit msm_ispif_exit_module(void)
|
||||
{
|
||||
platform_driver_unregister(&ispif_driver);
|
||||
}
|
||||
|
||||
module_init(msm_ispif_init_module);
|
||||
module_exit(msm_ispif_exit_module);
|
||||
MODULE_DESCRIPTION("MSM ISP Interface driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
59
drivers/media/video/msmb/ispif/msm_ispif.h
Normal file
59
drivers/media/video/msmb/ispif/msm_ispif.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/* Copyright (c) 2013, 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"
|
||||
|
||||
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 *irq;
|
||||
struct resource *io;
|
||||
void __iomem *base;
|
||||
struct mutex mutex;
|
||||
uint8_t start_ack_pending;
|
||||
struct completion reset_complete;
|
||||
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 clk *ispif_clk[INTF_MAX];
|
||||
};
|
||||
#endif
|
||||
102
drivers/media/video/msmb/ispif/msm_ispif_hwreg.h
Normal file
102
drivers/media/video/msmb/ispif/msm_ispif_hwreg.h
Normal file
@@ -0,0 +1,102 @@
|
||||
/* Copyright (c) 2013, 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_HWREG_H
|
||||
#define MSM_ISPIF_HWREG_H
|
||||
|
||||
|
||||
/* ISPIF registers */
|
||||
|
||||
#define ISPIF_RST_CMD_ADDR 0x08
|
||||
#define ISPIF_RST_CMD_1_ADDR 0x0C
|
||||
#define ISPIF_INTF_CMD_ADDR 0x248
|
||||
#define ISPIF_INTF_CMD_1_ADDR 0x24C
|
||||
#define ISPIF_CTRL_ADDR 0x08
|
||||
#define ISPIF_INPUT_SEL_ADDR 0x244
|
||||
#define ISPIF_PIX_0_INTF_CID_MASK_ADDR 0x254
|
||||
#define ISPIF_RDI_0_INTF_CID_MASK_ADDR 0x264
|
||||
#define ISPIF_PIX_1_INTF_CID_MASK_ADDR 0x258
|
||||
#define ISPIF_RDI_1_INTF_CID_MASK_ADDR 0x268
|
||||
#define ISPIF_RDI_2_INTF_CID_MASK_ADDR 0x26C
|
||||
#define ISPIF_PIX_0_STATUS_ADDR 0x2C0
|
||||
#define ISPIF_RDI_0_STATUS_ADDR 0x2D0
|
||||
#define ISPIF_PIX_1_STATUS_ADDR 0x2C4
|
||||
#define ISPIF_RDI_1_STATUS_ADDR 0x2D4
|
||||
#define ISPIF_RDI_2_STATUS_ADDR 0x2D8
|
||||
#define ISPIF_IRQ_MASK_ADDR 0x208
|
||||
#define ISPIF_IRQ_CLEAR_ADDR 0x230
|
||||
#define ISPIF_IRQ_STATUS_ADDR 0x21C
|
||||
#define ISPIF_IRQ_MASK_1_ADDR 0x20C
|
||||
#define ISPIF_IRQ_CLEAR_1_ADDR 0x234
|
||||
#define ISPIF_IRQ_STATUS_1_ADDR 0x220
|
||||
#define ISPIF_IRQ_MASK_2_ADDR 0x210
|
||||
#define ISPIF_IRQ_CLEAR_2_ADDR 0x238
|
||||
#define ISPIF_IRQ_STATUS_2_ADDR 0x224
|
||||
#define ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR 0x1C
|
||||
|
||||
/* new */
|
||||
#define ISPIF_VFE_m_CTRL_0_ADDR 0x200
|
||||
#define ISPIF_VFE_m_IRQ_MASK_0 0x208
|
||||
#define ISPIF_VFE_m_IRQ_MASK_1 0x20C
|
||||
#define ISPIF_VFE_m_IRQ_MASK_2 0x210
|
||||
#define ISPIF_VFE_m_IRQ_STATUS_0 0x21C
|
||||
#define ISPIF_VFE_m_IRQ_STATUS_1 0x220
|
||||
#define ISPIF_VFE_m_IRQ_STATUS_2 0x224
|
||||
#define ISPIF_VFE_m_IRQ_CLEAR_0 0x230
|
||||
#define ISPIF_VFE_m_IRQ_CLEAR_1 0x234
|
||||
#define ISPIF_VFE_m_IRQ_CLEAR_2 0x238
|
||||
|
||||
/*ISPIF RESET BITS*/
|
||||
|
||||
#define VFE_CLK_DOMAIN_RST 31
|
||||
#define RDI_CLK_DOMAIN_RST 26
|
||||
#define RDI_1_CLK_DOMAIN_RST 27
|
||||
#define RDI_2_CLK_DOMAIN_RST 28
|
||||
#define PIX_CLK_DOMAIN_RST 29
|
||||
#define PIX_1_CLK_DOMAIN_RST 30
|
||||
#define AHB_CLK_DOMAIN_RST 25
|
||||
#define RDI_2_VFE_RST_STB 12
|
||||
#define RDI_2_CSID_RST_STB 11
|
||||
#define RDI_1_VFE_RST_STB 10
|
||||
#define RDI_1_CSID_RST_STB 9
|
||||
#define RDI_0_VFE_RST_STB 8
|
||||
#define RDI_0_CSID_RST_STB 7
|
||||
#define PIX_1_VFE_RST_STB 6
|
||||
#define PIX_1_CSID_RST_STB 5
|
||||
#define PIX_0_VFE_RST_STB 4
|
||||
#define PIX_0_CSID_RST_STB 3
|
||||
#define SW_REG_RST_STB 2
|
||||
#define MISC_LOGIC_RST_STB 1
|
||||
#define STROBED_RST_EN 0
|
||||
|
||||
#define ISPIF_RST_CMD_MASK 0xFE0F1FFF
|
||||
#define ISPIF_RST_CMD_1_MASK 0xFC0F1FF9
|
||||
|
||||
#define PIX_INTF_0_OVERFLOW_IRQ 12
|
||||
#define RAW_INTF_0_OVERFLOW_IRQ 25
|
||||
#define RAW_INTF_1_OVERFLOW_IRQ 25
|
||||
#define RAW_INTF_2_OVERFLOW_IRQ 12
|
||||
#define RESET_DONE_IRQ 27
|
||||
|
||||
#define ISPIF_IRQ_STATUS_MASK 0x0A493249
|
||||
#define ISPIF_IRQ_STATUS_1_MASK 0x02493249
|
||||
#define ISPIF_IRQ_STATUS_2_MASK 0x00001249
|
||||
|
||||
#define ISPIF_IRQ_STATUS_PIX_SOF_MASK 0x249
|
||||
#define ISPIF_IRQ_STATUS_RDI0_SOF_MASK 0x492000
|
||||
#define ISPIF_IRQ_STATUS_RDI1_SOF_MASK 0x492000
|
||||
#define ISPIF_IRQ_STATUS_RDI2_SOF_MASK 0x249
|
||||
|
||||
#define ISPIF_IRQ_STATUS_SOF_MASK 0x492249
|
||||
#define ISPIF_IRQ_GLOBAL_CLEAR_CMD 0x1
|
||||
|
||||
#endif
|
||||
@@ -9,3 +9,5 @@ header-y += msm_mercury.h
|
||||
header-y += msm_media_info.h
|
||||
header-y += msmb_camera.h
|
||||
header-y += msm_cam_sensor.h
|
||||
header-y += msmb_isp.h
|
||||
header-y += msmb_ispif.h
|
||||
|
||||
320
include/media/msmb_isp.h
Normal file
320
include/media/msmb_isp.h
Normal file
@@ -0,0 +1,320 @@
|
||||
#ifndef __MSMB_ISP__
|
||||
#define __MSMB_ISP__
|
||||
|
||||
#include <linux/videodev2.h>
|
||||
|
||||
#define MAX_PLANES_PER_STREAM 3
|
||||
#define MAX_NUM_STREAM 7
|
||||
|
||||
#define ISP_VERSION_40 40
|
||||
#define ISP_VERSION_32 32
|
||||
|
||||
|
||||
enum ISP_START_PIXEL_PATTERN {
|
||||
ISP_BAYER_RGRGRG,
|
||||
ISP_BAYER_GRGRGR,
|
||||
ISP_BAYER_BGBGBG,
|
||||
ISP_BAYER_GBGBGB,
|
||||
ISP_YUV_YCbYCr,
|
||||
ISP_YUV_YCrYCb,
|
||||
ISP_YUV_CbYCrY,
|
||||
ISP_YUV_CrYCbY,
|
||||
ISP_PIX_PATTERN_MAX
|
||||
};
|
||||
|
||||
enum msm_vfe_plane_fmt {
|
||||
Y_PLANE,
|
||||
CB_PLANE,
|
||||
CR_PLANE,
|
||||
CRCB_PLANE,
|
||||
CBCR_PLANE,
|
||||
VFE_PLANE_FMT_MAX
|
||||
};
|
||||
|
||||
enum msm_vfe_input_src {
|
||||
VFE_PIX_0,
|
||||
VFE_RAW_0,
|
||||
VFE_RAW_1,
|
||||
VFE_RAW_2,
|
||||
VFE_SRC_MAX,
|
||||
};
|
||||
|
||||
enum msm_vfe_axi_stream_src {
|
||||
PIX_ENCODER,
|
||||
PIX_VIEWFINDER,
|
||||
CAMIF_RAW,
|
||||
IDEAL_RAW,
|
||||
RDI,
|
||||
VFE_AXI_SRC_MAX
|
||||
};
|
||||
|
||||
enum msm_vfe_frame_skip_pattern {
|
||||
NO_SKIP,
|
||||
EVERY_2FRAME,
|
||||
EVERY_4FRAME,
|
||||
EVERY_8FRAME,
|
||||
EVERY_16FRAME,
|
||||
EVERY_32FRAME,
|
||||
MAX_SKIP,
|
||||
};
|
||||
|
||||
enum msm_vfe_camif_input {
|
||||
CAMIF_DISABLED,
|
||||
CAMIF_PAD_REG_INPUT,
|
||||
CAMIF_MIDDI_INPUT,
|
||||
CAMIF_MIPI_INPUT,
|
||||
};
|
||||
|
||||
struct msm_vfe_camif_cfg {
|
||||
uint32_t lines_per_frame;
|
||||
uint32_t pixels_per_line;
|
||||
uint32_t first_pixel;
|
||||
uint32_t last_pixel;
|
||||
uint32_t first_line;
|
||||
uint32_t last_line;
|
||||
uint32_t epoch_line0;
|
||||
uint32_t epoch_line1;
|
||||
enum msm_vfe_camif_input camif_input;
|
||||
};
|
||||
|
||||
enum msm_vfe_inputmux {
|
||||
CAMIF,
|
||||
TESTGEN,
|
||||
EXTERNAL_READ,
|
||||
};
|
||||
|
||||
struct msm_vfe_pix_cfg {
|
||||
struct msm_vfe_camif_cfg camif_cfg;
|
||||
enum msm_vfe_inputmux input_mux;
|
||||
enum ISP_START_PIXEL_PATTERN pixel_pattern;
|
||||
};
|
||||
|
||||
struct msm_vfe_input_cfg {
|
||||
union {
|
||||
struct msm_vfe_pix_cfg pix_cfg;
|
||||
} d;
|
||||
enum msm_vfe_input_src input_src;
|
||||
|
||||
};
|
||||
|
||||
struct msm_vfe_axi_plane_cfg {
|
||||
uint32_t output_width; /*Include padding*/
|
||||
uint32_t output_height;
|
||||
uint32_t output_stride;
|
||||
uint32_t output_scan_lines;
|
||||
uint32_t output_plane_format; /*Y/Cb/Cr/CbCr*/
|
||||
|
||||
uint8_t csid_src; /*RDI 0-2*/
|
||||
uint8_t rdi_cid;/*CID 1-16*/
|
||||
};
|
||||
|
||||
struct msm_vfe_axi_stream_request_cmd {
|
||||
uint32_t session_id;
|
||||
uint32_t stream_id;
|
||||
uint32_t output_format;/*Planar/RAW/Misc*/
|
||||
enum msm_vfe_axi_stream_src stream_src; /*CAMIF/IDEAL/RDIs*/
|
||||
struct msm_vfe_axi_plane_cfg plane_cfg[MAX_PLANES_PER_STREAM];
|
||||
|
||||
uint32_t burst_count;
|
||||
uint32_t hfr_mode;
|
||||
uint8_t frame_base;
|
||||
|
||||
uint32_t init_frame_drop; /*MAX 31 Frames*/
|
||||
enum msm_vfe_frame_skip_pattern frame_skip_pattern;
|
||||
uint8_t buf_divert; /* if TRUE no vb2 buf done. */
|
||||
/*Return values*/
|
||||
uint32_t axi_stream_handle;
|
||||
};
|
||||
|
||||
struct msm_vfe_axi_stream_release_cmd {
|
||||
uint32_t stream_handle;
|
||||
};
|
||||
|
||||
enum msm_vfe_axi_stream_cmd {
|
||||
STOP_STREAM,
|
||||
START_STREAM,
|
||||
};
|
||||
|
||||
struct msm_vfe_axi_stream_cfg_cmd {
|
||||
uint8_t num_streams;
|
||||
uint32_t stream_handle[MAX_NUM_STREAM];
|
||||
enum msm_vfe_axi_stream_cmd cmd;
|
||||
};
|
||||
|
||||
enum msm_isp_stats_type {
|
||||
MSM_ISP_STATS_AEC, /* legacy based AEC */
|
||||
MSM_ISP_STATS_AF, /* legacy based AF */
|
||||
MSM_ISP_STATS_AWB, /* legacy based AWB */
|
||||
MSM_ISP_STATS_RS, /* legacy based RS */
|
||||
MSM_ISP_STATS_CS, /* legacy based CS */
|
||||
MSM_ISP_STATS_IHIST, /* legacy based HIST */
|
||||
MSM_ISP_STATS_SKIN, /* legacy based SKIN */
|
||||
MSM_ISP_STATS_BG, /* Bayer Grids */
|
||||
MSM_ISP_STATS_BF, /* Bayer Focus */
|
||||
MSM_ISP_STATS_BE, /* Bayer Exposure*/
|
||||
MSM_ISP_STATS_BHIST, /* Bayer Hist */
|
||||
MSM_ISP_STATS_MAX /* MAX */
|
||||
};
|
||||
|
||||
struct msm_vfe_stats_stream_request_cmd {
|
||||
uint32_t session_id;
|
||||
uint32_t stream_id;
|
||||
enum msm_isp_stats_type stats_type;
|
||||
uint32_t stream_handle;
|
||||
};
|
||||
struct msm_vfe_stats_stream_release_cmd {
|
||||
uint32_t stream_handle;
|
||||
};
|
||||
struct msm_vfe_stats_stream_cfg_cmd {
|
||||
uint8_t num_streams;
|
||||
uint32_t stream_handle[MSM_ISP_STATS_MAX];
|
||||
uint8_t enable;
|
||||
};
|
||||
enum msm_vfe_reg_cfg_type {
|
||||
VFE_WRITE,
|
||||
VFE_WRITE_MB,
|
||||
VFE_READ,
|
||||
VFE_WRITE_MASK,
|
||||
VFE_CLEAR_MASK,
|
||||
VFE_WRITE_AUTO_INCREMENT,
|
||||
};
|
||||
|
||||
struct msm_vfe_cfg_cmd2 {
|
||||
uint16_t num_cfg;
|
||||
uint16_t cmd_len;
|
||||
void __user *cfg_data;
|
||||
void __user *cfg_cmd;
|
||||
};
|
||||
|
||||
struct msm_vfe_reg_cfg_cmd {
|
||||
uint32_t reg_offset;
|
||||
uint32_t cmd_data;
|
||||
uint32_t len;
|
||||
enum msm_vfe_reg_cfg_type cmd_type;
|
||||
};
|
||||
|
||||
struct msm_isp_buf_request {
|
||||
uint32_t session_id;
|
||||
uint32_t stream_id;
|
||||
uint8_t num_buf;
|
||||
uint32_t handle;
|
||||
};
|
||||
|
||||
struct msm_isp_qbuf_info {
|
||||
uint32_t handle;
|
||||
int buf_idx;
|
||||
/*Only used for prepare buffer*/
|
||||
struct v4l2_buffer buffer;
|
||||
};
|
||||
|
||||
struct msm_vfe_axi_src_state {
|
||||
enum msm_vfe_input_src input_src;
|
||||
uint32_t src_active;
|
||||
};
|
||||
|
||||
enum msm_isp_event_idx {
|
||||
ISP_REG_UPDATE = 0,
|
||||
ISP_START_ACK = 1,
|
||||
ISP_STOP_ACK = 2,
|
||||
ISP_IRQ_VIOLATION = 3,
|
||||
ISP_WM_BUS_OVERFLOW = 4,
|
||||
ISP_STATS_OVERFLOW = 5,
|
||||
ISP_CAMIF_ERROR = 6,
|
||||
ISP_STATS_NOTIFY = 7,
|
||||
ISP_SOF = 8,
|
||||
ISP_EOF = 9,
|
||||
ISP_BUF_DIVERT = 10,
|
||||
ISP_EVENT_MAX = 11
|
||||
};
|
||||
|
||||
#define ISP_EVENT_BASE (V4L2_EVENT_PRIVATE_START + 1)
|
||||
#define ISP_EVENT_REG_UPDATE (ISP_EVENT_BASE + ISP_REG_UPDATE)
|
||||
#define ISP_EVENT_START_ACK (ISP_EVENT_BASE + ISP_START_ACK)
|
||||
#define ISP_EVENT_STOP_ACK (ISP_EVENT_BASE + ISP_STOP_ACK)
|
||||
#define ISP_EVENT_IRQ_VIOLATION (ISP_EVENT_BASE + ISP_IRQ_VIOLATION)
|
||||
#define ISP_EVENT_WM_BUS_OVERFLOW (ISP_EVENT_BASE + ISP_WM_BUS_OVERFLOW)
|
||||
#define ISP_EVENT_STATS_OVERFLOW (ISP_EVENT_BASE + ISP_STATS_OVERFLOW)
|
||||
#define ISP_EVENT_CAMIF_ERROR (ISP_EVENT_BASE + ISP_CAMIF_ERROR)
|
||||
#define ISP_EVENT_STATS_NOTIFY (ISP_EVENT_BASE + ISP_STATS_NOTIFY)
|
||||
#define ISP_EVENT_SOF (ISP_EVENT_BASE + ISP_SOF)
|
||||
#define ISP_EVENT_EOF (ISP_EVENT_BASE + ISP_EOF)
|
||||
#define ISP_EVENT_BUF_DIVERT (ISP_EVENT_BASE + ISP_BUF_DIVERT)
|
||||
|
||||
|
||||
/* The msm_v4l2_event_data structure should match the
|
||||
* v4l2_event.u.data field.
|
||||
* should not exceed 64 bytes */
|
||||
|
||||
struct msm_isp_buf_event {
|
||||
uint32_t session_id;
|
||||
uint32_t stream_id;
|
||||
uint32_t handle;
|
||||
int8_t buf_idx;
|
||||
};
|
||||
struct msm_isp_stats_event {
|
||||
uint32_t stats_mask; /* 4 bytes */
|
||||
uint8_t stats_buf_idxs[MSM_ISP_STATS_MAX]; /* 11 bytes */
|
||||
};
|
||||
|
||||
struct msm_isp_stream_ack {
|
||||
uint32_t session_id;
|
||||
uint32_t stream_id;
|
||||
uint32_t handle;
|
||||
};
|
||||
|
||||
struct msm_isp_event_data {
|
||||
struct timeval timestamp;
|
||||
/* if pix is a src frame_id is from camif */
|
||||
uint32_t frame_id;
|
||||
union {
|
||||
/* START_ACK, STOP_ACK */
|
||||
struct msm_isp_stream_ack stream_ack;
|
||||
/* REG_UPDATE_TRIGGER, bus over flow */
|
||||
enum msm_vfe_input_src input_src;
|
||||
/* stats notify */
|
||||
struct msm_isp_stats_event stats;
|
||||
/* IRQ_VIOLATION, STATS_OVER_FLOW, WM_OVER_FLOW */
|
||||
uint32_t irq_status_mask;
|
||||
struct msm_isp_buf_event buf_done;
|
||||
} u; /* union can have max 52 bytes */
|
||||
};
|
||||
|
||||
#define VIDIOC_MSM_VFE_REG_CFG \
|
||||
_IOWR('V', BASE_VIDIOC_PRIVATE, struct msm_vfe_cfg_cmd2)
|
||||
|
||||
#define VIDIOC_MSM_ISP_REQUEST_BUF \
|
||||
_IOWR('V', BASE_VIDIOC_PRIVATE+1, struct msm_isp_buf_request)
|
||||
|
||||
#define VIDIOC_MSM_ISP_ENQUEUE_BUF \
|
||||
_IOWR('V', BASE_VIDIOC_PRIVATE+2, struct msm_isp_qbuf_info)
|
||||
|
||||
#define VIDIOC_MSM_ISP_RELEASE_BUF \
|
||||
_IOWR('V', BASE_VIDIOC_PRIVATE+3, struct msm_isp_buf_request)
|
||||
|
||||
#define VIDIOC_MSM_ISP_REQUEST_STREAM \
|
||||
_IOWR('V', BASE_VIDIOC_PRIVATE+4, struct msm_vfe_axi_stream_request_cmd)
|
||||
|
||||
#define VIDIOC_MSM_ISP_CFG_STREAM \
|
||||
_IOWR('V', BASE_VIDIOC_PRIVATE+5, struct msm_vfe_axi_stream_cfg_cmd)
|
||||
|
||||
#define VIDIOC_MSM_ISP_RELEASE_STREAM \
|
||||
_IOWR('V', BASE_VIDIOC_PRIVATE+6, struct msm_vfe_axi_stream_release_cmd)
|
||||
|
||||
#define VIDIOC_MSM_ISP_INPUT_CFG \
|
||||
_IOWR('V', BASE_VIDIOC_PRIVATE+7, struct msm_vfe_input_cfg)
|
||||
|
||||
#define VIDIOC_MSM_ISP_SET_SRC_STATE \
|
||||
_IOWR('V', BASE_VIDIOC_PRIVATE+8, struct msm_vfe_axi_src_state)
|
||||
|
||||
#define VIDIOC_MSM_ISP_REQUEST_STATS_STREAM \
|
||||
_IOWR('V', BASE_VIDIOC_PRIVATE+9, \
|
||||
struct msm_vfe_stats_stream_request_cmd)
|
||||
|
||||
#define VIDIOC_MSM_ISP_CFG_STATS_STREAM \
|
||||
_IOWR('V', BASE_VIDIOC_PRIVATE+10, struct msm_vfe_stats_stream_cfg_cmd)
|
||||
|
||||
#define VIDIOC_MSM_ISP_RELEASE_STATS_STREAM \
|
||||
_IOWR('V', BASE_VIDIOC_PRIVATE+11, \
|
||||
struct msm_vfe_stats_stream_release_cmd)
|
||||
|
||||
#endif /* __MSMB_ISP__ */
|
||||
103
include/media/msmb_ispif.h
Normal file
103
include/media/msmb_ispif.h
Normal file
@@ -0,0 +1,103 @@
|
||||
#ifndef MSM_CAM_ISPIF_H
|
||||
#define MSM_CAM_ISPIF_H
|
||||
|
||||
#define CSID_VERSION_V2 0x02000011
|
||||
#define CSID_VERSION_V3 0x30000000
|
||||
|
||||
enum msm_ispif_vfe_intf {
|
||||
VFE0,
|
||||
VFE1,
|
||||
VFE_MAX
|
||||
};
|
||||
#define VFE0_MASK (1 << VFE0)
|
||||
#define VFE1_MASK (1 << VFE1)
|
||||
|
||||
enum msm_ispif_intftype {
|
||||
PIX0,
|
||||
RDI0,
|
||||
PIX1,
|
||||
RDI1,
|
||||
RDI2,
|
||||
INTF_MAX
|
||||
};
|
||||
#define PIX0_MASK (1 << PIX0)
|
||||
#define PIX1_MASK (1 << PIX1)
|
||||
#define RDI0_MASK (1 << RDI0)
|
||||
#define RDI1_MASK (1 << RDI1)
|
||||
#define RDI2_MASK (1 << RDI2)
|
||||
|
||||
|
||||
enum msm_ispif_vc {
|
||||
VC0,
|
||||
VC1,
|
||||
VC2,
|
||||
VC3,
|
||||
VC_MAX
|
||||
};
|
||||
|
||||
enum msm_ispif_cid {
|
||||
CID0,
|
||||
CID1,
|
||||
CID2,
|
||||
CID3,
|
||||
CID4,
|
||||
CID5,
|
||||
CID6,
|
||||
CID7,
|
||||
CID8,
|
||||
CID9,
|
||||
CID10,
|
||||
CID11,
|
||||
CID12,
|
||||
CID13,
|
||||
CID14,
|
||||
CID15,
|
||||
CID_MAX
|
||||
};
|
||||
|
||||
enum msm_ispif_csid {
|
||||
CSID0,
|
||||
CSID1,
|
||||
CSID2,
|
||||
CSID3,
|
||||
CSID_MAX
|
||||
};
|
||||
|
||||
struct msm_ispif_params_entry {
|
||||
enum msm_ispif_intftype intftype;
|
||||
int num_cids;
|
||||
enum msm_ispif_cid cids[3];
|
||||
enum msm_ispif_csid csid;
|
||||
};
|
||||
|
||||
struct msm_ispif_param_data {
|
||||
enum msm_ispif_vfe_intf vfe_intf;
|
||||
uint32_t num;
|
||||
struct msm_ispif_params_entry entries[INTF_MAX];
|
||||
};
|
||||
|
||||
enum ispif_cfg_type_t {
|
||||
ISPIF_CLK_ENABLE,
|
||||
ISPIF_CLK_DISABLE,
|
||||
ISPIF_INIT,
|
||||
ISPIF_CFG,
|
||||
ISPIF_START_FRAME_BOUNDARY,
|
||||
ISPIF_STOP_FRAME_BOUNDARY,
|
||||
ISPIF_STOP_IMMEDIATELY,
|
||||
ISPIF_RELEASE,
|
||||
ISPIF_ENABLE_REG_DUMP,
|
||||
};
|
||||
|
||||
struct ispif_cfg_data {
|
||||
enum ispif_cfg_type_t cfg_type;
|
||||
union {
|
||||
int reg_dump; /* ISPIF_ENABLE_REG_DUMP */
|
||||
uint32_t csid_version; /* ISPIF_INIT */
|
||||
struct msm_ispif_param_data params; /* CFG, START, STOP */
|
||||
};
|
||||
};
|
||||
|
||||
#define VIDIOC_MSM_ISPIF_CFG \
|
||||
_IOWR('V', BASE_VIDIOC_PRIVATE, struct ispif_cfg_data)
|
||||
|
||||
#endif /* MSM_CAM_ISPIF_H */
|
||||
Reference in New Issue
Block a user