Merge "msm: ais: Security fixes for ispif and cpp"

This commit is contained in:
Linux Build Service Account 2017-05-25 15:51:44 -07:00 committed by Gerrit - the friendly Code Review server
commit 8d140659e0
156 changed files with 70345 additions and 9 deletions

View file

@ -14,8 +14,8 @@ Required properties:
[Second level nodes]
Required properties:
- compatible : one of:
- "qcom,msm-cam-smmu-cb"
- "qcom,qsmmu-cam-cb"
- "qcom,msm-cam-smmu-cb" : For arm smmu iommu type.
- "qcom,qsmmu-cam-cb" : For qsmmu iommu type.
- iommus : Handle parsed by smmu driver. Number of entries will vary
across targets.
- label - string describing iommu domain usage.
@ -23,6 +23,7 @@ Required properties:
Optional properties:
- qcom,scratch-buf-support : Enables iommu scratch buffer support in
that context bank.
- qcom,secure-context : boolean type, to set the context domain type as secure.
Example:
qcom,cam_smmu@0 {

View file

@ -27,6 +27,17 @@ obj-$(CONFIG_VIDEO_ADV7343) += adv7343.o
obj-$(CONFIG_VIDEO_ADV7393) += adv7393.o
obj-$(CONFIG_VIDEO_ADV7604) += adv7604.o
obj-$(CONFIG_VIDEO_ADV7842) += adv7842.o
ifeq ($(CONFIG_MSM_AIS),y)
ccflags-y += -Idrivers/media/platform/msm/ais
ccflags-y += -Idrivers/media/platform/msm/ais/common
ccflags-y += -Idrivers/media/platform/msm/ais/sensor/io
ccflags-y += -Idrivers/media/platform/msm/ais/sensor/cci
else
ccflags-y += -Idrivers/media/platform/msm/camera_v2
ccflags-y += -Idrivers/media/platform/msm/camera_v2/common
ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/cci
endif
obj-$(CONFIG_VIDEO_ADV7481) += adv7481.o
obj-$(CONFIG_VIDEO_AD9389B) += ad9389b.o
obj-$(CONFIG_VIDEO_ADV7511) += adv7511.o

View file

@ -2,35 +2,35 @@
# MSM camera configuration
#
comment "Qualcomm MSM Camera And Video"
comment "QTI MSM Camera And Video & AIS"
menuconfig MSM_CAMERA
bool "Qualcomm MSM camera and video capture support"
bool "QTI MSM camera and video capture support"
depends on ARCH_QCOM && VIDEO_V4L2 && I2C
---help---
Say Y here to enable selecting the video adapters for
Qualcomm msm camera and video capture drivers. enabling this
QTI msm camera and video capture drivers. enabling this
adds support for the camera driver stack including sensor, isp
and postprocessing drivers for legacy chipsets.
config MSM_CAMERA_DEBUG
bool "Qualcomm MSM camera debugging with printk"
bool "QTI MSM camera debugging with printk"
depends on MSM_CAMERA
default n
---help---
Enable printk() debug for msm camera
menuconfig MSMB_CAMERA
bool "Qualcomm MSM camera and video capture 2.0 support"
bool "QTI MSM camera and video capture 2.0 support"
depends on ARCH_QCOM && VIDEO_V4L2 && I2C
---help---
Say Y here to enable selecting the video adapters for
Qualcomm msm camera and video capture 2.0, enabling this
QTI msm camera and video capture 2.0, enabling this
adds support for the camera driver stack including sensor, isp
and postprocessing drivers.
config MSMB_CAMERA_DEBUG
bool "Qualcomm MSM camera 2.0 debugging with printk"
bool "QTI MSM camera 2.0 debugging with printk"
depends on MSMB_CAMERA
---help---
Enable printk() debug for msm camera 2.0
@ -41,5 +41,6 @@ endif # MSMB_CAMERA
source "drivers/media/platform/msm/vidc/Kconfig"
source "drivers/media/platform/msm/sde/Kconfig"
source "drivers/media/platform/msm/ais/Kconfig"
source "drivers/media/platform/msm/dvb/Kconfig"
source "drivers/media/platform/msm/broadcast/Kconfig"

View file

@ -7,3 +7,4 @@ obj-$(CONFIG_MSM_VIDC_V4L2) += vidc/
obj-y += sde/
obj-y += broadcast/
obj-$(CONFIG_DVB_MPQ) += dvb/
obj-$(CONFIG_MSM_AIS) += ais/

View file

@ -0,0 +1,85 @@
menuconfig MSM_AIS
bool "QTI MSM Automotive Imaging Subsystem"
depends on ARCH_QCOM && VIDEO_V4L2 && I2C
---help---
Say Y here to enable msm AIS
config MSM_AIS_DEBUG
bool "QTI MSM AIS debugging with printk"
depends on MSM_AIS
default n
---help---
Enable printk() debug for msm AIS.
Enabling ais debug will affect performance.
This feature is only applicable to
Automotive platforms.
config MSM_AIS_CAMERA_SENSOR
bool "QTI MSM camera sensor support"
depends on MSM_AIS
select NEW_LEDS
select LEDS_CLASS
---help---
This flag enables support for Camera Sensor.
The sensor driver is capable of providing real time
data for camera support. The driver support V4L2
subdev APIs.
config MSM_AIS_CPP
bool "QTI MSM Camera Post Processing Engine support"
depends on MSM_AIS
---help---
Enable support for Camera Post-processing Engine
The Post processing engine is capable of scaling
and cropping image. The driver support V4L2 subdev
APIs.
config MSM_AIS_EEPROM
bool "QTI MSM Camera ROM Interface for Calibration support"
depends on MSM_AIS
---help---
Enable support for ROM Interface for Calibration
Provides interface for reading the Calibration data
and also provides support for writing data in case of FLASH ROM.
Currently supports I2C, CCI and SPI protocol
config MSM_AIS_JPEG
bool "QTI MSM Jpeg Encoder Engine support"
depends on MSM_AIS
---help---
Enable support for Jpeg Encoder/Decoder
Engine for 8974.
This module serves as the common driver
for the JPEG 1.0 encoder and decoder.
config MSM_AIS_FD
bool "QTI MSM FD face detection engine support"
depends on MSM_AIS
---help---
Enables support for the MSM FD face detection engine.
MSM Face Detection library
enables the Face detection
hardware block.
config MSM_AIS_JPEGDMA
bool "QTI MSM Jpeg dma"
depends on MSM_AIS
select V4L2_MEM2MEM_DEV
---help---
Enable support for Jpeg dma engine.
The jpeg DMA engine is a hardware enabled
jpeg decode.
This feature is currently not supported on
Automotive platforms.
config MSM_AIS_SEC_CCI_TA_NAME
string "Name of TA to handle Secure CCI transactions"
depends on MSM_AIS_CCI
default "seccamdemo64"
config MSM_AIS_SEC_CCI_DEBUG
bool "QTI MSM Secure CCI Relay Debug"
depends on MSM_AIS_CCI
---help---
Enables simulation of secure camera for Secure CCI Realy
debugging.

View file

@ -0,0 +1,24 @@
ccflags-y += -Idrivers/media/platform/msm/ais
ccflags-y += -Idrivers/media/platform/msm/ais/sensor
ccflags-y += -Idrivers/media/platform/msm/ais/codecs
ccflags-y += -Idrivers/media/platform/msm/ais/isps
ccflags-y += -Idrivers/media/platform/msm/ais/pproc
ccflags-y += -Idrivers/media/platform/msm/ais/msm_vb2
ccflags-y += -Idrivers/media/platform/msm/ais/camera
ccflags-y += -Idrivers/media/platform/msm/ais/jpeg_10
ccflags-y += -Idrivers/media/platform/msm/ais/jpeg_dma
ccflags-y += -Idrivers/media/platform/msm/ais/fd
ccflags-y += -Idrivers/media/platform/msm/ais/common
obj-$(CONFIG_MSM_AIS) += common/
obj-$(CONFIG_MSM_AIS) += msm.o
obj-$(CONFIG_MSM_AIS) += camera/
obj-$(CONFIG_MSM_AIS) += msm_vb2/
obj-$(CONFIG_MSM_AIS) += sensor/
obj-$(CONFIG_MSM_AIS) += pproc/
obj-$(CONFIG_MSM_AIS) += isp/
obj-$(CONFIG_MSM_AIS) += ispif/
obj-$(CONFIG_MSM_AIS_JPEG) += jpeg_10/
obj-$(CONFIG_MSM_AIS_JPEGDMA) += jpeg_dma/
obj-$(CONFIG_MSM_AIS) += msm_buf_mgr/
obj-$(CONFIG_MSM_AIS_FD) += fd/

View file

@ -0,0 +1,3 @@
ccflags-y += -Idrivers/media/platform/msm/ais
ccflags-y += -Idrivers/media/platform/msm/ais/msm_vb2
obj-$(CONFIG_MSM_AIS) += camera.o

View file

@ -0,0 +1,956 @@
/* Copyright (c) 2012-2017, 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/of.h>
#include <linux/module.h>
#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/proc_fs.h>
#include <linux/atomic.h>
#include <linux/wait.h>
#include <linux/videodev2.h>
#include <linux/msm_ion.h>
#include <linux/iommu.h>
#include <linux/platform_device.h>
#include <media/v4l2-fh.h>
#include <media/videobuf2-v4l2.h>
#include "camera.h"
#include "msm.h"
#include "msm_vb2.h"
#define fh_to_private(__fh) \
container_of(__fh, struct camera_v4l2_private, fh)
struct camera_v4l2_private {
struct v4l2_fh fh;
unsigned int stream_id;
unsigned int is_vb2_valid; /*0 if no vb2 buffers on stream, else 1*/
struct vb2_queue vb2_q;
bool stream_created;
struct mutex lock;
};
static void camera_pack_event(struct file *filep, int evt_id,
int command, int value, struct v4l2_event *event)
{
struct msm_v4l2_event_data *event_data =
(struct msm_v4l2_event_data *)&event->u.data[0];
struct msm_video_device *pvdev = video_drvdata(filep);
struct camera_v4l2_private *sp = fh_to_private(filep->private_data);
/* always MSM_CAMERA_V4L2_EVENT_TYPE */
event->type = MSM_CAMERA_V4L2_EVENT_TYPE;
event->id = evt_id;
event_data->command = command;
event_data->session_id = pvdev->vdev->num;
event_data->stream_id = sp->stream_id;
event_data->arg_value = value;
}
static int camera_check_event_status(struct v4l2_event *event)
{
struct msm_v4l2_event_data *event_data =
(struct msm_v4l2_event_data *)&event->u.data[0];
if (event_data->status > MSM_CAMERA_ERR_EVT_BASE) {
pr_err("%s : event_data status out of bounds\n",
__func__);
pr_err("%s : Line %d event_data->status 0X%x\n",
__func__, __LINE__, event_data->status);
switch (event_data->status) {
case MSM_CAMERA_ERR_CMD_FAIL:
case MSM_CAMERA_ERR_MAPPING:
return -EFAULT;
case MSM_CAMERA_ERR_DEVICE_BUSY:
return -EBUSY;
default:
return -EFAULT;
}
}
return 0;
}
static int camera_v4l2_querycap(struct file *filep, void *fh,
struct v4l2_capability *cap)
{
int rc;
struct v4l2_event event;
if (msm_is_daemon_present() == false)
return 0;
/* can use cap->driver to make differentiation */
camera_pack_event(filep, MSM_CAMERA_GET_PARM,
MSM_CAMERA_PRIV_QUERY_CAP, -1, &event);
rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT);
if (rc < 0)
return rc;
rc = camera_check_event_status(&event);
return rc;
}
static int camera_v4l2_s_crop(struct file *filep, void *fh,
const struct v4l2_crop *crop)
{
int rc = 0;
struct v4l2_event event;
if (msm_is_daemon_present() == false)
return 0;
if (crop->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
camera_pack_event(filep, MSM_CAMERA_SET_PARM,
MSM_CAMERA_PRIV_S_CROP, -1, &event);
rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT);
if (rc < 0)
return rc;
rc = camera_check_event_status(&event);
}
return rc;
}
static int camera_v4l2_g_crop(struct file *filep, void *fh,
struct v4l2_crop *crop)
{
int rc = 0;
struct v4l2_event event;
if (msm_is_daemon_present() == false)
return 0;
if (crop->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
camera_pack_event(filep, MSM_CAMERA_GET_PARM,
MSM_CAMERA_PRIV_G_CROP, -1, &event);
rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT);
if (rc < 0)
return rc;
rc = camera_check_event_status(&event);
}
return rc;
}
static int camera_v4l2_queryctrl(struct file *filep, void *fh,
struct v4l2_queryctrl *ctrl)
{
int rc = 0;
struct v4l2_event event;
if (msm_is_daemon_present() == false)
return 0;
if (ctrl->type == V4L2_CTRL_TYPE_MENU) {
camera_pack_event(filep, MSM_CAMERA_GET_PARM,
ctrl->id, -1, &event);
rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT);
if (rc < 0)
return rc;
rc = camera_check_event_status(&event);
}
return rc;
}
static int camera_v4l2_g_ctrl(struct file *filep, void *fh,
struct v4l2_control *ctrl)
{
int rc = 0;
struct v4l2_event event;
struct msm_video_device *pvdev = video_drvdata(filep);
unsigned int session_id = pvdev->vdev->num;
if (ctrl->id >= V4L2_CID_PRIVATE_BASE) {
if (ctrl->id == MSM_CAMERA_PRIV_G_SESSION_ID) {
ctrl->value = session_id;
} else {
camera_pack_event(filep, MSM_CAMERA_GET_PARM,
ctrl->id, -1, &event);
rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT);
if (rc < 0)
return rc;
rc = camera_check_event_status(&event);
}
}
return rc;
}
static int camera_v4l2_s_ctrl(struct file *filep, void *fh,
struct v4l2_control *ctrl)
{
int rc = 0;
struct v4l2_event event;
struct msm_v4l2_event_data *event_data;
if (ctrl->id >= V4L2_CID_PRIVATE_BASE) {
camera_pack_event(filep, MSM_CAMERA_SET_PARM, ctrl->id,
ctrl->value, &event);
rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT);
if (rc < 0)
return rc;
event_data = (struct msm_v4l2_event_data *)event.u.data;
ctrl->value = event_data->ret_value;
rc = camera_check_event_status(&event);
}
return rc;
}
static int camera_v4l2_reqbufs(struct file *filep, void *fh,
struct v4l2_requestbuffers *req)
{
int ret;
struct msm_session *session;
struct camera_v4l2_private *sp = fh_to_private(fh);
struct msm_video_device *pvdev = video_drvdata(filep);
unsigned int session_id = pvdev->vdev->num;
session = msm_session_find(session_id);
if (WARN_ON(!session))
return -EIO;
mutex_lock(&sp->lock);
ret = vb2_reqbufs(&sp->vb2_q, req);
mutex_unlock(&sp->lock);
return ret;
}
static int camera_v4l2_querybuf(struct file *filep, void *fh,
struct v4l2_buffer *pb)
{
return 0;
}
static int camera_v4l2_qbuf(struct file *filep, void *fh,
struct v4l2_buffer *pb)
{
int ret;
struct msm_session *session;
struct camera_v4l2_private *sp = fh_to_private(fh);
struct msm_video_device *pvdev = video_drvdata(filep);
unsigned int session_id = pvdev->vdev->num;
session = msm_session_find(session_id);
if (WARN_ON(!session))
return -EIO;
mutex_lock(&sp->lock);
ret = vb2_qbuf(&sp->vb2_q, pb);
mutex_unlock(&sp->lock);
return ret;
}
static int camera_v4l2_dqbuf(struct file *filep, void *fh,
struct v4l2_buffer *pb)
{
int ret;
struct msm_session *session;
struct camera_v4l2_private *sp = fh_to_private(fh);
struct msm_video_device *pvdev = video_drvdata(filep);
unsigned int session_id = pvdev->vdev->num;
session = msm_session_find(session_id);
if (WARN_ON(!session))
return -EIO;
mutex_lock(&sp->lock);
ret = vb2_dqbuf(&sp->vb2_q, pb, filep->f_flags & O_NONBLOCK);
mutex_unlock(&sp->lock);
return ret;
}
static int camera_v4l2_streamon(struct file *filep, void *fh,
enum v4l2_buf_type buf_type)
{
struct v4l2_event event;
int rc;
struct camera_v4l2_private *sp = fh_to_private(fh);
mutex_lock(&sp->lock);
rc = vb2_streamon(&sp->vb2_q, buf_type);
mutex_unlock(&sp->lock);
if (msm_is_daemon_present() == false)
return 0;
camera_pack_event(filep, MSM_CAMERA_SET_PARM,
MSM_CAMERA_PRIV_STREAM_ON, -1, &event);
rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT);
if (rc < 0)
return rc;
rc = camera_check_event_status(&event);
return rc;
}
static int camera_v4l2_streamoff(struct file *filep, void *fh,
enum v4l2_buf_type buf_type)
{
struct v4l2_event event;
int rc = 0;
struct camera_v4l2_private *sp = fh_to_private(fh);
if (msm_is_daemon_present() != false) {
camera_pack_event(filep, MSM_CAMERA_SET_PARM,
MSM_CAMERA_PRIV_STREAM_OFF, -1, &event);
rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT);
if (rc < 0)
return rc;
rc = camera_check_event_status(&event);
}
mutex_lock(&sp->lock);
vb2_streamoff(&sp->vb2_q, buf_type);
mutex_unlock(&sp->lock);
return rc;
}
static int camera_v4l2_g_fmt_vid_cap_mplane(struct file *filep, void *fh,
struct v4l2_format *pfmt)
{
int rc = -EINVAL;
if (msm_is_daemon_present() == false)
return 0;
if (pfmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
struct v4l2_event event;
camera_pack_event(filep, MSM_CAMERA_GET_PARM,
MSM_CAMERA_PRIV_G_FMT, -1, &event);
rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT);
if (rc < 0)
return rc;
rc = camera_check_event_status(&event);
}
return rc;
}
static int camera_v4l2_s_fmt_vid_cap_mplane(struct file *filep, void *fh,
struct v4l2_format *pfmt)
{
int rc = 0;
int i = 0;
struct v4l2_event event;
struct camera_v4l2_private *sp = fh_to_private(fh);
struct msm_v4l2_format_data *user_fmt;
if (pfmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
if (WARN_ON(!sp->vb2_q.drv_priv))
return -ENOMEM;
memcpy(sp->vb2_q.drv_priv, pfmt->fmt.raw_data,
sizeof(struct msm_v4l2_format_data));
user_fmt = (struct msm_v4l2_format_data *)sp->vb2_q.drv_priv;
pr_debug("%s: num planes :%c\n", __func__,
user_fmt->num_planes);
/* num_planes need to bound checked, otherwise for loop
* can execute forever
*/
if (WARN_ON(user_fmt->num_planes > VIDEO_MAX_PLANES))
return -EINVAL;
for (i = 0; i < user_fmt->num_planes; i++)
pr_debug("%s: plane size[%d]\n", __func__,
user_fmt->plane_sizes[i]);
if (msm_is_daemon_present() != false) {
camera_pack_event(filep, MSM_CAMERA_SET_PARM,
MSM_CAMERA_PRIV_S_FMT, -1, &event);
rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT);
if (rc < 0)
return rc;
rc = camera_check_event_status(&event);
if (rc < 0)
return rc;
}
sp->is_vb2_valid = 1;
}
return rc;
}
static int camera_v4l2_try_fmt_vid_cap_mplane(struct file *filep, void *fh,
struct v4l2_format *pfmt)
{
return 0;
}
static int camera_v4l2_g_parm(struct file *filep, void *fh,
struct v4l2_streamparm *a)
{
/* TODO */
return 0;
}
static int camera_v4l2_s_parm(struct file *filep, void *fh,
struct v4l2_streamparm *parm)
{
int rc = 0;
struct v4l2_event event;
struct msm_v4l2_event_data *event_data =
(struct msm_v4l2_event_data *)&event.u.data[0];
struct camera_v4l2_private *sp = fh_to_private(fh);
camera_pack_event(filep, MSM_CAMERA_SET_PARM,
MSM_CAMERA_PRIV_NEW_STREAM, -1, &event);
rc = msm_create_stream(event_data->session_id,
event_data->stream_id, &sp->vb2_q);
if (rc < 0)
return rc;
if (msm_is_daemon_present() != false) {
rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT);
if (rc < 0)
goto error;
rc = camera_check_event_status(&event);
if (rc < 0)
goto error;
}
/* use stream_id as stream index */
parm->parm.capture.extendedmode = sp->stream_id;
sp->stream_created = true;
return rc;
error:
msm_delete_stream(event_data->session_id,
event_data->stream_id);
return rc;
}
static int camera_v4l2_subscribe_event(struct v4l2_fh *fh,
const struct v4l2_event_subscription *sub)
{
int rc = 0;
struct camera_v4l2_private *sp = fh_to_private(fh);
rc = v4l2_event_subscribe(&sp->fh, sub, 5, NULL);
return rc;
}
static int camera_v4l2_unsubscribe_event(struct v4l2_fh *fh,
const struct v4l2_event_subscription *sub)
{
int rc = 0;
struct camera_v4l2_private *sp = fh_to_private(fh);
rc = v4l2_event_unsubscribe(&sp->fh, sub);
return rc;
}
static long camera_v4l2_vidioc_private_ioctl(struct file *filep, void *fh,
bool valid_prio, unsigned int cmd, void *arg)
{
struct camera_v4l2_private *sp = fh_to_private(fh);
struct msm_video_device *pvdev = video_drvdata(filep);
struct msm_camera_private_ioctl_arg *k_ioctl = arg;
long rc = -EINVAL;
if (WARN_ON(!k_ioctl || !pvdev))
return -EIO;
switch (k_ioctl->id) {
case MSM_CAMERA_PRIV_IOCTL_ID_RETURN_BUF: {
struct msm_camera_return_buf ptr, *tmp = NULL;
MSM_CAM_GET_IOCTL_ARG_PTR(&tmp, &k_ioctl->ioctl_ptr,
sizeof(tmp));
if (copy_from_user(&ptr, tmp,
sizeof(struct msm_camera_return_buf))) {
return -EFAULT;
}
rc = msm_vb2_return_buf_by_idx(pvdev->vdev->num, sp->stream_id,
ptr.index);
}
break;
default:
pr_debug("unimplemented id %d", k_ioctl->id);
return -EINVAL;
}
return rc;
}
static const struct v4l2_ioctl_ops camera_v4l2_ioctl_ops = {
.vidioc_querycap = camera_v4l2_querycap,
.vidioc_s_crop = camera_v4l2_s_crop,
.vidioc_g_crop = camera_v4l2_g_crop,
.vidioc_queryctrl = camera_v4l2_queryctrl,
.vidioc_g_ctrl = camera_v4l2_g_ctrl,
.vidioc_s_ctrl = camera_v4l2_s_ctrl,
.vidioc_reqbufs = camera_v4l2_reqbufs,
.vidioc_querybuf = camera_v4l2_querybuf,
.vidioc_qbuf = camera_v4l2_qbuf,
.vidioc_dqbuf = camera_v4l2_dqbuf,
.vidioc_streamon = camera_v4l2_streamon,
.vidioc_streamoff = camera_v4l2_streamoff,
.vidioc_g_fmt_vid_cap_mplane = camera_v4l2_g_fmt_vid_cap_mplane,
.vidioc_s_fmt_vid_cap_mplane = camera_v4l2_s_fmt_vid_cap_mplane,
.vidioc_try_fmt_vid_cap_mplane = camera_v4l2_try_fmt_vid_cap_mplane,
/* Stream type-dependent parameter ioctls */
.vidioc_g_parm = camera_v4l2_g_parm,
.vidioc_s_parm = camera_v4l2_s_parm,
/* event subscribe/unsubscribe */
.vidioc_subscribe_event = camera_v4l2_subscribe_event,
.vidioc_unsubscribe_event = camera_v4l2_unsubscribe_event,
.vidioc_default = camera_v4l2_vidioc_private_ioctl,
};
static int camera_v4l2_fh_open(struct file *filep)
{
struct msm_video_device *pvdev = video_drvdata(filep);
struct camera_v4l2_private *sp;
unsigned int stream_id;
sp = kzalloc(sizeof(*sp), GFP_KERNEL);
if (!sp)
return -ENOMEM;
filep->private_data = &sp->fh;
/* stream_id = open id */
stream_id = atomic_read(&pvdev->opened);
sp->stream_id = find_first_zero_bit(
(const unsigned long *)&stream_id, MSM_CAMERA_STREAM_CNT_BITS);
pr_debug("%s: Found stream_id=%d\n", __func__, sp->stream_id);
mutex_init(&sp->lock);
v4l2_fh_init(&sp->fh, pvdev->vdev);
v4l2_fh_add(&sp->fh);
return 0;
}
static int camera_v4l2_fh_release(struct file *filep)
{
struct camera_v4l2_private *sp = fh_to_private(filep->private_data);
if (sp) {
v4l2_fh_del(&sp->fh);
v4l2_fh_exit(&sp->fh);
}
mutex_destroy(&sp->lock);
kzfree(sp);
return 0;
}
static int camera_v4l2_vb2_q_init(struct file *filep)
{
struct camera_v4l2_private *sp = fh_to_private(filep->private_data);
struct vb2_queue *q = &sp->vb2_q;
memset(q, 0, sizeof(struct vb2_queue));
/* free up this buffer when stream is done */
q->drv_priv =
kzalloc(sizeof(struct msm_v4l2_format_data), GFP_KERNEL);
if (!q->drv_priv) {
pr_err("%s : memory not available\n", __func__);
return -ENOMEM;
}
q->mem_ops = msm_vb2_get_q_mem_ops();
q->ops = msm_vb2_get_q_ops();
/* default queue type */
q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
q->io_modes = VB2_USERPTR;
q->buf_struct_size = sizeof(struct msm_vb2_buffer);
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
return vb2_queue_init(q);
}
static void camera_v4l2_vb2_q_release(struct file *filep)
{
struct camera_v4l2_private *sp = filep->private_data;
kzfree(sp->vb2_q.drv_priv);
mutex_lock(&sp->lock);
vb2_queue_release(&sp->vb2_q);
mutex_unlock(&sp->lock);
}
static int camera_v4l2_open(struct file *filep)
{
int rc = 0;
struct v4l2_event event;
struct msm_video_device *pvdev = video_drvdata(filep);
unsigned int opn_idx, idx;
if (WARN_ON(!pvdev))
return -EIO;
rc = camera_v4l2_fh_open(filep);
if (rc < 0) {
pr_err("%s : camera_v4l2_fh_open failed Line %d rc %d\n",
__func__, __LINE__, rc);
goto fh_open_fail;
}
opn_idx = atomic_read(&pvdev->opened);
idx = opn_idx;
/* every stream has a vb2 queue */
rc = camera_v4l2_vb2_q_init(filep);
if (rc < 0) {
pr_err("%s : vb2 queue init fails Line %d rc %d\n",
__func__, __LINE__, rc);
goto vb2_q_fail;
}
if (!atomic_read(&pvdev->opened)) {
pm_stay_awake(&pvdev->vdev->dev);
/* Disable power collapse latency */
msm_pm_qos_update_request(CAMERA_DISABLE_PC_LATENCY);
/* create a new session when first opened */
rc = msm_create_session(pvdev->vdev->num, pvdev->vdev);
if (rc < 0) {
pr_err("%s : session creation failed Line %d rc %d\n",
__func__, __LINE__, rc);
goto session_fail;
}
rc = msm_create_command_ack_q(pvdev->vdev->num,
find_first_zero_bit((const unsigned long *)&opn_idx,
MSM_CAMERA_STREAM_CNT_BITS));
if (rc < 0) {
pr_err("%s : creation of command_ack queue failed\n",
__func__);
pr_err("%s : Line %d rc %d\n", __func__, __LINE__, rc);
goto command_ack_q_fail;
}
if (msm_is_daemon_present() != false) {
camera_pack_event(filep, MSM_CAMERA_NEW_SESSION,
0, -1, &event);
rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT);
if (rc < 0) {
pr_err("%s : NEW_SESSION event failed,rc %d\n",
__func__, rc);
goto post_fail;
}
rc = camera_check_event_status(&event);
if (rc < 0)
goto post_fail;
}
/* Enable power collapse latency */
msm_pm_qos_update_request(CAMERA_ENABLE_PC_LATENCY);
} else {
rc = msm_create_command_ack_q(pvdev->vdev->num,
find_first_zero_bit((const unsigned long *)&opn_idx,
MSM_CAMERA_STREAM_CNT_BITS));
if (rc < 0) {
pr_err("%s : creation of command_ack queue failed Line %d rc %d\n",
__func__, __LINE__, rc);
goto stream_fail;
}
}
idx |= (1 << find_first_zero_bit((const unsigned long *)&opn_idx,
MSM_CAMERA_STREAM_CNT_BITS));
atomic_cmpxchg(&pvdev->opened, opn_idx, idx);
return rc;
post_fail:
msm_delete_command_ack_q(pvdev->vdev->num, 0);
command_ack_q_fail:
msm_destroy_session(pvdev->vdev->num);
session_fail:
pm_relax(&pvdev->vdev->dev);
stream_fail:
camera_v4l2_vb2_q_release(filep);
vb2_q_fail:
camera_v4l2_fh_release(filep);
fh_open_fail:
return rc;
}
static unsigned int camera_v4l2_poll(struct file *filep,
struct poll_table_struct *wait)
{
int rc = 0;
struct camera_v4l2_private *sp = fh_to_private(filep->private_data);
if (sp->is_vb2_valid == 1)
rc = vb2_poll(&sp->vb2_q, filep, wait);
poll_wait(filep, &sp->fh.wait, wait);
if (v4l2_event_pending(&sp->fh))
rc |= POLLPRI;
return rc;
}
static int camera_v4l2_close(struct file *filep)
{
struct v4l2_event event;
struct msm_video_device *pvdev = video_drvdata(filep);
struct camera_v4l2_private *sp = fh_to_private(filep->private_data);
unsigned int opn_idx, mask;
struct msm_session *session;
if (WARN_ON(!pvdev))
return -EIO;
session = msm_session_find(pvdev->vdev->num);
if (WARN_ON(!session))
return -EIO;
mutex_lock(&session->close_lock);
opn_idx = atomic_read(&pvdev->opened);
mask = (1 << sp->stream_id);
opn_idx &= ~mask;
atomic_set(&pvdev->opened, opn_idx);
if (msm_is_daemon_present() != false && sp->stream_created == true) {
pr_debug("%s: close stream_id=%d\n", __func__, sp->stream_id);
camera_pack_event(filep, MSM_CAMERA_SET_PARM,
MSM_CAMERA_PRIV_DEL_STREAM, -1, &event);
msm_post_event(&event, MSM_POST_EVT_TIMEOUT);
}
if (sp->stream_created == true)
sp->stream_created = false;
if (atomic_read(&pvdev->opened) == 0) {
if (msm_is_daemon_present() != false) {
camera_pack_event(filep, MSM_CAMERA_DEL_SESSION,
0, -1, &event);
msm_post_event(&event, MSM_POST_EVT_TIMEOUT);
}
msm_delete_command_ack_q(pvdev->vdev->num, 0);
msm_delete_stream(pvdev->vdev->num, sp->stream_id);
mutex_unlock(&session->close_lock);
/* This should take care of both normal close
* and application crashes
*/
camera_v4l2_vb2_q_release(filep);
msm_destroy_session(pvdev->vdev->num);
pm_relax(&pvdev->vdev->dev);
} else {
msm_delete_command_ack_q(pvdev->vdev->num,
sp->stream_id);
camera_v4l2_vb2_q_release(filep);
msm_delete_stream(pvdev->vdev->num, sp->stream_id);
mutex_unlock(&session->close_lock);
}
camera_v4l2_fh_release(filep);
return 0;
}
#ifdef CONFIG_COMPAT
static long camera_handle_internal_compat_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
long rc = 0;
struct msm_camera_private_ioctl_arg k_ioctl;
void __user *tmp_compat_ioctl_ptr = NULL;
rc = msm_copy_camera_private_ioctl_args(arg,
&k_ioctl, &tmp_compat_ioctl_ptr);
if (rc < 0) {
pr_err("Subdev cmd %d failed\n", cmd);
return rc;
}
switch (k_ioctl.id) {
case MSM_CAMERA_PRIV_IOCTL_ID_RETURN_BUF: {
if (k_ioctl.size != sizeof(struct msm_camera_return_buf)) {
pr_debug("Invalid size for id %d with size %d",
k_ioctl.id, k_ioctl.size);
return -EINVAL;
}
k_ioctl.ioctl_ptr = (__u64)tmp_compat_ioctl_ptr;
if (!k_ioctl.ioctl_ptr) {
pr_debug("Invalid ptr for id %d", k_ioctl.id);
return -EINVAL;
}
rc = camera_v4l2_vidioc_private_ioctl(file, file->private_data,
0, cmd, (void *)&k_ioctl);
}
break;
default:
pr_debug("unimplemented id %d", k_ioctl.id);
return -EINVAL;
}
return rc;
}
long camera_v4l2_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
long ret = 0;
switch (cmd) {
case VIDIOC_MSM_CAMERA_PRIVATE_IOCTL_CMD: {
ret = camera_handle_internal_compat_ioctl(file, cmd, arg);
if (ret < 0) {
pr_debug("Subdev cmd %d fail\n", cmd);
return ret;
}
}
break;
default:
ret = -ENOIOCTLCMD;
break;
}
return ret;
}
#endif
static struct v4l2_file_operations camera_v4l2_fops = {
.owner = THIS_MODULE,
.open = camera_v4l2_open,
.poll = camera_v4l2_poll,
.release = camera_v4l2_close,
.unlocked_ioctl = video_ioctl2,
#ifdef CONFIG_COMPAT
.compat_ioctl32 = camera_v4l2_compat_ioctl,
#endif
};
int camera_init_v4l2(struct device *dev, unsigned int *session)
{
struct msm_video_device *pvdev;
struct v4l2_device *v4l2_dev;
int rc = 0;
pvdev = kzalloc(sizeof(struct msm_video_device),
GFP_KERNEL);
if (!pvdev) {
rc = -ENOMEM;
goto init_end;
}
pvdev->vdev = video_device_alloc();
if (!pvdev->vdev) {
rc = -ENOMEM;
goto video_fail;
}
v4l2_dev = kzalloc(sizeof(struct v4l2_device), GFP_KERNEL);
if (!v4l2_dev) {
rc = -ENOMEM;
goto v4l2_fail;
}
#if defined(CONFIG_MEDIA_CONTROLLER)
v4l2_dev->mdev = kzalloc(sizeof(struct media_device),
GFP_KERNEL);
if (!v4l2_dev->mdev) {
rc = -ENOMEM;
goto mdev_fail;
}
strlcpy(v4l2_dev->mdev->model, MSM_CAMERA_NAME,
sizeof(v4l2_dev->mdev->model));
v4l2_dev->mdev->dev = dev;
rc = media_device_register(v4l2_dev->mdev);
if (WARN_ON(rc < 0))
goto media_fail;
rc = media_entity_init(&pvdev->vdev->entity, 0, NULL, 0);
if (WARN_ON(rc < 0))
goto entity_fail;
pvdev->vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L;
pvdev->vdev->entity.group_id = QCAMERA_VNODE_GROUP_ID;
#endif
v4l2_dev->notify = NULL;
pvdev->vdev->v4l2_dev = v4l2_dev;
rc = v4l2_device_register(dev, pvdev->vdev->v4l2_dev);
if (WARN_ON(rc < 0))
goto register_fail;
strlcpy(pvdev->vdev->name, "msm-sensor", sizeof(pvdev->vdev->name));
pvdev->vdev->release = video_device_release;
pvdev->vdev->fops = &camera_v4l2_fops;
pvdev->vdev->ioctl_ops = &camera_v4l2_ioctl_ops;
pvdev->vdev->minor = -1;
pvdev->vdev->vfl_type = VFL_TYPE_GRABBER;
rc = video_register_device(pvdev->vdev,
VFL_TYPE_GRABBER, -1);
if (WARN_ON(rc < 0))
goto video_register_fail;
#if defined(CONFIG_MEDIA_CONTROLLER)
/* FIXME: How to get rid of this messy? */
pvdev->vdev->entity.name = video_device_node_name(pvdev->vdev);
#endif
*session = pvdev->vdev->num;
atomic_set(&pvdev->opened, 0);
video_set_drvdata(pvdev->vdev, pvdev);
device_init_wakeup(&pvdev->vdev->dev, 1);
goto init_end;
video_register_fail:
v4l2_device_unregister(pvdev->vdev->v4l2_dev);
register_fail:
#if defined(CONFIG_MEDIA_CONTROLLER)
media_entity_cleanup(&pvdev->vdev->entity);
entity_fail:
media_device_unregister(v4l2_dev->mdev);
media_fail:
kzfree(v4l2_dev->mdev);
mdev_fail:
#endif
kzfree(v4l2_dev);
v4l2_fail:
video_device_release(pvdev->vdev);
video_fail:
kzfree(pvdev);
init_end:
return rc;
}

View file

@ -0,0 +1,23 @@
/* Copyright (c) 2012-2017, 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 _CAMERA_H
#define _CAMERA_H
enum stream_state {
START_STREAM = 0,
STOP_STREAM,
};
int camera_init_v4l2(struct device *dev, unsigned int *session);
#endif /*_CAMERA_H */

View file

@ -0,0 +1,2 @@
ccflags-y += -Idrivers/media/platform/msm/ais/
obj-$(CONFIG_MSM_AIS) += msm_camera_io_util.o cam_smmu_api.o cam_hw_ops.o cam_soc_api.o

View file

@ -0,0 +1,338 @@
/* Copyright (c) 2015-2017, 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.
*/
#define pr_fmt(fmt) "CAM-AHB %s:%d " fmt, __func__, __LINE__
#define TRUE 1
#include <linux/module.h>
#include <linux/msm-bus.h>
#include <linux/msm-bus-board.h>
#include <linux/of_platform.h>
#include <linux/pm_opp.h>
#include <linux/regulator/rpm-smd-regulator.h>
#include "cam_hw_ops.h"
#ifdef CONFIG_CAM_AHB_DBG
#define CDBG(fmt, args...) pr_err(fmt, ##args)
#else
#define CDBG(fmt, args...) pr_debug(fmt, ##args)
#endif
struct cam_ahb_client {
enum cam_ahb_clk_vote vote;
};
struct cam_bus_vector {
const char *name;
};
struct cam_ahb_client_data {
struct msm_bus_scale_pdata *pbus_data;
u32 ahb_client;
u32 ahb_clk_state;
struct msm_bus_vectors *paths;
struct msm_bus_paths *usecases;
struct cam_bus_vector *vectors;
u32 *votes;
u32 cnt;
u32 probe_done;
struct cam_ahb_client clients[CAM_AHB_CLIENT_MAX];
struct mutex lock;
};
static struct cam_ahb_client_data data;
int get_vector_index(char *name)
{
int i = 0, rc = -1;
for (i = 0; i < data.cnt; i++) {
if (strcmp(name, data.vectors[i].name) == 0)
return i;
}
return rc;
}
int cam_ahb_clk_init(struct platform_device *pdev)
{
int i = 0, cnt = 0, rc = 0, index = 0;
struct device_node *of_node;
if (!pdev) {
pr_err("invalid pdev argument\n");
return -EINVAL;
}
of_node = pdev->dev.of_node;
data.cnt = of_property_count_strings(of_node, "bus-vectors");
if (data.cnt == 0) {
pr_err("no vectors strings found in device tree, count=%d",
data.cnt);
return 0;
}
cnt = of_property_count_u32_elems(of_node, "qcom,bus-votes");
if (cnt == 0) {
pr_err("no vector values found in device tree, count=%d", cnt);
return 0;
}
if (data.cnt != cnt) {
pr_err("vector mismatch num of strings=%u, num of values %d\n",
data.cnt, cnt);
return -EINVAL;
}
CDBG("number of bus vectors: %d\n", data.cnt);
data.vectors = devm_kzalloc(&pdev->dev,
sizeof(struct cam_bus_vector) * cnt,
GFP_KERNEL);
if (!data.vectors)
return -ENOMEM;
for (i = 0; i < data.cnt; i++) {
rc = of_property_read_string_index(of_node, "bus-vectors",
i, &(data.vectors[i].name));
CDBG("dbg: names[%d] = %s\n", i, data.vectors[i].name);
if (rc < 0) {
pr_err("failed\n");
rc = -EINVAL;
goto err1;
}
}
data.paths = devm_kzalloc(&pdev->dev,
sizeof(struct msm_bus_vectors) * cnt,
GFP_KERNEL);
if (!data.paths) {
rc = -ENOMEM;
goto err1;
}
data.usecases = devm_kzalloc(&pdev->dev,
sizeof(struct msm_bus_paths) * cnt,
GFP_KERNEL);
if (!data.usecases) {
rc = -ENOMEM;
goto err2;
}
data.pbus_data = devm_kzalloc(&pdev->dev,
sizeof(struct msm_bus_scale_pdata),
GFP_KERNEL);
if (!data.pbus_data) {
rc = -ENOMEM;
goto err3;
}
data.votes = devm_kzalloc(&pdev->dev, sizeof(u32) * cnt,
GFP_KERNEL);
if (!data.votes) {
rc = -ENOMEM;
goto err4;
}
rc = of_property_read_u32_array(of_node, "qcom,bus-votes",
data.votes, cnt);
for (i = 0; i < data.cnt; i++) {
data.paths[i] = (struct msm_bus_vectors) {
MSM_BUS_MASTER_AMPSS_M0,
MSM_BUS_SLAVE_CAMERA_CFG,
0,
data.votes[i]
};
data.usecases[i] = (struct msm_bus_paths) {
.num_paths = 1,
.vectors = &data.paths[i],
};
CDBG("dbg: votes[%d] = %u\n", i, data.votes[i]);
}
*data.pbus_data = (struct msm_bus_scale_pdata) {
.name = "msm_camera_ahb",
.num_usecases = data.cnt,
.usecase = data.usecases,
};
data.ahb_client =
msm_bus_scale_register_client(data.pbus_data);
if (!data.ahb_client) {
pr_err("ahb vote registering failed\n");
rc = -EINVAL;
goto err5;
}
index = get_vector_index("suspend");
if (index < 0) {
pr_err("svs vector not supported\n");
rc = -EINVAL;
goto err6;
}
/* request for svs in init */
msm_bus_scale_client_update_request(data.ahb_client,
index);
data.ahb_clk_state = CAM_AHB_SUSPEND_VOTE;
data.probe_done = TRUE;
mutex_init(&data.lock);
CDBG("dbg, done registering ahb votes\n");
CDBG("dbg, clk state :%u, probe :%d\n",
data.ahb_clk_state, data.probe_done);
return rc;
err6:
msm_bus_scale_unregister_client(data.ahb_client);
err5:
devm_kfree(&pdev->dev, data.votes);
data.votes = NULL;
err4:
devm_kfree(&pdev->dev, data.pbus_data);
data.pbus_data = NULL;
err3:
devm_kfree(&pdev->dev, data.usecases);
data.usecases = NULL;
err2:
devm_kfree(&pdev->dev, data.paths);
data.paths = NULL;
err1:
devm_kfree(&pdev->dev, data.vectors);
data.vectors = NULL;
return rc;
}
EXPORT_SYMBOL(cam_ahb_clk_init);
int cam_consolidate_ahb_vote(enum cam_ahb_clk_client id,
enum cam_ahb_clk_vote vote)
{
int i = 0;
u32 max = 0;
CDBG("dbg: id :%u, vote : 0x%x\n", id, vote);
mutex_lock(&data.lock);
data.clients[id].vote = vote;
if (vote == data.ahb_clk_state) {
CDBG("dbg: already at desired vote\n");
mutex_unlock(&data.lock);
return 0;
}
for (i = 0; i < CAM_AHB_CLIENT_MAX; i++) {
if (data.clients[i].vote > max)
max = data.clients[i].vote;
}
CDBG("dbg: max vote : %u\n", max);
if (max >= 0) {
if (max != data.ahb_clk_state) {
msm_bus_scale_client_update_request(data.ahb_client,
max);
data.ahb_clk_state = max;
CDBG("dbg: state : %u, vector : %d\n",
data.ahb_clk_state, max);
}
} else {
pr_err("err: no bus vector found\n");
mutex_unlock(&data.lock);
return -EINVAL;
}
mutex_unlock(&data.lock);
return 0;
}
static int cam_ahb_get_voltage_level(unsigned int corner)
{
switch (corner) {
case RPM_REGULATOR_CORNER_NONE:
return CAM_AHB_SUSPEND_VOTE;
case RPM_REGULATOR_CORNER_SVS_KRAIT:
case RPM_REGULATOR_CORNER_SVS_SOC:
return CAM_AHB_SVS_VOTE;
case RPM_REGULATOR_CORNER_NORMAL:
return CAM_AHB_NOMINAL_VOTE;
case RPM_REGULATOR_CORNER_SUPER_TURBO:
return CAM_AHB_TURBO_VOTE;
case RPM_REGULATOR_CORNER_TURBO:
case RPM_REGULATOR_CORNER_RETENTION:
default:
return -EINVAL;
}
}
int cam_config_ahb_clk(struct device *dev, unsigned long freq,
enum cam_ahb_clk_client id, enum cam_ahb_clk_vote vote)
{
struct dev_pm_opp *opp;
unsigned int corner;
enum cam_ahb_clk_vote dyn_vote = vote;
int rc = -EINVAL;
if (id >= CAM_AHB_CLIENT_MAX) {
pr_err("err: invalid argument\n");
return -EINVAL;
}
if (data.probe_done != TRUE) {
pr_err("ahb init is not done yet\n");
return -EINVAL;
}
CDBG("dbg: id :%u, vote : 0x%x\n", id, vote);
switch (dyn_vote) {
case CAM_AHB_SUSPEND_VOTE:
case CAM_AHB_SVS_VOTE:
case CAM_AHB_NOMINAL_VOTE:
case CAM_AHB_TURBO_VOTE:
break;
case CAM_AHB_DYNAMIC_VOTE:
if (!dev) {
pr_err("device is NULL\n");
return -EINVAL;
}
opp = dev_pm_opp_find_freq_exact(dev, freq, true);
if (IS_ERR(opp)) {
pr_err("Error on OPP freq :%ld\n", freq);
return -EINVAL;
}
corner = dev_pm_opp_get_voltage(opp);
if (corner == 0) {
pr_err("Bad voltage corner for OPP freq :%ld\n", freq);
return -EINVAL;
}
dyn_vote = cam_ahb_get_voltage_level(corner);
if (dyn_vote < 0) {
pr_err("Bad vote requested\n");
return -EINVAL;
}
break;
default:
pr_err("err: invalid vote argument\n");
return -EINVAL;
}
rc = cam_consolidate_ahb_vote(id, dyn_vote);
if (rc < 0) {
pr_err("%s: failed to vote for AHB\n", __func__);
goto end;
}
end:
return rc;
}
EXPORT_SYMBOL(cam_config_ahb_clk);

View file

@ -0,0 +1,42 @@
/* Copyright (c) 2015-2017, 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 _CAM_HW_OPS_H_
#define _CAM_HW_OPS_H_
enum cam_ahb_clk_vote {
/* need to update the voting requests
* according to dtsi entries.
*/
CAM_AHB_SUSPEND_VOTE = 0x0,
CAM_AHB_SVS_VOTE = 0x01,
CAM_AHB_NOMINAL_VOTE = 0x02,
CAM_AHB_TURBO_VOTE = 0x03,
CAM_AHB_DYNAMIC_VOTE = 0xFF,
};
enum cam_ahb_clk_client {
CAM_AHB_CLIENT_CSIPHY,
CAM_AHB_CLIENT_CSID,
CAM_AHB_CLIENT_CCI,
CAM_AHB_CLIENT_ISPIF,
CAM_AHB_CLIENT_VFE0,
CAM_AHB_CLIENT_VFE1,
CAM_AHB_CLIENT_CPP,
CAM_AHB_CLIENT_FD,
CAM_AHB_CLIENT_JPEG,
CAM_AHB_CLIENT_MAX
};
int cam_config_ahb_clk(struct device *dev, unsigned long freq,
enum cam_ahb_clk_client id, enum cam_ahb_clk_vote vote);
int cam_ahb_clk_init(struct platform_device *pdev);
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,166 @@
/* Copyright (c) 2014-2017, 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 _CAM_SMMU_API_H_
#define _CAM_SMMU_API_H_
#include <linux/dma-direction.h>
#include <linux/module.h>
#include <linux/dma-buf.h>
#include <asm/dma-iommu.h>
#include <linux/dma-direction.h>
#include <linux/dma-attrs.h>
#include <linux/of_platform.h>
#include <linux/iommu.h>
#include <linux/random.h>
#include <linux/spinlock_types.h>
#include <linux/mutex.h>
/*
* Enum for possible CAM SMMU operations
*/
enum cam_smmu_ops_param {
CAM_SMMU_ATTACH,
CAM_SMMU_DETACH,
CAM_SMMU_VOTE,
CAM_SMMU_DEVOTE,
CAM_SMMU_OPS_INVALID
};
enum cam_smmu_map_dir {
CAM_SMMU_MAP_READ,
CAM_SMMU_MAP_WRITE,
CAM_SMMU_MAP_RW,
CAM_SMMU_MAP_INVALID
};
/**
* @param identifier: Unique identifier to be used by clients which they
* should get from device tree. CAM SMMU driver will
* not enforce how this string is obtained and will
* only validate this against the list of permitted
* identifiers
* @param handle_ptr: Based on the indentifier, CAM SMMU drivier will
* fill the handle pointed by handle_ptr
* @return Status of operation. Negative in case of error. Zero otherwise.
*/
int cam_smmu_get_handle(char *identifier, int *handle_ptr);
/**
* @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.)
* @param op : Operation to be performed. Can be either CAM_SMMU_ATTACH
* or CAM_SMMU_DETACH
*
* @return Status of operation. Negative in case of error. Zero otherwise.
*/
int cam_smmu_ops(int handle, enum cam_smmu_ops_param op);
/**
* @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.)
* @param ion_fd: ION handle identifying the memory buffer.
* @phys_addr : Pointer to physical address where mapped address will be
* returned.
* @dir : Mapping direction: which will traslate toDMA_BIDIRECTIONAL,
* DMA_TO_DEVICE or DMA_FROM_DEVICE
* @len : Length of buffer mapped returned by CAM SMMU driver.
* @return Status of operation. Negative in case of error. Zero otherwise.
*/
int cam_smmu_get_phy_addr(int handle,
int ion_fd, enum cam_smmu_map_dir dir,
dma_addr_t *dma_addr, size_t *len_ptr);
/**
* @param handle: Handle to identify the CAMSMMU client (VFE, CPP, FD etc.)
* @param ion_fd: ION handle identifying the memory buffer.
*
* @return Status of operation. Negative in case of error. Zero otherwise.
*/
int cam_smmu_put_phy_addr(int handle, int ion_fd);
/**
* @brief : Allocates a scratch buffer
*
* This function allocates a scratch virtual buffer of length virt_len in the
* device virtual address space mapped to phys_len physically contiguous bytes
* in that device's SMMU.
*
* virt_len and phys_len are expected to be aligned to PAGE_SIZE and with each
* other, otherwise -EINVAL is returned.
*
* -EINVAL will be returned if virt_len is less than phys_len.
*
* Passing a too large phys_len might also cause failure if that much size is
* not available for allocation in a physically contiguous way.
*
* @param handle : Handle to identify the CAMSMMU client (VFE, CPP, FD etc.)
* @param dir : Direction of mapping which will translate to IOMMU_READ
* IOMMU_WRITE or a bit mask of both.
* @param paddr_ptr: Device virtual address that the client device will be
* able to read from/write to
* @param virt_len : Virtual length of the scratch buffer
* @param phys_len : Physical length of the scratch buffer
*
* @return Status of operation. Negative in case of error. Zero otherwise.
*/
int cam_smmu_get_phy_addr_scratch(int handle,
enum cam_smmu_map_dir dir,
dma_addr_t *paddr_ptr,
size_t virt_len,
size_t phys_len);
/**
* @brief : Frees a scratch buffer
*
* This function frees a scratch buffer and releases the corresponding SMMU
* mappings.
*
* @param handle : Handle to identify the CAMSMMU client (VFE, CPP, FD etc.)
* IOMMU_WRITE or a bit mask of both.
* @param paddr_ptr: Device virtual address of client's scratch buffer that
* will be freed.
*
* @return Status of operation. Negative in case of error. Zero otherwise.
*/
int cam_smmu_put_phy_addr_scratch(int handle,
dma_addr_t paddr);
/**
* @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.)
*
* @return Status of operation. Negative in case of error. Zero otherwise.
*/
int cam_smmu_destroy_handle(int handle);
/**
* @return numger of client. Zero in case of error.
*/
int cam_smmu_get_num_of_clients(void);
/**
* @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.)
* @return Index of SMMU client. Nagative in case of error.
*/
int cam_smmu_find_index_by_handle(int hdl);
/**
* @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.)
* @param client_page_fault_handler: It is triggered in IOMMU page fault
* @param token: It is input param when trigger page fault handler
*/
void cam_smmu_reg_client_page_fault_handler(int handle,
void (*client_page_fault_handler)(struct iommu_domain *,
struct device *, unsigned long,
int, void*), void *token);
#endif /* _CAM_SMMU_API_H_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,425 @@
/* Copyright (c) 2015-2017, 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 _CAM_SOC_API_H_
#define _CAM_SOC_API_H_
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/spinlock_types.h>
#include <linux/mutex.h>
#include <linux/clk.h>
#include <linux/regulator/consumer.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <soc/qcom/ais.h>
enum cam_bus_client {
CAM_BUS_CLIENT_VFE,
CAM_BUS_CLIENT_CPP,
CAM_BUS_CLIENT_FD,
CAM_BUS_CLIENT_JPEG_ENC0,
CAM_BUS_CLIENT_JPEG_ENC1,
CAM_BUS_CLIENT_JPEG_DEC,
CAM_BUS_CLIENT_JPEG_DMA,
CAM_BUS_CLIENT_MAX
};
struct msm_cam_regulator {
const char *name;
struct regulator *vdd;
};
/**
* @brief : Gets clock information from dtsi
*
* This function extracts the clocks information for a specific
* platform device
*
* @param pdev : Platform device to get clocks information
* @param clk_info : Pointer to populate clock information array
* @param clk_ptr : Pointer to populate clock resource pointers
* @param num_clk: Pointer to populate the number of clocks
* extracted from dtsi
*
* @return Status of operation. Negative in case of error. Zero otherwise.
*/
int msm_camera_get_clk_info(struct platform_device *pdev,
struct msm_cam_clk_info **clk_info,
struct clk ***clk_ptr,
size_t *num_clk);
/**
* @brief : Gets clock information from dtsi
*
* This function extracts the clocks information for a specific
* i2c device
*
* @param dev : i2c device to get clocks information
* @param clk_info : Pointer to populate clock information array
* @param clk_ptr : Pointer to populate clock resource pointers
* @param num_clk: Pointer to populate the number of clocks
* extracted from dtsi
*
* @return Status of operation. Negative in case of error. Zero otherwise.
*/
int msm_camera_i2c_dev_get_clk_info(struct device *dev,
struct msm_cam_clk_info **clk_info,
struct clk ***clk_ptr,
size_t *num_clk);
/**
* @brief : Gets clock information and rates from dtsi
*
* This function extracts the clocks information for a specific
* platform device
*
* @param pdev : Platform device to get clocks information
* @param clk_info : Pointer to populate clock information array
* @param clk_ptr : Pointer to populate clock resource pointers
* @param clk_rates : Pointer to populate clock rates
* @param num_set: Pointer to populate the number of sets of rates
* @param num_clk: Pointer to populate the number of clocks
* extracted from dtsi
*
* @return Status of operation. Negative in case of error. Zero otherwise.
*/
int msm_camera_get_clk_info_and_rates(
struct platform_device *pdev,
struct msm_cam_clk_info **clk_info,
struct clk ***clk_ptr,
uint32_t ***clk_rates,
size_t *num_set,
size_t *num_clk);
/**
* @brief : Puts clock information
*
* This function releases the memory allocated for the clocks
*
* @param pdev : Pointer to platform device
* @param clk_info : Pointer to release the allocated memory
* @param clk_ptr : Pointer to release the clock resources
* @param cnt : Number of clk resources
*
* @return Status of operation. Negative in case of error. Zero otherwise.
*/
int msm_camera_put_clk_info(struct platform_device *pdev,
struct msm_cam_clk_info **clk_info,
struct clk ***clk_ptr, int cnt);
/**
* @brief : Puts clock information
*
* This function releases the memory allocated for the clocks
*
* @param dev : Pointer to i2c device
* @param clk_info : Pointer to release the allocated memory
* @param clk_ptr : Pointer to release the clock resources
* @param cnt : Number of clk resources
*
* @return Status of operation. Negative in case of error. Zero otherwise.
*/
int msm_camera_i2c_dev_put_clk_info(struct device *dev,
struct msm_cam_clk_info **clk_info,
struct clk ***clk_ptr, int cnt);
/**
* @brief : Puts clock information
*
* This function releases the memory allocated for the clocks
*
* @param pdev : Pointer to platform device
* @param clk_info : Pointer to release the allocated memory
* @param clk_ptr : Pointer to release the clock resources
* @param clk_ptr : Pointer to release the clock rates
* @param set : Number of sets of clock rates
* @param cnt : Number of clk resources
*
* @return Status of operation. Negative in case of error. Zero otherwise.
*/
int msm_camera_put_clk_info_and_rates(struct platform_device *pdev,
struct msm_cam_clk_info **clk_info,
struct clk ***clk_ptr, uint32_t ***clk_rates,
size_t set, size_t cnt);
/**
* @brief : Enable clocks
*
* This function enables the clocks for a specified device
*
* @param dev : Device to get clocks information
* @param clk_info : Pointer to populate clock information
* @param clk_ptr : Pointer to populate clock information
* @param num_clk: Pointer to populate the number of clocks
* extracted from dtsi
* @param enable : Flag to specify enable/disable
*
* @return Status of operation. Negative in case of error. Zero otherwise.
*/
int msm_camera_clk_enable(struct device *dev,
struct msm_cam_clk_info *clk_info,
struct clk **clk_ptr,
int num_clk,
int enable);
/**
* @brief : Set clock rate
*
* This function sets the rate for a specified clock and
* returns the rounded value
*
* @param dev : Device to get clocks information
* @param clk : Pointer to clock to set rate
* @param clk_rate : Rate to be set
*
* @return Status of operation. Negative in case of error. clk rate otherwise.
*/
long msm_camera_clk_set_rate(struct device *dev,
struct clk *clk,
long clk_rate);
/**
* @brief : Gets regulator info
*
* This function extracts the regulator information for a specific
* platform device
*
* @param pdev : platform device to get regulator information
* @param vdd_info: Pointer to populate the regulator names
* @param num_reg: Pointer to populate the number of regulators
* extracted from dtsi
*
* @return Status of operation. Negative in case of error. Zero otherwise.
*/
int msm_camera_get_regulator_info(struct platform_device *pdev,
struct msm_cam_regulator **vdd_info, int *num_reg);
/**
* @brief : Enable/Disable the regultors
*
* This function enables/disables the regulators for a specific
* platform device
*
* @param vdd_info: Pointer to list of regulators
* @param cnt: Number of regulators to enable/disable
* @param enable: Flags specifies either enable/disable
*
* @return Status of operation. Negative in case of error. Zero otherwise.
*/
int msm_camera_regulator_enable(struct msm_cam_regulator *vdd_info,
int cnt, int enable);
/**
* @brief : Release the regulators
*
* This function releases the regulator resources.
*
* @param pdev: Pointer to platform device
* @param vdd_info: Pointer to list of regulators
* @param cnt: Number of regulators to release
*/
void msm_camera_put_regulators(struct platform_device *pdev,
struct msm_cam_regulator **vdd_info, int cnt);
/**
* @brief : Get the IRQ resource
*
* This function gets the irq resource from dtsi for a specific
* platform device
*
* @param pdev : Platform device to get IRQ
* @param irq_name: Name of the IRQ resource to get from DTSI
*
* @return Pointer to resource if success else null
*/
struct resource *msm_camera_get_irq(struct platform_device *pdev,
char *irq_name);
/**
* @brief : Register the IRQ
*
* This function registers the irq resource for specified hardware
*
* @param pdev : Platform device to register IRQ resource
* @param irq : IRQ resource
* @param handler : IRQ handler
* @param irqflags : IRQ flags
* @param irq_name: Name of the IRQ
* @param dev : Token of the device
*
* @return Status of operation. Negative in case of error. Zero otherwise.
*/
int msm_camera_register_irq(struct platform_device *pdev,
struct resource *irq,
irq_handler_t handler,
unsigned long irqflags,
char *irq_name,
void *dev);
/**
* @brief : Register the threaded IRQ
*
* This function registers the irq resource for specified hardware
*
* @param pdev : Platform device to register IRQ resource
* @param irq : IRQ resource
* @param handler_fn : IRQ handler function
* @param thread_fn : thread handler function
* @param irqflags : IRQ flags
* @param irq_name: Name of the IRQ
* @param dev : Token of the device
*
* @return Status of operation. Negative in case of error. Zero otherwise.
*/
int msm_camera_register_threaded_irq(struct platform_device *pdev,
struct resource *irq,
irq_handler_t handler_fn,
irq_handler_t thread_fn,
unsigned long irqflags,
const char *irq_name,
void *dev);
/**
* @brief : Enable/Disable the IRQ
*
* This function enables or disables a specific IRQ
*
* @param irq : IRQ resource
* @param flag : flag to enable/disable
*
* @return Status of operation. Negative in case of error. Zero otherwise.
*/
int msm_camera_enable_irq(struct resource *irq, int flag);
/**
* @brief : UnRegister the IRQ
*
* This function Unregisters/Frees the irq resource
*
* @param pdev : Pointer to platform device
* @param irq : IRQ resource
* @param dev : Token of the device
*
* @return Status of operation. Negative in case of error. Zero otherwise.
*/
int msm_camera_unregister_irq(struct platform_device *pdev,
struct resource *irq, void *dev_id);
/**
* @brief : Gets device register base
*
* This function extracts the device's register base from the dtsi
* for the specified platform device
*
* @param pdev : Platform device to get regulator infor
* @param device_name : Name of the device to fetch the register base
* @param reserve_mem : Flag to decide whether to reserve memory
* region or not.
*
* @return Pointer to resource if success else null
*/
void __iomem *msm_camera_get_reg_base(struct platform_device *pdev,
char *device_name, int reserve_mem);
/**
* @brief : Puts device register base
*
* This function releases the memory region for the specified
* resource
*
* @param pdev : Pointer to platform device
* @param base : Pointer to base to unmap
* @param device_name : Device name
* @param reserve_mem : Flag to decide whether to release memory
* region or not.
*
* @return Status of operation. Negative in case of error. Zero otherwise.
*/
int msm_camera_put_reg_base(struct platform_device *pdev, void __iomem *base,
char *device_name, int reserve_mem);
/**
* @brief : Register the bus client
*
* This function registers the bus client
*
* @param pdev : Pointer to platform device
* @param id : client identifier
*
* @return Status of operation. Negative in case of error. Zero otherwise.
*/
uint32_t msm_camera_register_bus_client(struct platform_device *pdev,
enum cam_bus_client id);
/**
* @brief : Update bus vector
*
* This function votes for the specified vector to the bus
*
* @param id : client identifier
* @param vector_index : vector index to register
*
* @return Status of operation. Negative in case of error. Zero otherwise.
*/
uint32_t msm_camera_update_bus_vector(enum cam_bus_client id,
int vector_index);
/**
* @brief : Update the bus bandwidth
*
* This function updates the bandwidth for the specific client
*
* @param client_id : client identifier
* @param ab : Asolute bandwidth
* @param ib : Instantaneous bandwidth
*
* @return non-zero as client id if success else fail
*/
uint32_t msm_camera_update_bus_bw(int id, uint64_t ab, uint64_t ib);
/**
* @brief : UnRegister the bus client
*
* This function unregisters the bus client
*
* @param id : client identifier
*
* @return Status of operation. Negative in case of error. Zero otherwise.
*/
uint32_t msm_camera_unregister_bus_client(enum cam_bus_client id);
/**
* @brief : Gets resource size
*
* This function returns the size of the resource for the
* specified platform device
*
* @param pdev : Platform device to get regulator infor
* @param device_name : Name of the device to fetch the register base
*
* @return size of the resource
*/
uint32_t msm_camera_get_res_size(struct platform_device *pdev,
char *device_name);
#endif

View file

@ -0,0 +1,851 @@
/* Copyright (c) 2011-2017, 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/gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/io.h>
#include <linux/err.h>
#include <soc/qcom/ais.h>
#include <linux/msm-bus.h>
#include "msm_camera_io_util.h"
#define BUFF_SIZE_128 128
#undef CDBG
#define CDBG(fmt, args...) pr_debug(fmt, ##args)
void msm_camera_io_w(u32 data, void __iomem *addr)
{
CDBG("%s: 0x%pK %08x\n", __func__, (addr), (data));
writel_relaxed((data), (addr));
}
/* This API is to write a block of data
* to same address
*/
int32_t msm_camera_io_w_block(const u32 *addr, void __iomem *base,
u32 len)
{
int i;
if (!addr || !len || !base)
return -EINVAL;
for (i = 0; i < len; i++) {
CDBG("%s: len =%d val=%x base =%pK\n", __func__,
len, addr[i], base);
writel_relaxed(addr[i], base);
}
return 0;
}
/* This API is to write a block of registers
* which is like a 2 dimensional array table with
* register offset and data
*/
int32_t msm_camera_io_w_reg_block(const u32 *addr, void __iomem *base,
u32 len)
{
int i;
if (!addr || !len || !base)
return -EINVAL;
for (i = 0; i < len; i = i + 2) {
CDBG("%s: len =%d val=%x base =%pK reg=%x\n", __func__,
len, addr[i + 1], base, addr[i]);
writel_relaxed(addr[i + 1], base + addr[i]);
}
return 0;
}
void msm_camera_io_w_mb(u32 data, void __iomem *addr)
{
CDBG("%s: 0x%pK %08x\n", __func__, (addr), (data));
/* ensure write is done */
wmb();
writel_relaxed((data), (addr));
/* ensure write is done */
wmb();
}
int32_t msm_camera_io_w_mb_block(const u32 *addr, void __iomem *base, u32 len)
{
int i;
if (!addr || !len || !base)
return -EINVAL;
for (i = 0; i < len; i++) {
/* ensure write is done */
wmb();
CDBG("%s: len =%d val=%x base =%pK\n", __func__,
len, addr[i], base);
writel_relaxed(addr[i], base);
}
/* ensure last write is done */
wmb();
return 0;
}
u32 msm_camera_io_r(void __iomem *addr)
{
uint32_t data = readl_relaxed(addr);
CDBG("%s: 0x%pK %08x\n", __func__, (addr), (data));
return data;
}
u32 msm_camera_io_r_mb(void __iomem *addr)
{
uint32_t data;
/* ensure read is done */
rmb();
data = readl_relaxed(addr);
/* ensure read is done */
rmb();
CDBG("%s: 0x%pK %08x\n", __func__, (addr), (data));
return data;
}
void msm_camera_io_memcpy_toio(void __iomem *dest_addr,
void __iomem *src_addr, u32 len)
{
int i;
u32 *d = (u32 *) dest_addr;
u32 *s = (u32 *) src_addr;
for (i = 0; i < len; i++)
writel_relaxed(*s++, d++);
}
int32_t msm_camera_io_poll_value(void __iomem *addr, u32 wait_data, u32 retry,
unsigned long min_usecs, unsigned long max_usecs)
{
uint32_t tmp, cnt = 0;
int32_t rc = 0;
if (!addr)
return -EINVAL;
tmp = msm_camera_io_r(addr);
while ((tmp != wait_data) && (cnt++ < retry)) {
if (min_usecs > 0 && max_usecs > 0)
usleep_range(min_usecs, max_usecs);
tmp = msm_camera_io_r(addr);
}
if (cnt > retry) {
pr_debug("Poll failed by value\n");
rc = -EINVAL;
}
return rc;
}
int32_t msm_camera_io_poll_value_wmask(void __iomem *addr, u32 wait_data,
u32 bmask, u32 retry, unsigned long min_usecs, unsigned long max_usecs)
{
uint32_t tmp, cnt = 0;
int32_t rc = 0;
if (!addr)
return -EINVAL;
tmp = msm_camera_io_r(addr);
while (((tmp & bmask) != wait_data) && (cnt++ < retry)) {
if (min_usecs > 0 && max_usecs > 0)
usleep_range(min_usecs, max_usecs);
tmp = msm_camera_io_r(addr);
}
if (cnt > retry) {
pr_debug("Poll failed with mask\n");
rc = -EINVAL;
}
return rc;
}
void msm_camera_io_dump(void __iomem *addr, int size, int enable)
{
char line_str[128], *p_str;
int i;
u32 *p = (u32 *) addr;
u32 data;
CDBG("%s: addr=%pK size=%d\n", __func__, addr, size);
if (!p || (size <= 0) || !enable)
return;
line_str[0] = '\0';
p_str = line_str;
for (i = 0; i < size/4; i++) {
if (i % 4 == 0) {
#ifdef CONFIG_COMPAT
snprintf(p_str, 20, "%016lx: ", (unsigned long) p);
p_str += 18;
#else
snprintf(p_str, 12, "%08lx: ", (unsigned long) p);
p_str += 10;
#endif
}
data = readl_relaxed(p++);
snprintf(p_str, 12, "%08x ", data);
p_str += 9;
if ((i + 1) % 4 == 0) {
pr_err("%s\n", line_str);
line_str[0] = '\0';
p_str = line_str;
}
}
if (line_str[0] != '\0')
pr_err("%s\n", line_str);
}
void msm_camera_io_dump_wstring_base(void __iomem *addr,
struct msm_cam_dump_string_info *dump_data,
int size)
{
int i, u = sizeof(struct msm_cam_dump_string_info);
pr_debug("%s: addr=%pK data=%pK size=%d u=%d, cnt=%d\n", __func__,
addr, dump_data, size, u,
(size/u));
if (!addr || (size <= 0) || !dump_data) {
pr_err("%s: addr=%pK data=%pK size=%d\n", __func__,
addr, dump_data, size);
return;
}
for (i = 0; i < (size / u); i++)
pr_debug("%s 0x%x\n", (dump_data + i)->print,
readl_relaxed((dump_data + i)->offset + addr));
}
void msm_camera_io_memcpy(void __iomem *dest_addr,
void __iomem *src_addr, u32 len)
{
CDBG("%s: %pK %pK %d\n", __func__, dest_addr, src_addr, len);
msm_camera_io_memcpy_toio(dest_addr, src_addr, len / 4);
}
void msm_camera_io_memcpy_mb(void __iomem *dest_addr,
void __iomem *src_addr, u32 len)
{
int i;
u32 *d = (u32 *) dest_addr;
u32 *s = (u32 *) src_addr;
/* This is generic function called who needs to register
* writes with memory barrier
*/
wmb();
for (i = 0; i < (len / 4); i++) {
msm_camera_io_w(*s++, d++);
/* ensure write is done after every iteration */
wmb();
}
}
int msm_cam_clk_sel_src(struct device *dev, struct msm_cam_clk_info *clk_info,
struct msm_cam_clk_info *clk_src_info, int num_clk)
{
int i;
int rc = 0;
struct clk *mux_clk = NULL;
struct clk *src_clk = NULL;
for (i = 0; i < num_clk; i++) {
if (clk_src_info[i].clk_name) {
mux_clk = clk_get(dev, clk_info[i].clk_name);
if (IS_ERR(mux_clk)) {
pr_err("%s get failed\n",
clk_info[i].clk_name);
continue;
}
src_clk = clk_get(dev, clk_src_info[i].clk_name);
if (IS_ERR(src_clk)) {
pr_err("%s get failed\n",
clk_src_info[i].clk_name);
continue;
}
clk_set_parent(mux_clk, src_clk);
}
}
return rc;
}
int msm_cam_clk_enable(struct device *dev, struct msm_cam_clk_info *clk_info,
struct clk **clk_ptr, int num_clk, int enable)
{
int i;
int rc = 0;
long clk_rate;
if (enable) {
for (i = 0; i < num_clk; i++) {
CDBG("%s enable %s\n", __func__, clk_info[i].clk_name);
clk_ptr[i] = clk_get(dev, clk_info[i].clk_name);
if (IS_ERR(clk_ptr[i])) {
pr_err("%s get failed\n", clk_info[i].clk_name);
rc = PTR_ERR(clk_ptr[i]);
goto cam_clk_get_err;
}
if (clk_info[i].clk_rate > 0) {
clk_rate = clk_round_rate(clk_ptr[i],
clk_info[i].clk_rate);
if (clk_rate < 0) {
pr_err("%s round failed\n",
clk_info[i].clk_name);
goto cam_clk_set_err;
}
rc = clk_set_rate(clk_ptr[i],
clk_rate);
if (rc < 0) {
pr_err("%s set failed\n",
clk_info[i].clk_name);
goto cam_clk_set_err;
}
} else if (clk_info[i].clk_rate == INIT_RATE) {
clk_rate = clk_get_rate(clk_ptr[i]);
if (clk_rate == 0) {
clk_rate =
clk_round_rate(clk_ptr[i], 0);
if (clk_rate < 0) {
pr_err("%s round rate failed\n",
clk_info[i].clk_name);
goto cam_clk_set_err;
}
rc = clk_set_rate(clk_ptr[i],
clk_rate);
if (rc < 0) {
pr_err("%s set rate failed\n",
clk_info[i].clk_name);
goto cam_clk_set_err;
}
}
}
rc = clk_prepare(clk_ptr[i]);
if (rc < 0) {
pr_err("%s prepare failed\n",
clk_info[i].clk_name);
goto cam_clk_prepare_err;
}
rc = clk_enable(clk_ptr[i]);
if (rc < 0) {
pr_err("%s enable failed\n",
clk_info[i].clk_name);
goto cam_clk_enable_err;
}
if (clk_info[i].delay > 20) {
msleep(clk_info[i].delay);
} else if (clk_info[i].delay) {
usleep_range(clk_info[i].delay * 1000,
(clk_info[i].delay * 1000) + 1000);
}
}
} else {
for (i = num_clk - 1; i >= 0; i--) {
if (clk_ptr[i] != NULL) {
CDBG("%s disable %s\n", __func__,
clk_info[i].clk_name);
clk_disable(clk_ptr[i]);
clk_unprepare(clk_ptr[i]);
clk_put(clk_ptr[i]);
}
}
}
return rc;
cam_clk_enable_err:
clk_unprepare(clk_ptr[i]);
cam_clk_prepare_err:
cam_clk_set_err:
clk_put(clk_ptr[i]);
cam_clk_get_err:
for (i--; i >= 0; i--) {
if (clk_ptr[i] != NULL) {
clk_disable(clk_ptr[i]);
clk_unprepare(clk_ptr[i]);
clk_put(clk_ptr[i]);
}
}
return rc;
}
int msm_camera_config_vreg(struct device *dev, struct camera_vreg_t *cam_vreg,
int num_vreg, enum msm_camera_vreg_name_t *vreg_seq,
int num_vreg_seq, struct regulator **reg_ptr, int config)
{
int i = 0, j = 0;
int rc = 0;
struct camera_vreg_t *curr_vreg;
if (num_vreg_seq > num_vreg) {
pr_err("%s:%d vreg sequence invalid\n", __func__, __LINE__);
return -EINVAL;
}
if (!num_vreg_seq)
num_vreg_seq = num_vreg;
if ((cam_vreg == NULL) && num_vreg_seq) {
pr_err("%s:%d cam_vreg NULL\n", __func__, __LINE__);
return -EINVAL;
}
if (config) {
for (i = 0; i < num_vreg_seq; i++) {
if (vreg_seq) {
j = vreg_seq[i];
if (j >= num_vreg)
continue;
} else
j = i;
curr_vreg = &cam_vreg[j];
reg_ptr[j] = regulator_get(dev,
curr_vreg->reg_name);
if (IS_ERR(reg_ptr[j])) {
pr_err("%s: %s get failed\n",
__func__,
curr_vreg->reg_name);
reg_ptr[j] = NULL;
goto vreg_get_fail;
}
if (regulator_count_voltages(reg_ptr[j]) > 0) {
rc = regulator_set_voltage(
reg_ptr[j],
curr_vreg->min_voltage,
curr_vreg->max_voltage);
if (rc < 0) {
pr_err("%s: %s set voltage failed\n",
__func__,
curr_vreg->reg_name);
goto vreg_set_voltage_fail;
}
if (curr_vreg->op_mode >= 0) {
rc = regulator_set_load(
reg_ptr[j],
curr_vreg->op_mode);
rc = 0;
if (rc < 0) {
pr_err(
"%s:%s set optimum mode fail\n",
__func__,
curr_vreg->reg_name);
goto vreg_set_opt_mode_fail;
}
}
}
}
} else {
for (i = num_vreg_seq-1; i >= 0; i--) {
if (vreg_seq) {
j = vreg_seq[i];
if (j >= num_vreg)
continue;
} else
j = i;
curr_vreg = &cam_vreg[j];
if (reg_ptr[j]) {
if (regulator_count_voltages(reg_ptr[j]) > 0) {
if (curr_vreg->op_mode >= 0) {
regulator_set_load(
reg_ptr[j], 0);
}
regulator_set_voltage(
reg_ptr[j], 0, curr_vreg->
max_voltage);
}
regulator_put(reg_ptr[j]);
reg_ptr[j] = NULL;
}
}
}
return 0;
vreg_unconfig:
if (regulator_count_voltages(reg_ptr[j]) > 0)
regulator_set_load(reg_ptr[j], 0);
vreg_set_opt_mode_fail:
if (regulator_count_voltages(reg_ptr[j]) > 0)
regulator_set_voltage(reg_ptr[j], 0,
curr_vreg->max_voltage);
vreg_set_voltage_fail:
regulator_put(reg_ptr[j]);
reg_ptr[j] = NULL;
vreg_get_fail:
for (i--; i >= 0; i--) {
if (vreg_seq) {
j = vreg_seq[i];
if (j >= num_vreg)
continue;
} else
j = i;
curr_vreg = &cam_vreg[j];
goto vreg_unconfig;
}
return -ENODEV;
}
int msm_camera_enable_vreg(struct device *dev, struct camera_vreg_t *cam_vreg,
int num_vreg, enum msm_camera_vreg_name_t *vreg_seq,
int num_vreg_seq, struct regulator **reg_ptr, int enable)
{
int i = 0, j = 0, rc = 0;
if (num_vreg_seq > num_vreg) {
pr_err("%s:%d vreg sequence invalid\n", __func__, __LINE__);
return -EINVAL;
}
if (!num_vreg_seq)
num_vreg_seq = num_vreg;
if (enable) {
for (i = 0; i < num_vreg_seq; i++) {
if (vreg_seq) {
j = vreg_seq[i];
if (j >= num_vreg)
continue;
} else
j = i;
if (IS_ERR(reg_ptr[j])) {
pr_err("%s: %s null regulator\n",
__func__, cam_vreg[j].reg_name);
goto disable_vreg;
}
rc = regulator_enable(reg_ptr[j]);
if (rc < 0) {
pr_err("%s: %s enable failed\n",
__func__, cam_vreg[j].reg_name);
goto disable_vreg;
}
if (cam_vreg[j].delay > 20)
msleep(cam_vreg[j].delay);
else if (cam_vreg[j].delay)
usleep_range(cam_vreg[j].delay * 1000,
(cam_vreg[j].delay * 1000) + 1000);
}
} else {
for (i = num_vreg_seq-1; i >= 0; i--) {
if (vreg_seq) {
j = vreg_seq[i];
if (j >= num_vreg)
continue;
} else
j = i;
regulator_disable(reg_ptr[j]);
if (cam_vreg[j].delay > 20)
msleep(cam_vreg[j].delay);
else if (cam_vreg[j].delay)
usleep_range(cam_vreg[j].delay * 1000,
(cam_vreg[j].delay * 1000) + 1000);
}
}
return rc;
disable_vreg:
for (i--; i >= 0; i--) {
if (vreg_seq) {
j = vreg_seq[i];
if (j >= num_vreg)
continue;
} else
j = i;
regulator_disable(reg_ptr[j]);
if (cam_vreg[j].delay > 20)
msleep(cam_vreg[j].delay);
else if (cam_vreg[j].delay)
usleep_range(cam_vreg[j].delay * 1000,
(cam_vreg[j].delay * 1000) + 1000);
}
return rc;
}
void msm_camera_bus_scale_cfg(uint32_t bus_perf_client,
enum msm_bus_perf_setting perf_setting)
{
int rc = 0;
if (!bus_perf_client) {
pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
return;
}
switch (perf_setting) {
case S_EXIT:
rc = msm_bus_scale_client_update_request(bus_perf_client, 1);
msm_bus_scale_unregister_client(bus_perf_client);
break;
case S_PREVIEW:
rc = msm_bus_scale_client_update_request(bus_perf_client, 1);
break;
case S_VIDEO:
rc = msm_bus_scale_client_update_request(bus_perf_client, 2);
break;
case S_CAPTURE:
rc = msm_bus_scale_client_update_request(bus_perf_client, 3);
break;
case S_ZSL:
rc = msm_bus_scale_client_update_request(bus_perf_client, 4);
break;
case S_LIVESHOT:
rc = msm_bus_scale_client_update_request(bus_perf_client, 5);
break;
case S_DEFAULT:
break;
default:
pr_err("%s: INVALID CASE\n", __func__);
}
}
int msm_camera_set_gpio_table(struct msm_gpio_set_tbl *gpio_tbl,
uint8_t gpio_tbl_size, int gpio_en)
{
int rc = 0, i;
if (gpio_en) {
for (i = 0; i < gpio_tbl_size; i++) {
gpio_set_value_cansleep(gpio_tbl[i].gpio,
gpio_tbl[i].flags);
usleep_range(gpio_tbl[i].delay,
gpio_tbl[i].delay + 1000);
}
} else {
for (i = gpio_tbl_size - 1; i >= 0; i--) {
if (gpio_tbl[i].flags)
gpio_set_value_cansleep(gpio_tbl[i].gpio,
GPIOF_OUT_INIT_LOW);
}
}
return rc;
}
int msm_camera_config_single_vreg(struct device *dev,
struct camera_vreg_t *cam_vreg, struct regulator **reg_ptr, int config)
{
int rc = 0;
const char *vreg_name = NULL;
if (!dev || !cam_vreg || !reg_ptr) {
pr_err("%s: get failed NULL parameter\n", __func__);
goto vreg_get_fail;
}
if (cam_vreg->type == VREG_TYPE_CUSTOM) {
if (cam_vreg->custom_vreg_name == NULL) {
pr_err("%s : can't find sub reg name",
__func__);
goto vreg_get_fail;
}
vreg_name = cam_vreg->custom_vreg_name;
} else {
if (cam_vreg->reg_name == NULL) {
pr_err("%s : can't find reg name", __func__);
goto vreg_get_fail;
}
vreg_name = cam_vreg->reg_name;
}
if (config) {
CDBG("%s enable %s\n", __func__, vreg_name);
*reg_ptr = regulator_get(dev, vreg_name);
if (IS_ERR(*reg_ptr)) {
pr_err("%s: %s get failed\n", __func__, vreg_name);
*reg_ptr = NULL;
goto vreg_get_fail;
}
if (regulator_count_voltages(*reg_ptr) > 0) {
CDBG("%s: voltage min=%d, max=%d\n",
__func__, cam_vreg->min_voltage,
cam_vreg->max_voltage);
rc = regulator_set_voltage(
*reg_ptr, cam_vreg->min_voltage,
cam_vreg->max_voltage);
if (rc < 0) {
pr_err("%s: %s set voltage failed\n",
__func__, vreg_name);
goto vreg_set_voltage_fail;
}
if (cam_vreg->op_mode >= 0) {
rc = regulator_set_load(*reg_ptr,
cam_vreg->op_mode);
if (rc < 0) {
pr_err(
"%s: %s set optimum mode failed\n",
__func__, vreg_name);
goto vreg_set_opt_mode_fail;
}
}
}
rc = regulator_enable(*reg_ptr);
if (rc < 0) {
pr_err("%s: %s regulator_enable failed\n", __func__,
vreg_name);
goto vreg_unconfig;
}
} else {
CDBG("%s disable %s\n", __func__, vreg_name);
if (*reg_ptr) {
CDBG("%s disable %s\n", __func__, vreg_name);
regulator_disable(*reg_ptr);
if (regulator_count_voltages(*reg_ptr) > 0) {
if (cam_vreg->op_mode >= 0)
regulator_set_load(*reg_ptr, 0);
regulator_set_voltage(
*reg_ptr, 0, cam_vreg->max_voltage);
}
regulator_put(*reg_ptr);
*reg_ptr = NULL;
} else {
pr_err("%s can't disable %s\n", __func__, vreg_name);
}
}
return 0;
vreg_unconfig:
if (regulator_count_voltages(*reg_ptr) > 0)
regulator_set_load(*reg_ptr, 0);
vreg_set_opt_mode_fail:
if (regulator_count_voltages(*reg_ptr) > 0)
regulator_set_voltage(*reg_ptr, 0, cam_vreg->max_voltage);
vreg_set_voltage_fail:
regulator_put(*reg_ptr);
*reg_ptr = NULL;
vreg_get_fail:
return -ENODEV;
}
int msm_camera_request_gpio_table(struct gpio *gpio_tbl, uint8_t size,
int gpio_en)
{
int rc = 0, i = 0, err = 0;
if (!gpio_tbl || !size) {
pr_err("%s:%d invalid gpio_tbl %pK / size %d\n", __func__,
__LINE__, gpio_tbl, size);
return -EINVAL;
}
for (i = 0; i < size; i++) {
CDBG("%s:%d i %d, gpio %d dir %ld\n", __func__, __LINE__, i,
gpio_tbl[i].gpio, gpio_tbl[i].flags);
}
if (gpio_en) {
for (i = 0; i < size; i++) {
err = gpio_request_one(gpio_tbl[i].gpio,
gpio_tbl[i].flags, gpio_tbl[i].label);
if (err) {
/*
* After GPIO request fails, contine to
* apply new gpios, outout a error message
* for driver bringup debug
*/
pr_err("%s:%d gpio %d:%s request fails\n",
__func__, __LINE__,
gpio_tbl[i].gpio, gpio_tbl[i].label);
}
}
} else {
gpio_free_array(gpio_tbl, size);
}
return rc;
}
/*
* msm_camera_get_dt_reg_settings - Get dt reg settings from device-tree.
* @of_node: Pointer to device of_node from dev.
* @dt_prop_name: String of the property to search in of_node from dev.
* @reg_s: Double pointer will be allocated by this function and filled.
* @size: Pointer to fill the length of the available entries.
*/
int msm_camera_get_dt_reg_settings(struct device_node *of_node,
const char *dt_prop_name, uint32_t **reg_s,
unsigned int *size)
{
int ret;
unsigned int cnt;
if (!of_node || !dt_prop_name || !size || !reg_s) {
pr_err("%s: Error invalid args %pK:%pK:%pK:%pK\n",
__func__, size, reg_s, of_node, dt_prop_name);
return -EINVAL;
}
if (!of_get_property(of_node, dt_prop_name, &cnt)) {
pr_debug("Missing dt reg settings for %s\n", dt_prop_name);
return -ENOENT;
}
if (!cnt || (cnt % 8)) {
pr_err("%s: Error invalid number of entries cnt=%d\n",
__func__, cnt);
return -EINVAL;
}
cnt /= 4;
if (cnt != 0) {
*reg_s = kcalloc(cnt, sizeof(uint32_t),
GFP_KERNEL);
if (!*reg_s)
return -ENOMEM;
ret = of_property_read_u32_array(of_node,
dt_prop_name,
*reg_s,
cnt);
if (ret < 0) {
pr_err("%s: No dt reg info read for %s ret=%d\n",
__func__, dt_prop_name, ret);
kfree(*reg_s);
return -ENOENT;
}
*size = cnt;
} else {
pr_err("%s: Error invalid entries\n", __func__);
return -EINVAL;
}
return ret;
}
/*
* msm_camera_get_dt_reg_settings - Free dt reg settings memory.
* @reg_s: Double pointer will be allocated by this function and filled.
* @size: Pointer to set the length as invalid.
*/
void msm_camera_put_dt_reg_settings(uint32_t **reg_s,
unsigned int *size)
{
kfree(*reg_s);
*reg_s = NULL;
*size = 0;
}
int msm_camera_hw_write_dt_reg_settings(void __iomem *base,
uint32_t *reg_s,
unsigned int size)
{
int32_t rc = 0;
if (!reg_s || !base || !size) {
pr_err("%s: Error invalid args\n", __func__);
return -EINVAL;
}
rc = msm_camera_io_w_reg_block((const u32 *) reg_s,
base, size);
if (rc < 0)
pr_err("%s: Failed dt reg setting write\n", __func__);
return rc;
}

View file

@ -0,0 +1,93 @@
/* Copyright (c) 2011-2017, 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_CAMERA_IO_UTIL_H
#define __MSM_CAMERA_IO_UTIL_H
#include <linux/regulator/consumer.h>
#include <linux/gpio.h>
#include <linux/clk.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <soc/qcom/ais.h>
#include <media/ais/msm_ais_sensor.h>
#include <media/v4l2-ioctl.h>
#define NO_SET_RATE -1
#define INIT_RATE -2
struct msm_gpio_set_tbl {
unsigned gpio;
unsigned long flags;
uint32_t delay;
};
struct msm_cam_dump_string_info {
const char *print;
uint32_t offset;
};
void msm_camera_io_w(u32 data, void __iomem *addr);
void msm_camera_io_w_mb(u32 data, void __iomem *addr);
u32 msm_camera_io_r(void __iomem *addr);
u32 msm_camera_io_r_mb(void __iomem *addr);
void msm_camera_io_dump(void __iomem *addr, int size, int enable);
void msm_camera_io_memcpy(void __iomem *dest_addr,
void __iomem *src_addr, u32 len);
void msm_camera_io_memcpy_mb(void __iomem *dest_addr,
void __iomem *src_addr, u32 len);
int msm_cam_clk_sel_src(struct device *dev, struct msm_cam_clk_info *clk_info,
struct msm_cam_clk_info *clk_src_info, int num_clk);
int msm_cam_clk_enable(struct device *dev, struct msm_cam_clk_info *clk_info,
struct clk **clk_ptr, int num_clk, int enable);
int msm_camera_config_vreg(struct device *dev, struct camera_vreg_t *cam_vreg,
int num_vreg, enum msm_camera_vreg_name_t *vreg_seq,
int num_vreg_seq, struct regulator **reg_ptr, int config);
int msm_camera_enable_vreg(struct device *dev, struct camera_vreg_t *cam_vreg,
int num_vreg, enum msm_camera_vreg_name_t *vreg_seq,
int num_vreg_seq, struct regulator **reg_ptr, int enable);
void msm_camera_bus_scale_cfg(uint32_t bus_perf_client,
enum msm_bus_perf_setting perf_setting);
int msm_camera_set_gpio_table(struct msm_gpio_set_tbl *gpio_tbl,
uint8_t gpio_tbl_size, int gpio_en);
void msm_camera_config_single_gpio(uint16_t gpio, unsigned long flags,
int gpio_en);
int msm_camera_config_single_vreg(struct device *dev,
struct camera_vreg_t *cam_vreg, struct regulator **reg_ptr, int config);
int msm_camera_request_gpio_table(struct gpio *gpio_tbl, uint8_t size,
int gpio_en);
void msm_camera_io_dump_wstring_base(void __iomem *addr,
struct msm_cam_dump_string_info *dump_data,
int size);
int32_t msm_camera_io_poll_value_wmask(void __iomem *addr, u32 wait_data,
u32 bmask, u32 retry, unsigned long min_usecs,
unsigned long max_usecs);
int32_t msm_camera_io_poll_value(void __iomem *addr, u32 wait_data, u32 retry,
unsigned long min_usecs, unsigned long max_usecs);
int32_t msm_camera_io_w_block(const u32 *addr, void __iomem *base, u32 len);
int32_t msm_camera_io_w_reg_block(const u32 *addr, void __iomem *base, u32 len);
int32_t msm_camera_io_w_mb_block(const u32 *addr, void __iomem *base, u32 len);
int msm_camera_get_dt_reg_settings(struct device_node *of_node,
const char *dt_prop_name, uint32_t **reg_s,
unsigned int *size);
void msm_camera_put_dt_reg_settings(uint32_t **reg_s,
unsigned int *size);
int msm_camera_hw_write_dt_reg_settings(void __iomem *base,
uint32_t *reg_s,
unsigned int size);
#endif

View file

@ -0,0 +1,8 @@
GCC_VERSION := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc)
ccflags-y += -Idrivers/media/video/msm
ccflags-y += -Idrivers/media/platform/msm/ais/common
ccflags-y += -Idrivers/media/platform/msm/ais
ccflags-y += -Idrivers/media/platform/msm/ais/pproc/cpp
ccflags-y += -Idrivers/media/platform/msm/ais/msm_buf_mgr/
obj-$(CONFIG_MSM_AIS_FD) += msm_fd_dev.o msm_fd_hw.o

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,258 @@
/* Copyright (c) 2014-2017, 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_FD_DEV_H__
#define __MSM_FD_DEV_H__
#include <media/v4l2-device.h>
#include <media/v4l2-fh.h>
#include <media/v4l2-ctrls.h>
#include <linux/msm-bus.h>
#include <media/msm_fd.h>
#include <linux/dma-buf.h>
#include <linux/msm_ion.h>
#include "cam_soc_api.h"
#include "cam_hw_ops.h"
#include "msm_cpp.h"
/* Maximum number of result buffers */
#define MSM_FD_MAX_RESULT_BUFS 5
/* Max number of clocks defined in device tree */
#define MSM_FD_MAX_CLK_NUM 15
/* Max number of clock rates defined in device tree */
#define MSM_FD_MAX_CLK_RATES 5
/* Max number of faces which can be detected in one hw processing */
#define MSM_FD_MAX_FACES_DETECTED 32
/* Max number of regulators defined in device tree */
#define MSM_FD_MAX_REGULATOR_NUM 3
/*
* struct msm_fd_size - Structure contain FD size related values.
* @width: Image width.
* @height: Image height.
* @reg_val: Register value for this size.
* @work_size: Working buffer size in bytes for this size.
*/
struct msm_fd_size {
int width;
int height;
u32 reg_val;
int work_size;
};
/*
* struct msm_fd_setings - Structure contain FD settings values.
* @min_size_index: Minimum face size array index.
* @angle_index: Face detection angle array index.
* @direction_index: Face detection direction array index.
* @threshold: Face detection threshold value.
* @speed: Face detection speed value (it should match with clock rate index).
*/
struct msm_fd_setings {
unsigned int min_size_index;
unsigned int angle_index;
unsigned int direction_index;
unsigned int threshold;
unsigned int speed;
};
/*
* struct msm_fd_format - Structure contain FD format settings.
* @size: Pointer to fd size struct used for this format.
* @crop: V4l2 crop structure.
* @bytesperline: Bytes per line of input image buffer.
* @sizeimage: Size of input image buffer.
* @pixelformat: Pixel format of input image buffer.
*/
struct msm_fd_format {
struct msm_fd_size *size;
struct v4l2_rect crop;
int bytesperline;
int sizeimage;
u32 pixelformat;
};
/*
* struct msm_fd_mem_pool - Structure contain FD memory pool information.
* @fd_device: Pointer to fd device.
* @client: Pointer to ion client.
* @domain_num: Domain number associated with FD hw.
*/
struct msm_fd_mem_pool {
struct msm_fd_device *fd_device;
};
/*
* struct msm_fd_buf_handle - Structure contain FD buffer handle information.
* @fd: ion FD from which this buffer is imported.
* @pool: Pointer to FD memory pool struct.
* @handle: Pointer to ion handle.
* @size: Size of the buffer.
* @addr: Adders of FD mmu mapped buffer. This address should be set to FD hw.
*/
struct msm_fd_buf_handle {
int fd;
struct msm_fd_mem_pool *pool;
size_t size;
ion_phys_addr_t addr;
};
/*
* struct msm_fd_buffer - Vb2 buffer wrapper structure.
* @vb: Videobuf 2 buffer structure.
* @active: Flag indicating if buffer currently used by FD hw.
* @completion: Completion need to wait on, if buffer is used by FD hw.
* @format: Format information of this buffer.
* @settings: Settings value of this buffer.
* @work_addr: Working buffer address need to be used when for this buffer.
* @list: Buffer is part of FD device processing queue
*/
struct msm_fd_buffer {
struct vb2_buffer vb;
atomic_t active;
struct completion completion;
struct msm_fd_format format;
struct msm_fd_setings settings;
ion_phys_addr_t work_addr;
struct list_head list;
};
/*
* struct msm_fd_stats - Structure contains FD result statistic information.
* @frame_id: Frame id for which statistic corresponds to.
* @face_cnt: Number of faces detected and included in face data.
* @face_data: Structure containing detected face data information.
*/
struct msm_fd_stats {
atomic_t frame_id;
u32 face_cnt;
struct msm_fd_face_data face_data[MSM_FD_MAX_FACES_DETECTED];
};
/*
* struct fd_ctx - Structure contains per open file handle context.
* @fd_device: Pointer to fd device.
* @fh: V4l2 file handle.
* @vb2_q: Videobuf 2 queue.
* @sequence: Sequence number for this statistic.
* @format: Current format.
* @settings: Current settings.
* @mem_pool: FD hw memory pool.
* @stats: Pointer to statistic buffers.
* @work_buf: Working memory buffer handle.
*/
struct fd_ctx {
struct msm_fd_device *fd_device;
struct v4l2_fh fh;
struct vb2_queue vb2_q;
unsigned int sequence;
atomic_t subscribed_for_event;
struct msm_fd_format format;
struct msm_fd_setings settings;
struct msm_fd_mem_pool mem_pool;
struct msm_fd_stats *stats;
struct msm_fd_buf_handle work_buf;
};
/*
* enum msm_fd_device_state - FD device state.
* @MSM_FD_DEVICE_IDLE: Device is idle, we can start with processing.
* @MSM_FD_DEVICE_RUNNING: Device is running, next processing will be
* scheduled from fd irq.
*/
enum msm_fd_device_state {
MSM_FD_DEVICE_IDLE,
MSM_FD_DEVICE_RUNNING,
};
/*
* enum msm_fd_mem_resources - FD device iomem resources.
* @MSM_FD_IOMEM_CORE: Index of fd core registers.
* @MSM_FD_IOMEM_MISC: Index of fd misc registers.
* @MSM_FD_IOMEM_VBIF: Index of fd vbif registers.
* @MSM_FD_IOMEM_LAST: Not valid.
*/
enum msm_fd_mem_resources {
MSM_FD_IOMEM_CORE,
MSM_FD_IOMEM_MISC,
MSM_FD_IOMEM_VBIF,
MSM_FD_IOMEM_LAST
};
/*
* struct msm_fd_device - FD device structure.
* @hw_revision: Face detection hw revision.
* @lock: Lock used for reference count.
* @slock: Spinlock used to protect FD device struct.
* @irq_num: Face detection irq number.
* @ref_count: Device reference count.
* @res_mem: Array of memory resources used by FD device.
* @iomem_base: Array of register mappings used by FD device.
* @vdd: Pointer to vdd regulator.
* @clk_num: Number of clocks attached to the device.
* @clk: Array of clock resources used by fd device.
* @clk_rates: Array of clock rates set.
* @bus_vectors: Pointer to bus vectors array.
* @bus_paths: Pointer to bus paths array.
* @bus_scale_data: Memory access bus scale data.
* @bus_client: Memory access bus client.
* @iommu_attached_cnt: Iommu attached devices reference count.
* @iommu_hdl: reference for iommu context.
* @dev: Pointer to device struct.
* @v4l2_dev: V4l2 device.
* @video: Video device.
* @state: FD device state.
* @buf_queue: FD device processing queue.
* @work_queue: Pointer to FD device IRQ bottom half workqueue.
* @work: IRQ bottom half work struct.
* @hw_halt_completion: Completes when face detection hw halt completes.
* @recovery_mode: Indicates if FD is in recovery mode
*/
struct msm_fd_device {
u32 hw_revision;
struct mutex lock;
spinlock_t slock;
struct mutex recovery_lock;
int ref_count;
int irq_num;
void __iomem *iomem_base[MSM_FD_IOMEM_LAST];
struct msm_cam_clk_info *clk_info;
struct msm_cam_regulator *vdd_info;
int num_reg;
struct resource *irq;
size_t clk_num;
size_t clk_rates_num;
struct clk **clk;
uint32_t **clk_rates;
uint32_t bus_client;
unsigned int iommu_attached_cnt;
int iommu_hdl;
struct device *dev;
struct platform_device *pdev;
struct v4l2_device v4l2_dev;
struct video_device video;
enum msm_fd_device_state state;
struct list_head buf_queue;
struct workqueue_struct *work_queue;
struct work_struct work;
struct completion hw_halt_completion;
int recovery_mode;
uint32_t clk_rate_idx;
};
#endif /* __MSM_FD_DEV_H__ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,82 @@
/* Copyright (c) 2014-2017, 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_FD_HW_H__
#define __MSM_FD_HW_H__
#include "msm_fd_dev.h"
int msm_fd_hw_get_face_count(struct msm_fd_device *fd);
int msm_fd_hw_get_result_x(struct msm_fd_device *fd, int idx);
int msm_fd_hw_get_result_y(struct msm_fd_device *fd, int idx);
void msm_fd_hw_get_result_conf_size(struct msm_fd_device *fd,
int idx, u32 *conf, u32 *size);
void msm_fd_hw_get_result_angle_pose(struct msm_fd_device *fd, int idx,
u32 *angle, u32 *pose);
int msm_fd_hw_request_irq(struct platform_device *pdev,
struct msm_fd_device *fd, work_func_t work_func);
void msm_fd_hw_release_irq(struct msm_fd_device *fd);
int msm_fd_hw_get_revision(struct msm_fd_device *fd);
void msm_fd_hw_release_mem_resources(struct msm_fd_device *fd);
int msm_fd_hw_get_mem_resources(struct platform_device *pdev,
struct msm_fd_device *fd);
int msm_fd_hw_get_iommu(struct msm_fd_device *fd);
void msm_fd_hw_put_iommu(struct msm_fd_device *fd);
int msm_fd_hw_get_regulators(struct msm_fd_device *fd);
int msm_fd_hw_put_regulators(struct msm_fd_device *fd);
int msm_fd_hw_get_clocks(struct msm_fd_device *fd);
int msm_fd_hw_put_clocks(struct msm_fd_device *fd);
int msm_fd_hw_get_bus(struct msm_fd_device *fd);
void msm_fd_hw_put_bus(struct msm_fd_device *fd);
int msm_fd_hw_get(struct msm_fd_device *fd, unsigned int clock_rate_idx);
void msm_fd_hw_put(struct msm_fd_device *fd);
int msm_fd_hw_map_buffer(struct msm_fd_mem_pool *pool, int fd,
struct msm_fd_buf_handle *buf);
void msm_fd_hw_unmap_buffer(struct msm_fd_buf_handle *buf);
void msm_fd_hw_add_buffer(struct msm_fd_device *fd,
struct msm_fd_buffer *buffer);
void msm_fd_hw_remove_buffers_from_queue(struct msm_fd_device *fd,
struct vb2_queue *vb2_q);
int msm_fd_hw_buffer_done(struct msm_fd_device *fd,
struct msm_fd_buffer *buffer);
struct msm_fd_buffer *msm_fd_hw_get_active_buffer(struct msm_fd_device *fd);
int msm_fd_hw_schedule_and_start(struct msm_fd_device *fd);
int msm_fd_hw_schedule_next_buffer(struct msm_fd_device *fd);
#endif /* __MSM_FD_HW_H__ */

View file

@ -0,0 +1,169 @@
/* Copyright (c) 2014-2017, 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_FD_REGS_H__
#define __MSM_FD_REGS_H__
/* FD core registers */
#define MSM_FD_CONTROL (0x00)
#define MSM_FD_CONTROL_SRST (1 << 0)
#define MSM_FD_CONTROL_RUN (1 << 1)
#define MSM_FD_CONTROL_FINISH (1 << 2)
#define MSM_FD_RESULT_CNT (0x04)
#define MSM_FD_RESULT_CNT_MASK (0x3F)
#define MSM_FD_CONDT (0x08)
#define MSM_FD_CONDT_MIN_MASK (0x03)
#define MSM_FD_CONDT_MIN_SHIFT (0x00)
#define MSM_FD_CONDT_DIR_MAX (0x08)
#define MSM_FD_CONDT_DIR_MASK (0x3C)
#define MSM_FD_CONDT_DIR_SHIFT (0x02)
#define MSM_FD_START_X (0x0C)
#define MSM_FD_START_X_MASK (0x3FF)
#define MSM_FD_START_Y (0x10)
#define MSM_FD_START_Y_MASK (0x1FF)
#define MSM_FD_SIZE_X (0x14)
#define MSM_FD_SIZE_X_MASK (0x3FF)
#define MSM_FD_SIZE_Y (0x18)
#define MSM_FD_SIZE_Y_MASK (0x1FF)
#define MSM_FD_DHINT (0x1C)
#define MSM_FD_DHINT_MASK (0xF)
#define MSM_FD_IMAGE_ADDR (0x24)
#define MSM_FD_IMAGE_ADDR_ALIGN (0x8)
#define MSM_FD_WORK_ADDR (0x28)
#define MSM_FD_WORK_ADDR_ALIGN (0x8)
#define MSM_FD_IMAGE_SIZE (0x2C)
#define MSM_FD_IMAGE_SIZE_QVGA (0x0)
#define MSM_FD_IMAGE_SIZE_VGA (0x1)
#define MSM_FD_IMAGE_SIZE_WQVGA (0x2)
#define MSM_FD_IMAGE_SIZE_WVGA (0x3)
#define MSM_FD_LINE_BYTES (0x30)
#define MSM_FD_LINE_BYTES_MASK (0x1FFF)
#define MSM_FD_LINE_BYTES_ALIGN (0x8)
#define MSM_FD_RESULT_CENTER_X(x) (0x400 + (0x10 * (x)))
#define MSM_FD_RESULT_CENTER_Y(x) (0x404 + (0x10 * (x)))
#define MSM_FD_RESULT_CONF_SIZE(x) (0x408 + (0x10 * (x)))
#define MSM_FD_RESULT_SIZE_MASK (0x1FF)
#define MSM_FD_RESULT_SIZE_SHIFT (0x000)
#define MSM_FD_RESULT_CONF_MASK (0xF)
#define MSM_FD_RESULT_CONF_SHIFT (0x9)
#define MSM_FD_RESULT_ANGLE_POSE(x) (0x40C + (0x10 * (x)))
#define MSM_FD_RESULT_ANGLE_MASK (0x1FF)
#define MSM_FD_RESULT_ANGLE_SHIFT (0x000)
#define MSM_FD_RESULT_POSE_MASK (0x7)
#define MSM_FD_RESULT_POSE_SHIFT (0x9)
#define MSM_FD_RESULT_POSE_FRONT (0x1)
#define MSM_FD_RESULT_POSE_RIGHT_DIAGONAL (0x2)
#define MSM_FD_RESULT_POSE_RIGHT (0x3)
#define MSM_FD_RESULT_POSE_LEFT_DIAGONAL (0x4)
#define MSM_FD_RESULT_POSE_LEFT (0x5)
/* FD misc registers */
#define MSM_FD_MISC_HW_VERSION (0x00)
#define MSM_FD_MISC_CGC_DISABLE (0x04)
#define MSM_FD_HW_STOP (0x08)
#define MSM_FD_MISC_SW_RESET (0x10)
#define MSM_FD_MISC_SW_RESET_SET (1 << 0)
#define MSM_FD_MISC_FIFO_STATUS (0x14)
#define MSM_FD_MISC_FIFO_STATUS_RFIFO_DCNT_MAST (0x1F)
#define MSM_FD_MISC_FIFO_STATUS_RFIFO_DCNT_SHIFT (0)
#define MSM_FD_MISC_FIFO_STATUS_RFIFO_FULL (1 << 13)
#define MSM_FD_MISC_FIFO_STATUS_RFIFO_EMPTY (1 << 14)
#define MSM_FD_MISC_FIFO_STATUS_WFIFO_DCNT_MAST (0x1F)
#define MSM_FD_MISC_FIFO_STATUS_WFIFO_DCNT_SHIFT (16)
#define MSM_FD_MISC_FIFO_STATUS_WFIFO_EMPTY (1 << 29)
#define MSM_FD_MISC_FIFO_STATUS_WFIFO_FULL (1 << 30)
#define MSM_FD_MISC_DATA_ENDIAN (0x18)
#define MSM_FD_MISC_DATA_ENDIAN_BYTE_SWAP_SET (1 << 0)
#define MSM_FD_MISC_VBIF_REQ_PRIO (0x20)
#define MSM_FD_MISC_VBIF_REQ_PRIO_MASK (0x3)
#define MSM_FD_MISC_VBIF_PRIO_LEVEL (0x24)
#define MSM_FD_MISC_VBIF_PRIO_LEVEL_MASK (0x3)
#define MSM_FD_MISC_VBIF_MMU_PDIRECT (0x28)
#define MSM_FD_MISC_VBIF_MMU_PDIRECT_INCREMENT (1 << 0)
#define MSM_FD_MISC_VBIF_IRQ_CLR (0x30)
#define MSM_FD_MISC_VBIF_IRQ_CLR_ALL (1 << 0)
#define MSM_FD_MISC_VBIF_DONE_STATUS (0x34)
#define MSM_FD_MISC_VBIF_DONE_STATUS_WRITE (1 << 0)
#define MSM_FD_MISC_VBIF_DONE_STATUS_READ (1 << 1)
#define MSM_FD_MISC_IRQ_MASK (0x50)
#define MSM_FD_MISC_IRQ_MASK_HALT_REQ (1 << 1)
#define MSM_FD_MISC_IRQ_MASK_CORE_IRQ (1 << 0)
#define MSM_FD_MISC_IRQ_STATUS (0x54)
#define MSM_FD_MISC_IRQ_STATUS_HALT_REQ (1 << 1)
#define MSM_FD_MISC_IRQ_STATUS_CORE_IRQ (1 << 0)
#define MSM_FD_MISC_IRQ_CLEAR (0x58)
#define MSM_FD_MISC_IRQ_CLEAR_HALT (1 << 1)
#define MSM_FD_MISC_IRQ_CLEAR_CORE (1 << 0)
#define MSM_FD_MISC_TEST_BUS_SEL (0x40)
#define MSM_FD_MISC_TEST_BUS_SEL_TEST_MODE_MASK (0xF)
#define MSM_FD_MISC_TEST_BUS_SEL_TEST_MODE_SHIFT (0)
#define MSM_FD_MISC_TEST_BUS_SEL_7_0_MASK (0x3)
#define MSM_FD_MISC_TEST_BUS_SEL_7_0_SHIFT (16)
#define MSM_FD_MISC_TEST_BUS_SEL_15_8_MASK (0x3)
#define MSM_FD_MISC_TEST_BUS_SEL_15_8_SHIFT (18)
#define MSM_FD_MISC_TEST_BUS_SEL_23_16_MASK (0x3)
#define MSM_FD_MISC_TEST_BUS_SEL_23_16_SHIFT (20)
#define MSM_FD_MISC_TEST_BUS_SEL_31_24_MASK (0x3)
#define MSM_FD_MISC_TEST_BUS_SEL_31_24_SHIFT (22)
#define MSM_FD_MISC_AHB_TEST_EN (0x44)
#define MSM_FD_MISC_AHB_TEST_EN_MASK (0x3)
#define MSM_FD_MISC_FD2VBIF_INT_TEST_SEL (0x48)
#define MSM_FD_MISC_FD2VBIF_INT_TEST_MASK (0xF)
#define MSM_FD_MISC_TEST_BUS (0x4C)
/* FD vbif registers */
#define MSM_FD_VBIF_CLKON (0x04)
#define MSM_FD_VBIF_QOS_OVERRIDE_EN (0x10)
#define MSM_FD_VBIF_QOS_OVERRIDE_REQPRI (0x18)
#define MSM_FD_VBIF_QOS_OVERRIDE_PRILVL (0x1C)
#define MSM_FD_VBIF_IN_RD_LIM_CONF0 (0xB0)
#define MSM_FD_VBIF_IN_WR_LIM_CONF0 (0xC0)
#define MSM_FD_VBIF_OUT_RD_LIM_CONF0 (0xD0)
#define MSM_FD_VBIF_OUT_WR_LIM_CONF0 (0xD4)
#define MSM_FD_VBIF_DDR_OUT_MAX_BURST (0xD8)
#define MSM_FD_VBIF_ARB_CTL (0xF0)
#define MSM_FD_VBIF_OUT_AXI_AMEMTYPE_CONF0 (0x160)
#define MSM_FD_VBIF_OUT_AXI_AOOO_EN (0x178)
#define MSM_FD_VBIF_OUT_AXI_AOOO (0x17c)
#define MSM_FD_VBIF_ROUND_ROBIN_QOS_ARB (0x124)
#endif /* __MSM_FD_REGS_H__ */

View file

@ -0,0 +1,5 @@
ccflags-y += -Idrivers/media/platform/msm/ais
ccflags-y += -Idrivers/media/platform/msm/ais/sensor/io
ccflags-y += -Idrivers/media/platform/msm/ais/common/
obj-$(CONFIG_MSM_AIS) += msm_buf_mgr.o msm_isp_util.o msm_isp_axi_util.o msm_isp_stats_util.o
obj-$(CONFIG_MSM_AIS) += msm_isp47.o msm_isp.o

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,230 @@
/* Copyright (c) 2013-2017, 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/ais/msm_ais_isp.h>
#include "msm_sd.h"
/* Buffer type could be userspace / HAL.
* Userspase could provide native or scratch buffer.
*/
#define BUF_SRC(id) ( \
(id & ISP_SCRATCH_BUF_BIT) ? MSM_ISP_BUFFER_SRC_SCRATCH : \
(id & ISP_NATIVE_BUF_BIT) ? MSM_ISP_BUFFER_SRC_NATIVE : \
MSM_ISP_BUFFER_SRC_HAL)
/*
* This mask can be set dynamically if there are more than 2 VFE
* and 2 of those are used
*/
#define ISP_SHARE_BUF_MASK 0x3
#define ISP_NUM_BUF_MASK 2
#define BUF_MGR_NUM_BUF_Q 28
#define MAX_IOMMU_CTX 2
#define MSM_ISP_INVALID_BUF_INDEX 0xFFFFFFFF
struct msm_isp_buf_mgr;
enum msm_isp_buffer_src_t {
MSM_ISP_BUFFER_SRC_HAL,
MSM_ISP_BUFFER_SRC_NATIVE,
MSM_ISP_BUFFER_SRC_SCRATCH,
MSM_ISP_BUFFER_SRC_MAX,
};
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_DIVERTED, /* Sent to other hardware*/
MSM_ISP_BUFFER_STATE_DISPATCHED, /* Sent to HAL*/
};
enum msm_isp_buffer_put_state {
MSM_ISP_BUFFER_STATE_PUT_PREPARED, /* on init */
MSM_ISP_BUFFER_STATE_PUT_BUF, /* on rotation */
MSM_ISP_BUFFER_STATE_FLUSH, /* on recovery */
MSM_ISP_BUFFER_STATE_DROP_REG, /* on drop frame for reg_update */
MSM_ISP_BUFFER_STATE_DROP_SKIP, /* on drop frame for sw skip */
MSM_ISP_BUFFER_STATE_RETURN_EMPTY, /* for return empty */
};
enum msm_isp_buffer_flush_t {
MSM_ISP_BUFFER_FLUSH_DIVERTED,
MSM_ISP_BUFFER_FLUSH_ALL,
};
enum msm_isp_buf_mgr_state {
MSM_ISP_BUF_MGR_ATTACH,
MSM_ISP_BUF_MGR_DETACH,
};
struct msm_isp_buffer_mapped_info {
size_t len;
dma_addr_t paddr;
int buf_fd;
};
struct buffer_cmd {
struct list_head list;
struct msm_isp_buffer_mapped_info *mapped_info;
};
struct msm_isp_buffer_debug_t {
enum msm_isp_buffer_put_state put_state[2];
uint8_t put_state_last;
};
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;
uint32_t frame_id;
struct timeval *tv;
/* Indicates whether buffer is used as ping ot pong buffer */
uint32_t pingpong_bit;
/*Native buffer*/
struct list_head list;
enum msm_isp_buffer_state state;
struct msm_isp_buffer_debug_t buf_debug;
/*Vb2 buffer data*/
struct vb2_v4l2_buffer *vb2_v4l2_buf;
};
struct msm_isp_bufq {
uint32_t vfe_id;
enum msm_vfe_axi_stream_src output_id;
uint32_t flags;
uint32_t num_bufs;
uint32_t bufq_handle;
enum msm_isp_buf_type buf_type;
struct msm_isp_buffer *bufs;
spinlock_t bufq_lock;
uint8_t put_buf_mask[ISP_NUM_BUF_MASK];
/*Native buffer queue*/
struct list_head head;
/*deprecated params*/
uint32_t session_id;
uint32_t stream_id;
};
struct msm_isp_buf_ops {
int (*request_bufq)(struct msm_isp_buf_mgr *buf_mgr,
struct msm_isp_buf_request *buf_request);
int (*release_bufq)(struct msm_isp_buf_mgr *buf_mgr,
uint32_t bufq_handle);
int (*enqueue_buf)(struct msm_isp_buf_mgr *buf_mgr,
struct msm_isp_qbuf_info *info);
int (*dequeue_buf)(struct msm_isp_buf_mgr *buf_mgr,
struct msm_isp_qbuf_info *info);
int (*get_bufq_handle)(struct msm_isp_buf_mgr *buf_mgr,
uint32_t vfe_id, uint32_t output_id);
int (*get_buf_src)(struct msm_isp_buf_mgr *buf_mgr,
uint32_t bufq_handle, uint32_t *buf_src);
int (*get_buf)(struct msm_isp_buf_mgr *buf_mgr,
uint32_t bufq_handle, uint32_t buf_index,
struct msm_isp_buffer **buf_info);
int (*get_buf_by_index)(struct msm_isp_buf_mgr *buf_mgr,
uint32_t bufq_handle, uint32_t buf_index,
struct msm_isp_buffer **buf_info);
int (*map_buf)(struct msm_isp_buf_mgr *buf_mgr,
struct msm_isp_buffer_mapped_info *mapped_info, uint32_t fd);
int (*unmap_buf)(struct msm_isp_buf_mgr *buf_mgr, uint32_t fd);
int (*put_buf)(struct msm_isp_buf_mgr *buf_mgr,
uint32_t bufq_handle, uint32_t buf_index);
int (*flush_buf)(struct msm_isp_buf_mgr *buf_mgr, uint32_t id,
uint32_t bufq_handle, enum msm_isp_buffer_flush_t flush_type,
struct timeval *tv, uint32_t frame_id);
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, uint32_t output_format);
void (*register_ctx)(struct msm_isp_buf_mgr *buf_mgr,
struct device **iommu_ctx1, struct device **iommu_ctx2,
int num_iommu_ctx1, int num_iommu_ctx2);
int (*buf_mgr_init)(struct msm_isp_buf_mgr *buf_mgr,
const char *ctx_name);
int (*buf_mgr_deinit)(struct msm_isp_buf_mgr *buf_mgr);
int (*buf_mgr_debug)(struct msm_isp_buf_mgr *buf_mgr,
unsigned long fault_addr);
struct msm_isp_bufq * (*get_bufq)(struct msm_isp_buf_mgr *buf_mgr,
uint32_t bufq_handle);
int (*update_put_buf_cnt)(struct msm_isp_buf_mgr *buf_mgr,
uint32_t id, uint32_t bufq_handle, int32_t buf_index,
struct timeval *tv, uint32_t frame_id, uint32_t pingpong_bit);
};
struct msm_isp_buf_mgr {
int init_done;
uint32_t open_count;
uint32_t pagefault_debug_disable;
uint32_t frameId_mismatch_recovery;
uint16_t num_buf_q;
struct msm_isp_bufq bufq[BUF_MGR_NUM_BUF_Q];
struct ion_client *client;
struct msm_isp_buf_ops *ops;
struct msm_sd_req_vb2_q *vb2_ops;
/*IOMMU driver*/
int iommu_hdl;
/*Add secure mode*/
int secure_enable;
int num_iommu_ctx;
int num_iommu_secure_ctx;
int attach_ref_cnt;
enum msm_isp_buf_mgr_state attach_state;
struct device *isp_dev;
struct mutex lock;
/* Scratch buffer */
dma_addr_t scratch_buf_addr;
uint32_t scratch_buf_range;
};
int msm_isp_create_isp_buf_mgr(struct msm_isp_buf_mgr *buf_mgr,
struct msm_sd_req_vb2_q *vb2_ops, struct device *dev,
uint32_t scratch_addr_range);
int msm_isp_proc_buf_cmd(struct msm_isp_buf_mgr *buf_mgr,
unsigned int cmd, void *arg);
int msm_isp_smmu_attach(struct msm_isp_buf_mgr *buf_mgr,
void *arg);
int msm_isp_flush_queue(struct msm_isp_buf_mgr *buf_mgr,
uint32_t bufq_handle);
#endif /* _MSM_ISP_BUF_H_ */

View file

@ -0,0 +1,658 @@
/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/debugfs.h>
#include <linux/videodev2.h>
#include <linux/of_device.h>
#include <linux/sched_clock.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-event.h>
#include "msm_isp.h"
#include "msm_isp_util.h"
#include "msm_isp_axi_util.h"
#include "msm_isp_stats_util.h"
#include "msm_sd.h"
static struct msm_sd_req_vb2_q vfe_vb2_ops;
static struct msm_isp_buf_mgr vfe_buf_mgr;
static struct msm_vfe_common_dev_data vfe_common_data;
static struct dual_vfe_resource dualvfe;
static const struct of_device_id msm_vfe_dt_match[] = {
{
.compatible = "qcom,vfe",
},
{}
};
MODULE_DEVICE_TABLE(of, msm_vfe_dt_match);
#define MAX_OVERFLOW_COUNTERS 29
#define OVERFLOW_LENGTH 1024
#define OVERFLOW_BUFFER_LENGTH 64
static char stat_line[OVERFLOW_LENGTH];
struct msm_isp_statistics stats;
struct msm_isp_ub_info ub_info;
static int msm_isp_enable_debugfs(struct vfe_device *vfe_dev,
struct msm_isp_bw_req_info *isp_req_hist);
static char *stats_str[MAX_OVERFLOW_COUNTERS] = {
"imgmaster0_overflow_cnt",
"imgmaster1_overflow_cnt",
"imgmaster2_overflow_cnt",
"imgmaster3_overflow_cnt",
"imgmaster4_overflow_cnt",
"imgmaster5_overflow_cnt",
"imgmaster6_overflow_cnt",
"be_overflow_cnt",
"bg_overflow_cnt",
"bf_overflow_cnt",
"awb_overflow_cnt",
"rs_overflow_cnt",
"cs_overflow_cnt",
"ihist_overflow_cnt",
"skinbhist_overflow_cnt",
"bfscale_overflow_cnt",
"ISP_VFE0_client_info.active",
"ISP_VFE0_client_info.ab",
"ISP_VFE0_client_info.ib",
"ISP_VFE1_client_info.active",
"ISP_VFE1_client_info.ab",
"ISP_VFE1_client_info.ib",
"ISP_CPP_client_info.active",
"ISP_CPP_client_info.ab",
"ISP_CPP_client_info.ib",
"ISP_last_overflow.ab",
"ISP_last_overflow.ib",
"ISP_VFE_CLK_RATE",
"ISP_CPP_CLK_RATE",
};
#define MAX_DEPTH_BW_REQ_HISTORY 25
#define MAX_BW_HISTORY_BUFF_LEN 6144
#define MAX_BW_HISTORY_LINE_BUFF_LEN 512
#define MAX_UB_INFO_BUFF_LEN 1024
#define MAX_UB_INFO_LINE_BUFF_LEN 256
static struct msm_isp_bw_req_info
msm_isp_bw_request_history[MAX_DEPTH_BW_REQ_HISTORY];
static int msm_isp_bw_request_history_idx;
static char bw_request_history_buff[MAX_BW_HISTORY_BUFF_LEN];
static char ub_info_buffer[MAX_UB_INFO_BUFF_LEN];
static spinlock_t req_history_lock;
static int vfe_debugfs_statistics_open(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
return 0;
}
static ssize_t vfe_debugfs_statistics_read(struct file *t_file, char *t_char,
size_t t_size_t, loff_t *t_loff_t)
{
int i;
uint64_t *ptr;
char buffer[OVERFLOW_BUFFER_LENGTH] = {0};
struct vfe_device *vfe_dev = (struct vfe_device *)
t_file->private_data;
struct msm_isp_statistics *stats = vfe_dev->stats;
memset(stat_line, 0, sizeof(stat_line));
msm_isp_util_get_bandwidth_stats(vfe_dev, stats);
ptr = (uint64_t *)(stats);
for (i = 0; i < MAX_OVERFLOW_COUNTERS; i++) {
strlcat(stat_line, stats_str[i], sizeof(stat_line));
strlcat(stat_line, " ", sizeof(stat_line));
snprintf(buffer, sizeof(buffer), "%llu", ptr[i]);
strlcat(stat_line, buffer, sizeof(stat_line));
strlcat(stat_line, "\r\n", sizeof(stat_line));
}
return simple_read_from_buffer(t_char, t_size_t,
t_loff_t, stat_line, strlen(stat_line));
}
static ssize_t vfe_debugfs_statistics_write(struct file *t_file,
const char *t_char, size_t t_size_t, loff_t *t_loff_t)
{
struct vfe_device *vfe_dev = (struct vfe_device *)
t_file->private_data;
struct msm_isp_statistics *stats = vfe_dev->stats;
memset(stats, 0, sizeof(struct msm_isp_statistics));
return sizeof(struct msm_isp_statistics);
}
static int bw_history_open(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
return 0;
}
static ssize_t bw_history_read(struct file *t_file, char *t_char,
size_t t_size_t, loff_t *t_loff_t)
{
int i;
char *out_buffer = bw_request_history_buff;
char line_buffer[MAX_BW_HISTORY_LINE_BUFF_LEN] = {0};
struct msm_isp_bw_req_info *isp_req_hist =
(struct msm_isp_bw_req_info *) t_file->private_data;
memset(out_buffer, 0, MAX_BW_HISTORY_BUFF_LEN);
snprintf(line_buffer, sizeof(line_buffer),
"Bus bandwidth request history in chronological order:\n");
strlcat(out_buffer, line_buffer, sizeof(bw_request_history_buff));
snprintf(line_buffer, sizeof(line_buffer),
"MSM_ISP_MIN_AB = %u, MSM_ISP_MIN_IB = %u\n\n",
MSM_ISP_MIN_AB, MSM_ISP_MIN_IB);
strlcat(out_buffer, line_buffer, sizeof(bw_request_history_buff));
for (i = 0; i < MAX_DEPTH_BW_REQ_HISTORY; i++) {
snprintf(line_buffer, sizeof(line_buffer),
"idx = %d, client = %u, timestamp = %llu, ab = %llu, ib = %llu\n"
"ISP0.active = %x, ISP0.ab = %llu, ISP0.ib = %llu\n"
"ISP1.active = %x, ISP1.ab = %llu, ISP1.ib = %llu\n"
"CPP.active = %x, CPP.ab = %llu, CPP.ib = %llu\n\n",
i, isp_req_hist[i].client, isp_req_hist[i].timestamp,
isp_req_hist[i].total_ab, isp_req_hist[i].total_ib,
isp_req_hist[i].client_info[0].active,
isp_req_hist[i].client_info[0].ab,
isp_req_hist[i].client_info[0].ib,
isp_req_hist[i].client_info[1].active,
isp_req_hist[i].client_info[1].ab,
isp_req_hist[i].client_info[1].ib,
isp_req_hist[i].client_info[2].active,
isp_req_hist[i].client_info[2].ab,
isp_req_hist[i].client_info[2].ib);
strlcat(out_buffer, line_buffer,
sizeof(bw_request_history_buff));
}
return simple_read_from_buffer(t_char, t_size_t,
t_loff_t, out_buffer, strlen(out_buffer));
}
static ssize_t bw_history_write(struct file *t_file,
const char *t_char, size_t t_size_t, loff_t *t_loff_t)
{
struct msm_isp_bw_req_info *isp_req_hist =
(struct msm_isp_bw_req_info *) t_file->private_data;
memset(isp_req_hist, 0, sizeof(msm_isp_bw_request_history));
msm_isp_bw_request_history_idx = 0;
return sizeof(msm_isp_bw_request_history);
}
static int ub_info_open(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
return 0;
}
static ssize_t ub_info_read(struct file *t_file, char *t_char,
size_t t_size_t, loff_t *t_loff_t)
{
int i;
char *out_buffer = ub_info_buffer;
char line_buffer[MAX_UB_INFO_LINE_BUFF_LEN] = {0};
struct vfe_device *vfe_dev =
(struct vfe_device *) t_file->private_data;
struct msm_isp_ub_info *ub_info = vfe_dev->ub_info;
memset(out_buffer, 0, MAX_UB_INFO_LINE_BUFF_LEN);
snprintf(line_buffer, sizeof(line_buffer),
"wm_ub_policy_type = %d\n"
"num_wm = %d\n"
"wm_ub = %d\n",
ub_info->policy, ub_info->num_wm, ub_info->wm_ub);
strlcat(out_buffer, line_buffer,
sizeof(ub_info_buffer));
for (i = 0; i < ub_info->num_wm; i++) {
snprintf(line_buffer, sizeof(line_buffer),
"data[%d] = 0x%x, addr[%d] = 0x%llx\n",
i, ub_info->data[i], i, ub_info->addr[i]);
strlcat(out_buffer, line_buffer,
sizeof(ub_info_buffer));
}
return simple_read_from_buffer(t_char, t_size_t,
t_loff_t, out_buffer, strlen(out_buffer));
}
static ssize_t ub_info_write(struct file *t_file,
const char *t_char, size_t t_size_t, loff_t *t_loff_t)
{
struct vfe_device *vfe_dev =
(struct vfe_device *) t_file->private_data;
struct msm_isp_ub_info *ub_info = vfe_dev->ub_info;
memset(ub_info, 0, sizeof(struct msm_isp_ub_info));
return sizeof(struct msm_isp_ub_info);
}
static const struct file_operations vfe_debugfs_error = {
.open = vfe_debugfs_statistics_open,
.read = vfe_debugfs_statistics_read,
.write = vfe_debugfs_statistics_write,
};
static const struct file_operations bw_history_ops = {
.open = bw_history_open,
.read = bw_history_read,
.write = bw_history_write,
};
static const struct file_operations ub_info_ops = {
.open = ub_info_open,
.read = ub_info_read,
.write = ub_info_write,
};
static int msm_isp_enable_debugfs(struct vfe_device *vfe_dev,
struct msm_isp_bw_req_info *isp_req_hist)
{
struct dentry *debugfs_base;
char dirname[32] = {0};
snprintf(dirname, sizeof(dirname), "msm_isp%d", vfe_dev->pdev->id);
debugfs_base = debugfs_create_dir(dirname, NULL);
if (!debugfs_base)
return -ENOMEM;
if (!debugfs_create_file("stats", S_IRUGO | S_IWUSR, debugfs_base,
vfe_dev, &vfe_debugfs_error))
return -ENOMEM;
if (!debugfs_create_file("bw_req_history", S_IRUGO | S_IWUSR,
debugfs_base, isp_req_hist, &bw_history_ops))
return -ENOMEM;
if (!debugfs_create_file("ub_info", S_IRUGO | S_IWUSR,
debugfs_base, vfe_dev, &ub_info_ops))
return -ENOMEM;
return 0;
}
void msm_isp_update_req_history(uint32_t client, uint64_t ab,
uint64_t ib,
struct msm_isp_bandwidth_info *client_info,
unsigned long long ts)
{
int i;
spin_lock(&req_history_lock);
msm_isp_bw_request_history[msm_isp_bw_request_history_idx].client =
client;
msm_isp_bw_request_history[msm_isp_bw_request_history_idx].timestamp =
ts;
msm_isp_bw_request_history[msm_isp_bw_request_history_idx].total_ab =
ab;
msm_isp_bw_request_history[msm_isp_bw_request_history_idx].total_ib =
ib;
for (i = 0; i < MAX_ISP_CLIENT; i++) {
msm_isp_bw_request_history[msm_isp_bw_request_history_idx].
client_info[i].active = client_info[i].active;
msm_isp_bw_request_history[msm_isp_bw_request_history_idx].
client_info[i].ab = client_info[i].ab;
msm_isp_bw_request_history[msm_isp_bw_request_history_idx].
client_info[i].ib = client_info[i].ib;
}
msm_isp_bw_request_history_idx = (msm_isp_bw_request_history_idx + 1)
% MAX_DEPTH_BW_REQ_HISTORY;
spin_unlock(&req_history_lock);
}
void msm_isp_update_last_overflow_ab_ib(struct vfe_device *vfe_dev)
{
spin_lock(&req_history_lock);
vfe_dev->msm_isp_last_overflow_ab =
msm_isp_bw_request_history[msm_isp_bw_request_history_idx].total_ab;
vfe_dev->msm_isp_last_overflow_ib =
msm_isp_bw_request_history[msm_isp_bw_request_history_idx].total_ib;
spin_unlock(&req_history_lock);
}
#ifdef CONFIG_COMPAT
static long msm_isp_dqevent(struct file *file, struct v4l2_fh *vfh, void *arg)
{
long rc;
if (is_compat_task()) {
struct msm_isp_event_data32 *event_data32;
struct msm_isp_event_data *event_data;
struct v4l2_event isp_event;
struct v4l2_event *isp_event_user;
memset(&isp_event, 0, sizeof(isp_event));
rc = v4l2_event_dequeue(vfh, &isp_event,
file->f_flags & O_NONBLOCK);
if (rc)
return rc;
event_data = (struct msm_isp_event_data *)
isp_event.u.data;
isp_event_user = (struct v4l2_event *)arg;
memcpy(isp_event_user, &isp_event,
sizeof(*isp_event_user));
event_data32 = (struct msm_isp_event_data32 *)
isp_event_user->u.data;
memset(event_data32, 0,
sizeof(struct msm_isp_event_data32));
event_data32->timestamp.tv_sec =
event_data->timestamp.tv_sec;
event_data32->timestamp.tv_usec =
event_data->timestamp.tv_usec;
event_data32->mono_timestamp.tv_sec =
event_data->mono_timestamp.tv_sec;
event_data32->mono_timestamp.tv_usec =
event_data->mono_timestamp.tv_usec;
event_data32->frame_id = event_data->frame_id;
memcpy(&(event_data32->u), &(event_data->u),
sizeof(event_data32->u));
} else {
rc = v4l2_event_dequeue(vfh, arg,
file->f_flags & O_NONBLOCK);
}
return rc;
}
#else
static long msm_isp_dqevent(struct file *file, struct v4l2_fh *vfh, void *arg)
{
return v4l2_event_dequeue(vfh, arg,
file->f_flags & O_NONBLOCK);
}
#endif
static long msm_isp_subdev_do_ioctl(
struct file *file, unsigned int cmd, void *arg)
{
struct video_device *vdev = video_devdata(file);
struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
struct v4l2_fh *vfh = file->private_data;
switch (cmd) {
case VIDIOC_DQEVENT: {
if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
return -ENOIOCTLCMD;
return msm_isp_dqevent(file, vfh, arg);
}
break;
case VIDIOC_SUBSCRIBE_EVENT:
return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg);
case VIDIOC_UNSUBSCRIBE_EVENT:
return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg);
default:
return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
}
}
static struct v4l2_subdev_core_ops msm_vfe_v4l2_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_vfe_v4l2_subdev_ops = {
.core = &msm_vfe_v4l2_subdev_core_ops,
};
static struct v4l2_subdev_internal_ops msm_vfe_subdev_internal_ops = {
.open = msm_isp_open_node,
.close = msm_isp_close_node,
};
static long msm_isp_v4l2_fops_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
return video_usercopy(file, cmd, arg, msm_isp_subdev_do_ioctl);
}
static struct v4l2_file_operations msm_isp_v4l2_fops = {
#ifdef CONFIG_COMPAT
.compat_ioctl32 = msm_isp_v4l2_fops_ioctl,
#endif
.unlocked_ioctl = msm_isp_v4l2_fops_ioctl
};
static int vfe_set_common_data(struct platform_device *pdev)
{
struct v4l2_subdev *sd = NULL;
struct vfe_device *vfe_dev = NULL;
sd = (struct v4l2_subdev *)platform_get_drvdata(pdev);
if (!sd) {
pr_err("%s: Error! Cannot find subdev\n", __func__);
return -EPERM;
}
vfe_dev = (struct vfe_device *)v4l2_get_subdevdata(sd);
if (!vfe_dev) {
pr_err("%s: Error! Cannot find vfe_dev\n", __func__);
return -EPERM;
}
vfe_dev->common_data = (struct msm_vfe_common_dev_data *)
pdev->dev.platform_data;
vfe_dev->common_data->dual_vfe_res = &dualvfe;
vfe_dev->common_data->dual_vfe_res->axi_data[vfe_dev->pdev->id] =
&vfe_dev->axi_data;
vfe_dev->common_data->dual_vfe_res->stats_data[vfe_dev->pdev->id] =
&vfe_dev->stats_data;
vfe_dev->common_data->dual_vfe_res->vfe_dev[vfe_dev->pdev->id] =
vfe_dev;
return 0;
}
static int vfe_probe(struct platform_device *pdev)
{
int rc = 0;
struct device_node *node;
struct platform_device *new_dev = NULL;
uint32_t i = 0;
uint32_t num_hw_sd = 0;
char name[10] = "\0";
memset(&vfe_common_data, 0, sizeof(vfe_common_data));
spin_lock_init(&vfe_common_data.common_dev_data_lock);
of_property_read_u32(pdev->dev.of_node,
"num_child", &num_hw_sd);
for (i = 0; i < num_hw_sd; i++) {
node = NULL;
snprintf(name, sizeof(name), "qcom,vfe%d", i);
node = of_find_node_by_name(NULL, name);
if (!node) {
pr_err("%s: Error! Cannot find node in dtsi %s\n",
__func__, name);
break;
}
new_dev = of_find_device_by_node(node);
if (!new_dev) {
pr_err("%s: Failed to find device on bus %s\n",
__func__, node->name);
break;
}
new_dev->dev.platform_data =
(void *)&vfe_common_data;
rc = vfe_set_common_data(new_dev);
if (rc < 0)
break;
}
return rc;
}
int vfe_hw_probe(struct platform_device *pdev)
{
struct vfe_device *vfe_dev;
/*struct msm_cam_subdev_info sd_info;*/
const struct of_device_id *match_dev;
int rc = 0;
vfe_dev = kzalloc(sizeof(struct vfe_device), GFP_KERNEL);
if (!vfe_dev) {
rc = -ENOMEM;
goto end;
}
vfe_dev->stats = kzalloc(sizeof(struct msm_isp_statistics), GFP_KERNEL);
if (!vfe_dev->stats) {
rc = -ENOMEM;
goto probe_fail1;
}
vfe_dev->ub_info = kzalloc(sizeof(struct msm_isp_ub_info), GFP_KERNEL);
if (!vfe_dev->ub_info) {
rc = -ENOMEM;
goto probe_fail2;
}
if (pdev->dev.of_node) {
of_property_read_u32(pdev->dev.of_node,
"cell-index", &pdev->id);
match_dev = of_match_device(pdev->dev.driver->of_match_table,
&pdev->dev);
if (!match_dev) {
pr_err("%s: No vfe hardware info\n", __func__);
rc = -EINVAL;
goto probe_fail3;
}
vfe_dev->hw_info =
(struct msm_vfe_hardware_info *) match_dev->data;
} else {
vfe_dev->hw_info = (struct msm_vfe_hardware_info *)
platform_get_device_id(pdev)->driver_data;
}
if (!vfe_dev->hw_info) {
pr_err("%s: No vfe hardware info\n", __func__);
rc = -EINVAL;
goto probe_fail3;
}
ISP_DBG("%s: device id = %d\n", __func__, pdev->id);
vfe_dev->pdev = pdev;
rc = vfe_dev->hw_info->vfe_ops.platform_ops.get_platform_data(vfe_dev);
if (rc < 0) {
pr_err("%s: failed to get platform resources\n", __func__);
rc = -ENOMEM;
goto probe_fail3;
}
INIT_LIST_HEAD(&vfe_dev->tasklet_q);
tasklet_init(&vfe_dev->vfe_tasklet,
msm_isp_do_tasklet, (unsigned long)vfe_dev);
v4l2_subdev_init(&vfe_dev->subdev.sd, &msm_vfe_v4l2_subdev_ops);
vfe_dev->subdev.sd.internal_ops =
&msm_vfe_subdev_internal_ops;
snprintf(vfe_dev->subdev.sd.name,
ARRAY_SIZE(vfe_dev->subdev.sd.name),
"vfe");
vfe_dev->subdev.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
vfe_dev->subdev.sd.flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
v4l2_set_subdevdata(&vfe_dev->subdev.sd, vfe_dev);
platform_set_drvdata(pdev, &vfe_dev->subdev.sd);
mutex_init(&vfe_dev->realtime_mutex);
mutex_init(&vfe_dev->core_mutex);
spin_lock_init(&vfe_dev->tasklet_lock);
spin_lock_init(&vfe_dev->shared_data_lock);
spin_lock_init(&vfe_dev->reg_update_lock);
spin_lock_init(&req_history_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;
vfe_dev->subdev.close_seq = MSM_SD_CLOSE_1ST_CATEGORY | 0x2;
rc = msm_sd_register(&vfe_dev->subdev);
if (rc != 0) {
pr_err("%s: msm_sd_register error = %d\n", __func__, rc);
goto probe_fail3;
}
msm_cam_copy_v4l2_subdev_fops(&msm_isp_v4l2_fops);
msm_isp_v4l2_fops.unlocked_ioctl = msm_isp_v4l2_fops_ioctl;
#ifdef CONFIG_COMPAT
msm_isp_v4l2_fops.compat_ioctl32 =
msm_isp_v4l2_fops_ioctl;
#endif
vfe_dev->subdev.sd.devnode->fops = &msm_isp_v4l2_fops;
vfe_dev->buf_mgr = &vfe_buf_mgr;
v4l2_subdev_notify(&vfe_dev->subdev.sd,
MSM_SD_NOTIFY_REQ_CB, &vfe_vb2_ops);
rc = msm_isp_create_isp_buf_mgr(vfe_dev->buf_mgr,
&vfe_vb2_ops, &pdev->dev,
vfe_dev->hw_info->axi_hw_info->scratch_buf_range);
if (rc < 0) {
pr_err("%s: Unable to create buffer manager\n", __func__);
rc = -EINVAL;
goto probe_fail3;
}
msm_isp_enable_debugfs(vfe_dev, msm_isp_bw_request_history);
vfe_dev->buf_mgr->num_iommu_secure_ctx =
vfe_dev->hw_info->num_iommu_secure_ctx;
vfe_dev->buf_mgr->init_done = 1;
vfe_dev->vfe_open_cnt = 0;
return rc;
probe_fail3:
kfree(vfe_dev->ub_info);
probe_fail2:
kfree(vfe_dev->stats);
probe_fail1:
kfree(vfe_dev);
end:
return rc;
}
static struct platform_driver vfe_driver = {
.probe = vfe_probe,
.driver = {
.name = "msm_vfe",
.owner = THIS_MODULE,
.of_match_table = msm_vfe_dt_match,
},
};
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);
}
late_initcall(msm_vfe_init_module);
module_exit(msm_vfe_exit_module);
MODULE_DESCRIPTION("MSM VFE driver");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,813 @@
/* Copyright (c) 2013-2017, 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 <linux/avtimer_kernel.h>
#include <media/v4l2-subdev.h>
#include <media/ais/msm_ais_isp.h>
#include <linux/msm-bus.h>
#include <linux/msm-bus-board.h>
#include "msm_buf_mgr.h"
#include "cam_hw_ops.h"
#define VFE40_8974V1_VERSION 0x10000018
#define VFE40_8974V2_VERSION 0x1001001A
#define VFE40_8974V3_VERSION 0x1001001B
#define VFE40_8x26_VERSION 0x20000013
#define VFE40_8x26V2_VERSION 0x20010014
#define VFE40_8916_VERSION 0x10030000
#define VFE40_8939_VERSION 0x10040000
#define VFE40_8952_VERSION 0x10060000
#define VFE40_8976_VERSION 0x10050000
#define VFE40_8937_VERSION 0x10080000
#define VFE40_8917_VERSION 0x10080001
#define VFE40_8953_VERSION 0x10090000
#define VFE32_8909_VERSION 0x30600
#define MAX_IOMMU_CTX 2
#define MAX_NUM_WM 7
#define MAX_NUM_RDI 3
#define MAX_NUM_RDI_MASTER 3
#define MAX_NUM_COMPOSITE_MASK 4
#define MAX_NUM_STATS_COMP_MASK 2
#define MAX_INIT_FRAME_DROP 31
#define MAX_REG_UPDATE_THRESHOLD 10
#define ISP_Q2 (1 << 2)
#define VFE_PING_FLAG 0xFFFFFFFF
#define VFE_PONG_FLAG 0x0
#define VFE_MAX_CFG_TIMEOUT 3000
#define VFE_CLK_INFO_MAX 16
#define STATS_COMP_BIT_MASK 0x1FF
#define MSM_ISP_MIN_AB 100000000
#define MSM_ISP_MIN_IB 100000000
#define MAX_BUFFERS_IN_HW 2
#define MAX_VFE 2
#define MAX_RECOVERY_THRESHOLD 5
struct vfe_device;
struct msm_vfe_axi_stream;
struct msm_vfe_stats_stream;
#define VFE_SD_HW_MAX VFE_SD_COMMON
/* Irq operations to perform on the irq mask register */
enum msm_isp_irq_operation {
/* enable the irq bits in given parameters */
MSM_ISP_IRQ_ENABLE = 1,
/* disable the irq bits in the given parameters */
MSM_ISP_IRQ_DISABLE = 2,
/* set the irq bits to the given parameters */
MSM_ISP_IRQ_SET = 3,
};
/* This struct is used to save/track SOF info for some INTF.
* e.g. used in Master-Slave mode
*/
struct msm_vfe_sof_info {
uint32_t timestamp_ms;
uint32_t mono_timestamp_ms;
uint32_t frame_id;
};
/* Each INTF in Master-Slave mode uses this struct. */
struct msm_vfe_dual_hw_ms_info {
/* type is Master/Slave */
enum msm_vfe_dual_hw_ms_type dual_hw_ms_type;
/* sof_info is resource from common_data. If NULL, then this INTF
* sof does not need to be saved
*/
struct msm_vfe_sof_info *sof_info;
/* slave_id is index in common_data sof_info array for slaves */
uint8_t slave_id;
};
struct vfe_subscribe_info {
struct v4l2_fh *vfh;
uint32_t active;
};
enum msm_isp_pack_fmt {
QCOM,
MIPI,
DPCM6,
DPCM8,
PLAIN8,
PLAIN16,
DPCM10,
MAX_ISP_PACK_FMT,
};
enum msm_isp_camif_update_state {
NO_UPDATE,
ENABLE_CAMIF,
DISABLE_CAMIF,
DISABLE_CAMIF_IMMEDIATELY
};
struct msm_isp_timestamp {
/* Monotonic clock for v4l2 buffer */
struct timeval buf_time;
/* Monotonic clock for VT */
struct timeval vt_time;
/* Wall clock for userspace event */
struct timeval event_time;
};
struct msm_vfe_irq_ops {
void (*read_irq_status_and_clear)(struct vfe_device *vfe_dev,
uint32_t *irq_status0, uint32_t *irq_status1);
void (*read_irq_status)(struct vfe_device *vfe_dev,
uint32_t *irq_status0, uint32_t *irq_status1);
void (*process_reg_update)(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
struct msm_isp_timestamp *ts);
void (*process_epoch_irq)(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
struct msm_isp_timestamp *ts);
void (*process_reset_irq)(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1);
void (*process_halt_irq)(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1);
void (*process_camif_irq)(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
struct msm_isp_timestamp *ts);
void (*process_axi_irq)(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
uint32_t pingpong_status,
struct msm_isp_timestamp *ts);
void (*process_stats_irq)(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
uint32_t pingpong_status,
struct msm_isp_timestamp *ts);
void (*config_irq)(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
enum msm_isp_irq_operation);
void (*process_eof_irq)(struct vfe_device *vfe_dev,
uint32_t irq_status0);
};
struct msm_vfe_axi_ops {
void (*reload_wm)(struct vfe_device *vfe_dev, void __iomem *vfe_base,
uint32_t reload_mask);
void (*enable_wm)(void __iomem *vfe_base,
uint8_t wm_idx, uint8_t enable);
int32_t (*cfg_io_format)(struct vfe_device *vfe_dev,
enum msm_vfe_axi_stream_src stream_src,
uint32_t io_format);
void (*cfg_framedrop)(void __iomem *vfe_base,
struct msm_vfe_axi_stream *stream_info,
uint32_t framedrop_pattern, uint32_t framedrop_period);
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 (*clear_irq_mask)(struct vfe_device *vfe_dev);
void (*cfg_wm_reg)(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info,
uint8_t plane_idx);
void (*clear_wm_reg)(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx);
void (*cfg_wm_xbar_reg)(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info,
uint8_t plane_idx);
void (*clear_wm_xbar_reg)(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx);
void (*cfg_ub)(struct vfe_device *vfe_dev,
enum msm_vfe_input_src frame_src);
void (*read_wm_ping_pong_addr)(struct vfe_device *vfe_dev);
void (*update_ping_pong_addr)(void __iomem *vfe_base,
uint8_t wm_idx, uint32_t pingpong_bit, dma_addr_t paddr,
int32_t buf_size);
uint32_t (*get_wm_mask)(uint32_t irq_status0, uint32_t irq_status1);
uint32_t (*get_comp_mask)(uint32_t irq_status0, uint32_t irq_status1);
uint32_t (*get_pingpong_status)(struct vfe_device *vfe_dev);
int (*halt)(struct vfe_device *vfe_dev, uint32_t blocking);
int (*restart)(struct vfe_device *vfe_dev, uint32_t blocking,
uint32_t enable_camif);
void (*update_cgc_override)(struct vfe_device *vfe_dev,
uint8_t wm_idx, uint8_t cgc_override);
uint32_t (*ub_reg_offset)(struct vfe_device *vfe_dev, int idx);
uint32_t (*get_ub_size)(struct vfe_device *vfe_dev);
};
struct msm_vfe_core_ops {
void (*reg_update)(struct vfe_device *vfe_dev,
enum msm_vfe_input_src frame_src);
long (*reset_hw)(struct vfe_device *vfe_dev, uint32_t first_start,
uint32_t blocking_call);
int (*init_hw)(struct vfe_device *vfe_dev);
void (*init_hw_reg)(struct vfe_device *vfe_dev);
void (*clear_status_reg)(struct vfe_device *vfe_dev);
void (*release_hw)(struct vfe_device *vfe_dev);
void (*cfg_input_mux)(struct vfe_device *vfe_dev,
struct msm_vfe_pix_cfg *pix_cfg);
int (*start_fetch_eng)(struct vfe_device *vfe_dev,
void *arg);
void (*update_camif_state)(struct vfe_device *vfe_dev,
enum msm_isp_camif_update_state update_state);
void (*cfg_rdi_reg)(struct vfe_device *vfe_dev,
struct msm_vfe_rdi_cfg *rdi_cfg,
enum msm_vfe_input_src input_src);
void (*get_error_mask)(uint32_t *error_mask0, uint32_t *error_mask1);
void (*process_error_status)(struct vfe_device *vfe_dev);
void (*get_overflow_mask)(uint32_t *overflow_mask);
void (*get_irq_mask)(struct vfe_device *vfe_dev,
uint32_t *irq0_mask, uint32_t *irq1_mask);
void (*get_halt_restart_mask)(uint32_t *irq0_mask,
uint32_t *irq1_mask);
void (*get_rdi_wm_mask)(struct vfe_device *vfe_dev,
uint32_t *rdi_wm_mask);
bool (*is_module_cfg_lock_needed)(uint32_t reg_offset);
int (*ahb_clk_cfg)(struct vfe_device *vfe_dev,
struct msm_isp_ahb_clk_cfg *ahb_cfg);
void (*set_halt_restart_mask)(struct vfe_device *vfe_dev);
int (*start_fetch_eng_multi_pass)(struct vfe_device *vfe_dev,
void *arg);
};
struct msm_vfe_stats_ops {
int (*get_stats_idx)(enum msm_isp_stats_type stats_type);
int (*check_streams)(struct msm_vfe_stats_stream *stream_info);
void (*cfg_framedrop)(struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info,
uint32_t framedrop_pattern, uint32_t framedrop_period);
void (*clear_framedrop)(struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info);
void (*cfg_comp_mask)(struct vfe_device *vfe_dev,
uint32_t stats_mask, uint8_t comp_index,
uint8_t enable);
void (*cfg_wm_irq_mask)(struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info);
void (*clear_wm_irq_mask)(struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info);
void (*cfg_wm_reg)(struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info);
void (*clear_wm_reg)(struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info);
void (*cfg_ub)(struct vfe_device *vfe_dev);
void (*enable_module)(struct vfe_device *vfe_dev,
uint32_t stats_mask, uint8_t enable);
void (*update_ping_pong_addr)(void __iomem *vfe_base,
struct msm_vfe_stats_stream *stream_info,
uint32_t pingpong_status, dma_addr_t paddr);
uint32_t (*get_frame_id)(struct vfe_device *vfe_dev);
uint32_t (*get_wm_mask)(uint32_t irq_status0, uint32_t irq_status1);
uint32_t (*get_comp_mask)(uint32_t irq_status0, uint32_t irq_status1);
uint32_t (*get_pingpong_status)(struct vfe_device *vfe_dev);
void (*update_cgc_override)(struct vfe_device *vfe_dev,
uint32_t stats_mask, uint8_t enable);
void (*enable_stats_wm)(struct vfe_device *vfe_dev,
uint32_t stats_mask, uint8_t enable);
};
enum msm_isp_hw_client {
ISP_VFE0,
ISP_VFE1,
ISP_CPP,
MAX_ISP_CLIENT,
};
struct msm_isp_bandwidth_info {
uint32_t active;
uint64_t ab;
uint64_t ib;
};
struct msm_isp_bandwidth_mgr {
uint32_t bus_client;
uint32_t bus_vector_active_idx;
uint32_t use_count;
struct msm_isp_bandwidth_info client_info[MAX_ISP_CLIENT];
int (*update_bw)(struct msm_isp_bandwidth_mgr *isp_bandwidth_mgr);
void (*deinit_bw_mgr)(struct msm_isp_bandwidth_mgr *isp_bandwidth_mgr);
};
struct msm_vfe_platform_ops {
int (*get_platform_data)(struct vfe_device *vfe_dev);
int (*enable_clks)(struct vfe_device *vfe_dev, int enable);
int (*get_clks)(struct vfe_device *vfe_dev);
void (*put_clks)(struct vfe_device *vfe_dev);
int (*get_clk_rates)(struct vfe_device *vfe_dev,
struct msm_isp_clk_rates *rates);
int (*get_max_clk_rate)(struct vfe_device *vfe_dev, long *rate);
int (*set_clk_rate)(struct vfe_device *vfe_dev, long *rate);
int (*enable_regulators)(struct vfe_device *vfe_dev, int enable);
int (*get_regulators)(struct vfe_device *vfe_dev);
void (*put_regulators)(struct vfe_device *vfe_dev);
int (*init_bw_mgr)(struct vfe_device *vfe_dev,
struct msm_isp_bandwidth_mgr *isp_bandwidth_mgr);
int (*update_bw)(struct msm_isp_bandwidth_mgr *isp_bandwidth_mgr);
void (*deinit_bw_mgr)(struct msm_isp_bandwidth_mgr *isp_bandwidth_mgr);
};
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_platform_ops platform_ops;
};
struct msm_vfe_hardware_info {
int num_iommu_ctx;
/* secure iommu ctx nums */
int num_iommu_secure_ctx;
int vfe_clk_idx;
int runtime_axi_update;
struct msm_vfe_ops vfe_ops;
struct msm_vfe_axi_hardware_info *axi_hw_info;
struct msm_vfe_stats_hardware_info *stats_hw_info;
uint32_t dmi_reg_offset;
uint32_t min_ab;
uint32_t min_ib;
const char *regulator_names[];
};
struct msm_vfe_axi_hardware_info {
uint8_t num_wm;
uint8_t num_rdi;
uint8_t num_rdi_master;
uint8_t num_comp_mask;
uint32_t min_wm_ub;
uint32_t scratch_buf_range;
};
enum msm_vfe_axi_state {
AVAILABLE,
INACTIVE,
ACTIVE,
PAUSED,
START_PENDING,
STOP_PENDING,
PAUSE_PENDING,
RESUME_PENDING,
STARTING,
STOPPING,
PAUSING,
RESUMING,
UPDATING,
};
enum msm_vfe_axi_cfg_update_state {
NO_AXI_CFG_UPDATE,
APPLYING_UPDATE_RESUME,
UPDATE_REQUESTED,
};
#define VFE_NO_DROP 0xFFFFFFFF
#define VFE_DROP_EVERY_2FRAME 0x55555555
#define VFE_DROP_EVERY_4FRAME 0x11111111
#define VFE_DROP_EVERY_8FRAME 0x01010101
#define VFE_DROP_EVERY_16FRAME 0x00010001
#define VFE_DROP_EVERY_32FRAME 0x00000001
enum msm_vfe_axi_stream_type {
CONTINUOUS_STREAM,
BURST_STREAM,
};
struct msm_vfe_frame_request_queue {
struct list_head list;
enum msm_vfe_buff_queue_id buff_queue_id;
uint32_t buf_index;
uint8_t cmd_used;
};
#define MSM_VFE_REQUESTQ_SIZE 8
struct msm_vfe_axi_stream {
uint32_t frame_id;
enum msm_vfe_axi_state state;
enum msm_vfe_axi_stream_src stream_src;
uint8_t num_planes;
uint8_t wm[MAX_PLANES_PER_STREAM];
uint32_t output_format;/*Planar/RAW/Misc*/
struct msm_vfe_axi_plane_cfg plane_cfg[MAX_PLANES_PER_STREAM];
struct msm_vfe_axi_output_plane_cfg
vfe_plane_cfg[MAX_PLANES_PER_STREAM];
uint8_t comp_mask_index;
struct msm_isp_buffer *buf[2];
uint32_t session_id;
uint32_t stream_id;
uint32_t bufq_handle[VFE_BUF_QUEUE_MAX];
uint8_t controllable_output;
uint8_t undelivered_request_cnt;
uint8_t request_q_idx;
uint32_t request_q_cnt;
struct list_head request_q;
struct msm_vfe_frame_request_queue
request_queue_cmd[MSM_VFE_REQUESTQ_SIZE];
uint32_t stream_handle;
uint8_t buf_divert;
enum msm_vfe_axi_stream_type stream_type;
uint32_t frame_based;
enum msm_vfe_frame_skip_pattern frame_skip_pattern;
uint32_t current_framedrop_period; /* user requested period*/
uint32_t requested_framedrop_period; /* requested period*/
uint32_t activated_framedrop_period; /* active hw period */
uint32_t num_burst_capture;/*number of frame to capture*/
uint32_t init_frame_drop;
spinlock_t lock;
/* Bandwidth calculation info */
uint32_t max_width;
/* Based on format plane size in Q2. e.g NV12 = 1.5 */
uint32_t format_factor;
uint32_t bandwidth;
uint32_t runtime_num_burst_capture;
uint32_t runtime_output_format;
enum msm_stream_memory_input_t memory_input;
struct msm_isp_sw_framskip sw_skip;
uint8_t sw_ping_pong_bit;
};
struct msm_vfe_axi_composite_info {
uint32_t stream_handle;
uint32_t stream_composite_mask;
};
enum msm_vfe_camif_state {
CAMIF_STOPPED,
CAMIF_ENABLE,
CAMIF_DISABLE,
CAMIF_STOPPING,
};
struct msm_vfe_src_info {
uint32_t frame_id;
uint32_t reg_update_frame_id;
uint8_t active;
uint8_t flag;
uint8_t pix_stream_count;
uint8_t raw_stream_count;
enum msm_vfe_inputmux input_mux;
enum ISP_START_PIXEL_PATTERN pixel_pattern;
enum msm_vfe_camif_input camif_input;
uint32_t width;
long pixel_clock;
uint32_t input_format;/*V4L2 pix format with bayer pattern*/
uint32_t last_updt_frm_id;
uint32_t sof_counter_step;
struct timeval time_stamp;
enum msm_vfe_dual_hw_type dual_hw_type;
struct msm_vfe_dual_hw_ms_info dual_hw_ms_info;
uint32_t eof_id;
};
struct msm_vfe_fetch_engine_info {
uint32_t session_id;
uint32_t stream_id;
uint32_t bufq_handle;
uint32_t buf_idx;
uint8_t is_busy;
uint8_t offline_mode;
uint32_t fd;
};
enum msm_wm_ub_cfg_type {
MSM_WM_UB_CFG_DEFAULT,
MSM_WM_UB_EQUAL_SLICING,
MSM_WM_UB_CFG_MAX_NUM
};
struct msm_vfe_axi_shared_data {
struct msm_vfe_axi_hardware_info *hw_info;
struct msm_vfe_axi_stream stream_info[VFE_AXI_SRC_MAX];
uint32_t free_wm[MAX_NUM_WM];
uint32_t wm_image_size[MAX_NUM_WM];
enum msm_wm_ub_cfg_type wm_ub_cfg_policy;
uint8_t num_used_wm;
uint8_t num_active_stream;
uint8_t num_rdi_stream;
uint8_t num_pix_stream;
uint32_t rdi_wm_mask;
struct msm_vfe_axi_composite_info
composite_info[MAX_NUM_COMPOSITE_MASK];
uint8_t num_used_composite_mask;
uint32_t stream_update[VFE_SRC_MAX];
atomic_t axi_cfg_update[VFE_SRC_MAX];
enum msm_isp_camif_update_state pipeline_update;
struct msm_vfe_src_info src_info[VFE_SRC_MAX];
uint16_t stream_handle_cnt;
uint32_t event_mask;
uint8_t enable_frameid_recovery;
enum msm_vfe_camif_state camif_state;
uint32_t recovery_count;
};
struct msm_vfe_stats_hardware_info {
uint32_t stats_capability_mask;
uint8_t *stats_ping_pong_offset;
uint8_t *stats_wm_index;
uint8_t num_stats_type;
uint8_t num_stats_comp_mask;
};
enum msm_vfe_stats_state {
STATS_AVAILABLE,
STATS_INACTIVE,
STATS_ACTIVE,
STATS_START_PENDING,
STATS_STOP_PENDING,
STATS_STARTING,
STATS_STOPPING,
};
struct msm_vfe_stats_stream {
uint32_t session_id;
uint32_t stream_id;
uint32_t stream_handle;
uint32_t composite_flag;
enum msm_isp_stats_type stats_type;
enum msm_vfe_stats_state state;
uint32_t framedrop_pattern;
uint32_t framedrop_period;
uint32_t irq_subsample_pattern;
uint32_t init_stats_frame_drop;
struct msm_isp_sw_framskip sw_skip;
uint32_t buffer_offset;
struct msm_isp_buffer *buf[2];
uint32_t bufq_handle;
};
struct msm_vfe_stats_shared_data {
struct msm_vfe_stats_stream stream_info[MSM_ISP_STATS_MAX];
uint8_t num_active_stream;
atomic_t stats_comp_mask[MAX_NUM_STATS_COMP_MASK];
uint16_t stream_handle_cnt;
atomic_t stats_update;
};
struct msm_vfe_tasklet_queue_cmd {
struct list_head list;
uint32_t vfeInterruptStatus0;
uint32_t vfeInterruptStatus1;
uint32_t vfePingPongStatus;
struct msm_isp_timestamp ts;
uint8_t cmd_used;
};
#define MSM_VFE_TASKLETQ_SIZE 200
enum msm_vfe_overflow_state {
NO_OVERFLOW,
OVERFLOW_DETECTED,
HALT_ENFORCED,
};
struct msm_vfe_error_info {
atomic_t overflow_state;
uint32_t error_mask0;
uint32_t error_mask1;
uint32_t violation_status;
uint32_t camif_status;
uint8_t stream_framedrop_count[BUF_MGR_NUM_BUF_Q];
uint8_t stats_framedrop_count[MSM_ISP_STATS_MAX];
uint32_t info_dump_frame_count;
uint32_t error_count;
uint32_t framedrop_flag;
};
struct msm_isp_statistics {
int64_t imagemaster0_overflow;
int64_t imagemaster1_overflow;
int64_t imagemaster2_overflow;
int64_t imagemaster3_overflow;
int64_t imagemaster4_overflow;
int64_t imagemaster5_overflow;
int64_t imagemaster6_overflow;
int64_t be_overflow;
int64_t bg_overflow;
int64_t bf_overflow;
int64_t awb_overflow;
int64_t rs_overflow;
int64_t cs_overflow;
int64_t ihist_overflow;
int64_t skinbhist_overflow;
int64_t bfscale_overflow;
int64_t isp_vfe0_active;
int64_t isp_vfe0_ab;
int64_t isp_vfe0_ib;
int64_t isp_vfe1_active;
int64_t isp_vfe1_ab;
int64_t isp_vfe1_ib;
int64_t isp_cpp_active;
int64_t isp_cpp_ab;
int64_t isp_cpp_ib;
int64_t last_overflow_ab;
int64_t last_overflow_ib;
int64_t vfe_clk_rate;
int64_t cpp_clk_rate;
};
struct msm_isp_bw_req_info {
uint32_t client;
unsigned long long timestamp;
uint64_t total_ab;
uint64_t total_ib;
struct msm_isp_bandwidth_info client_info[MAX_ISP_CLIENT];
};
#define MSM_ISP_MAX_WM 7
struct msm_isp_ub_info {
enum msm_wm_ub_cfg_type policy;
uint8_t num_wm;
uint32_t wm_ub;
uint32_t data[MSM_ISP_MAX_WM];
uint64_t addr[MSM_ISP_MAX_WM];
};
struct msm_vfe_hw_init_parms {
const char *entries;
const char *regs;
const char *settings;
};
struct dual_vfe_resource {
struct vfe_device *vfe_dev[MAX_VFE];
void __iomem *vfe_base[MAX_VFE];
uint32_t reg_update_mask[MAX_VFE];
struct msm_vfe_stats_shared_data *stats_data[MAX_VFE];
struct msm_vfe_axi_shared_data *axi_data[MAX_VFE];
uint32_t wm_reload_mask[MAX_VFE];
uint32_t epoch_sync_mask;
};
struct master_slave_resource_info {
enum msm_vfe_dual_hw_type dual_hw_type;
struct msm_vfe_sof_info master_sof_info;
uint8_t master_active;
uint32_t sof_delta_threshold; /* Updated by Master */
uint32_t num_slave;
uint32_t reserved_slave_mask;
uint32_t slave_active_mask;
struct msm_vfe_sof_info slave_sof_info[MS_NUM_SLAVE_MAX];
};
struct msm_vfe_irq_debug_info {
uint32_t vfe_id;
struct msm_isp_timestamp ts;
uint32_t core_id;
uint32_t irq_status0[MAX_VFE];
uint32_t irq_status1[MAX_VFE];
uint32_t ping_pong_status[MAX_VFE];
};
struct msm_vfe_common_dev_data {
spinlock_t common_dev_data_lock;
struct dual_vfe_resource *dual_vfe_res;
struct master_slave_resource_info ms_resource;
};
struct msm_vfe_common_subdev {
/* parent reference */
struct vfe_parent_device *parent;
/* Media Subdevice */
struct msm_sd_subdev *subdev;
/* Buf Mgr */
struct msm_isp_buf_mgr *buf_mgr;
/* Common Data */
struct msm_vfe_common_dev_data *common_data;
};
struct vfe_device {
/* Driver private data */
struct platform_device *pdev;
struct msm_vfe_common_dev_data *common_data;
struct msm_sd_subdev subdev;
struct msm_isp_buf_mgr *buf_mgr;
/* Resource info */
struct resource *vfe_irq;
void __iomem *vfe_base;
uint32_t vfe_base_size;
void __iomem *vfe_vbif_base;
uint32_t vfe_vbif_base_size;
struct device *iommu_ctx[MAX_IOMMU_CTX];
struct msm_cam_regulator *regulator_info;
uint32_t vfe_num_regulators;
struct clk **vfe_clk;
struct msm_cam_clk_info *vfe_clk_info;
uint32_t **vfe_clk_rates;
size_t num_clk;
size_t num_rates;
enum cam_ahb_clk_vote ahb_vote;
/* Sync variables*/
struct completion reset_complete;
struct completion halt_complete;
struct completion stream_config_complete;
struct completion stats_config_complete;
struct mutex realtime_mutex;
struct mutex core_mutex;
spinlock_t shared_data_lock;
spinlock_t reg_update_lock;
spinlock_t tasklet_lock;
/* Tasklet info */
atomic_t irq_cnt;
uint8_t taskletq_idx;
struct list_head tasklet_q;
struct tasklet_struct vfe_tasklet;
struct msm_vfe_tasklet_queue_cmd
tasklet_queue_cmd[MSM_VFE_TASKLETQ_SIZE];
/* Data structures */
struct msm_vfe_hardware_info *hw_info;
struct msm_vfe_axi_shared_data axi_data;
struct msm_vfe_stats_shared_data stats_data;
struct msm_vfe_error_info error_info;
struct msm_vfe_fetch_engine_info fetch_engine_info;
enum msm_vfe_hvx_streaming_cmd hvx_cmd;
/* State variables */
uint32_t vfe_hw_version;
int vfe_clk_idx;
uint32_t vfe_open_cnt;
uint8_t vt_enable;
uint32_t vfe_ub_policy;
uint8_t reset_pending;
uint8_t reg_update_requested;
uint8_t reg_updated;
uint32_t is_split;
uint32_t dual_vfe_enable;
unsigned long page_fault_addr;
/* Debug variables */
int dump_reg;
struct msm_isp_statistics *stats;
uint64_t msm_isp_last_overflow_ab;
uint64_t msm_isp_last_overflow_ib;
uint64_t msm_isp_vfe_clk_rate;
struct msm_isp_ub_info *ub_info;
uint32_t isp_sof_debug;
uint32_t isp_raw0_debug;
uint32_t isp_raw1_debug;
uint32_t isp_raw2_debug;
/* irq info */
uint32_t irq0_mask;
uint32_t irq1_mask;
/* before halt irq info */
uint32_t recovery_irq0_mask;
uint32_t recovery_irq1_mask;
};
struct vfe_parent_device {
struct platform_device *pdev;
uint32_t num_sd;
uint32_t num_hw_sd;
struct platform_device *child_list[VFE_SD_HW_MAX];
struct msm_vfe_common_subdev *common_sd;
};
int vfe_hw_probe(struct platform_device *pdev);
void msm_isp_update_last_overflow_ab_ib(struct vfe_device *vfe_dev);
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,202 @@
/* Copyright (c) 2013-2017, 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_ISP47_H__
#define __MSM_ISP47_H__
#define VFE47_NUM_STATS_COMP 2
#define VFE47_NUM_STATS_TYPE 9
/* composite mask order */
enum msm_vfe47_stats_comp_idx {
STATS_COMP_IDX_HDR_BE = 0,
STATS_COMP_IDX_BG,
STATS_COMP_IDX_BF,
STATS_COMP_IDX_HDR_BHIST,
STATS_COMP_IDX_RS,
STATS_COMP_IDX_CS,
STATS_COMP_IDX_IHIST,
STATS_COMP_IDX_BHIST,
STATS_COMP_IDX_AEC_BG,
};
extern struct msm_vfe_hardware_info vfe47_hw_info;
void msm_vfe47_read_irq_status(struct vfe_device *vfe_dev,
uint32_t *irq_status0, uint32_t *irq_status1);
void msm_vfe47_read_irq_status_and_clear(struct vfe_device *vfe_dev,
uint32_t *irq_status0, uint32_t *irq_status1);
void msm_vfe47_enable_camif_error(struct vfe_device *vfe_dev,
int enable);
void msm_vfe47_process_reg_update(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
struct msm_isp_timestamp *ts);
void msm_vfe47_process_epoch_irq(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
struct msm_isp_timestamp *ts);
void msm_isp47_process_eof_irq(struct vfe_device *vfe_dev,
uint32_t irq_status0);
void msm_vfe47_reg_update(struct vfe_device *vfe_dev,
enum msm_vfe_input_src frame_src);
long msm_vfe47_reset_hardware(struct vfe_device *vfe_dev,
uint32_t first_start, uint32_t blocking_call);
void msm_vfe47_axi_reload_wm(struct vfe_device *vfe_dev,
void __iomem *vfe_base, uint32_t reload_mask);
void msm_vfe47_axi_update_cgc_override(struct vfe_device *vfe_dev,
uint8_t wm_idx, uint8_t enable);
void msm_vfe47_axi_cfg_comp_mask(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info);
void msm_vfe47_axi_clear_comp_mask(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info);
void msm_vfe47_axi_cfg_wm_irq_mask(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info);
void msm_vfe47_axi_clear_wm_irq_mask(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info);
void msm_vfe47_axi_clear_irq_mask(struct vfe_device *vfe_dev);
void msm_vfe47_cfg_framedrop(void __iomem *vfe_base,
struct msm_vfe_axi_stream *stream_info, uint32_t framedrop_pattern,
uint32_t framedrop_period);
void msm_vfe47_clear_framedrop(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info);
int32_t msm_vfe47_cfg_io_format(struct vfe_device *vfe_dev,
enum msm_vfe_axi_stream_src stream_src, uint32_t io_format);
int msm_vfe47_start_fetch_engine(struct vfe_device *vfe_dev,
void *arg);
void msm_vfe47_cfg_fetch_engine(struct vfe_device *vfe_dev,
struct msm_vfe_pix_cfg *pix_cfg);
void msm_vfe47_cfg_testgen(struct vfe_device *vfe_dev,
struct msm_vfe_testgen_cfg *testgen_cfg);
void msm_vfe47_cfg_camif(struct vfe_device *vfe_dev,
struct msm_vfe_pix_cfg *pix_cfg);
void msm_vfe47_cfg_input_mux(struct vfe_device *vfe_dev,
struct msm_vfe_pix_cfg *pix_cfg);
void msm_vfe47_configure_hvx(struct vfe_device *vfe_dev,
uint8_t is_stream_on);
void msm_vfe47_update_camif_state(struct vfe_device *vfe_dev,
enum msm_isp_camif_update_state update_state);
void msm_vfe47_cfg_rdi_reg(
struct vfe_device *vfe_dev, struct msm_vfe_rdi_cfg *rdi_cfg,
enum msm_vfe_input_src input_src);
void msm_vfe47_axi_cfg_wm_reg(
struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info,
uint8_t plane_idx);
void msm_vfe47_axi_clear_wm_reg(
struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx);
void msm_vfe47_axi_cfg_wm_xbar_reg(
struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info,
uint8_t plane_idx);
void msm_vfe47_axi_clear_wm_xbar_reg(
struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx);
void msm_vfe47_cfg_axi_ub_equal_default(
struct vfe_device *vfe_dev, enum msm_vfe_input_src frame_src);
void msm_vfe47_cfg_axi_ub_equal_slicing(
struct vfe_device *vfe_dev);
void msm_vfe47_cfg_axi_ub(struct vfe_device *vfe_dev,
enum msm_vfe_input_src frame_src);
void msm_vfe47_read_wm_ping_pong_addr(
struct vfe_device *vfe_dev);
void msm_vfe47_update_ping_pong_addr(
void __iomem *vfe_base,
uint8_t wm_idx, uint32_t pingpong_bit, dma_addr_t paddr,
int32_t buf_size);
int msm_vfe47_axi_halt(struct vfe_device *vfe_dev,
uint32_t blocking);
int msm_vfe47_axi_restart(struct vfe_device *vfe_dev,
uint32_t blocking, uint32_t enable_camif);
uint32_t msm_vfe47_get_wm_mask(
uint32_t irq_status0, uint32_t irq_status1);
uint32_t msm_vfe47_get_comp_mask(
uint32_t irq_status0, uint32_t irq_status1);
uint32_t msm_vfe47_get_pingpong_status(
struct vfe_device *vfe_dev);
int msm_vfe47_get_stats_idx(enum msm_isp_stats_type stats_type);
int msm_vfe47_stats_check_streams(
struct msm_vfe_stats_stream *stream_info);
void msm_vfe47_stats_cfg_comp_mask(
struct vfe_device *vfe_dev, uint32_t stats_mask,
uint8_t request_comp_index, uint8_t enable);
void msm_vfe47_stats_cfg_wm_irq_mask(
struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info);
void msm_vfe47_stats_clear_wm_irq_mask(
struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info);
void msm_vfe47_stats_cfg_wm_reg(
struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info);
void msm_vfe47_stats_clear_wm_reg(
struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info);
void msm_vfe47_stats_cfg_ub(struct vfe_device *vfe_dev);
void msm_vfe47_stats_update_cgc_override(struct vfe_device *vfe_dev,
uint32_t stats_mask, uint8_t enable);
bool msm_vfe47_is_module_cfg_lock_needed(
uint32_t reg_offset);
void msm_vfe47_stats_enable_module(struct vfe_device *vfe_dev,
uint32_t stats_mask, uint8_t enable);
void msm_vfe47_stats_update_ping_pong_addr(
void __iomem *vfe_base, struct msm_vfe_stats_stream *stream_info,
uint32_t pingpong_status, dma_addr_t paddr);
uint32_t msm_vfe47_stats_get_wm_mask(
uint32_t irq_status0, uint32_t irq_status1);
uint32_t msm_vfe47_stats_get_comp_mask(
uint32_t irq_status0, uint32_t irq_status1);
uint32_t msm_vfe47_stats_get_frame_id(
struct vfe_device *vfe_dev);
void msm_vfe47_get_error_mask(
uint32_t *error_mask0, uint32_t *error_mask1);
void msm_vfe47_get_overflow_mask(uint32_t *overflow_mask);
void msm_vfe47_get_rdi_wm_mask(struct vfe_device *vfe_dev,
uint32_t *rdi_wm_mask);
void msm_vfe47_get_irq_mask(struct vfe_device *vfe_dev,
uint32_t *irq0_mask, uint32_t *irq1_mask);
void msm_vfe47_restore_irq_mask(struct vfe_device *vfe_dev);
void msm_vfe47_get_halt_restart_mask(uint32_t *irq0_mask,
uint32_t *irq1_mask);
int msm_vfe47_init_hardware(struct vfe_device *vfe_dev);
void msm_vfe47_release_hardware(struct vfe_device *vfe_dev);
void msm_vfe47_init_hardware_reg(struct vfe_device *vfe_dev);
void msm_vfe47_process_reset_irq(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1);
void msm_vfe47_process_halt_irq(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1);
void msm_vfe47_process_input_irq(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
struct msm_isp_timestamp *ts);
void msm_vfe47_process_violation_status(
struct vfe_device *vfe_dev);
void msm_vfe47_process_error_status(struct vfe_device *vfe_dev);
void msm_vfe47_clear_status_reg(struct vfe_device *vfe_dev);
int msm_vfe47_get_platform_data(struct vfe_device *vfe_dev);
int msm_vfe47_enable_regulators(struct vfe_device *vfe_dev, int enable);
int msm_vfe47_get_regulators(struct vfe_device *vfe_dev);
void msm_vfe47_put_regulators(struct vfe_device *vfe_dev);
int msm_vfe47_enable_clks(struct vfe_device *vfe_dev, int enable);
int msm_vfe47_get_clks(struct vfe_device *vfe_dev);
void msm_vfe47_put_clks(struct vfe_device *vfe_dev);
int msm_vfe47_get_clk_rates(struct vfe_device *vfe_dev,
struct msm_isp_clk_rates *rates);
int msm_vfe47_get_max_clk_rate(struct vfe_device *vfe_dev, long *rate);
int msm_vfe47_set_clk_rate(struct vfe_device *vfe_dev, long *rate);
int msm_vfe47_init_bandwidth_mgr(struct vfe_device *vfe_dev,
struct msm_isp_bandwidth_mgr *isp_bandwidth_mgr);
void msm_vfe47_deinit_bandwidth_mgr(
struct msm_isp_bandwidth_mgr *isp_bandwidth_mgr);
int msm_vfe47_update_bandwidth(
struct msm_isp_bandwidth_mgr *isp_bandwidth_mgr);
void msm_vfe47_config_irq(struct vfe_device *vfe_dev,
uint32_t irq0_mask, uint32_t irq1_mask,
enum msm_isp_irq_operation oper);
#endif /* __MSM_ISP47_H__ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,131 @@
/* Copyright (c) 2013-2017, 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"
#define HANDLE_TO_IDX(handle) (handle & 0xFF)
#define SRC_TO_INTF(src) \
((src < RDI_INTF_0 || src == VFE_AXI_SRC_MAX) ? VFE_PIX_0 : \
(VFE_RAW_0 + src - RDI_INTF_0))
int msm_isp_axi_create_stream(struct vfe_device *vfe_dev,
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 vfe_device *vfe_dev,
struct msm_vfe_axi_shared_data *axi_data,
struct msm_vfe_axi_stream *stream_info);
void msm_isp_axi_reserve_comp_mask(
struct msm_vfe_axi_shared_data *axi_data,
struct msm_vfe_axi_stream *stream_info);
int msm_isp_axi_check_stream_state(
struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd);
int msm_isp_calculate_framedrop(
struct msm_vfe_axi_shared_data *axi_data,
struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd);
void msm_isp_reset_framedrop(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info);
int msm_isp_request_axi_stream(struct vfe_device *vfe_dev, void *arg);
void msm_isp_get_avtimer_ts(struct msm_isp_timestamp *time_stamp);
int msm_isp_cfg_axi_stream(struct vfe_device *vfe_dev, void *arg);
int msm_isp_update_stream_bandwidth(struct vfe_device *vfe_dev,
enum msm_vfe_hw_state hw_state);
int msm_isp_release_axi_stream(struct vfe_device *vfe_dev, void *arg);
int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg);
void msm_isp_axi_cfg_update(struct vfe_device *vfe_dev,
enum msm_vfe_input_src frame_src);
int msm_isp_axi_halt(struct vfe_device *vfe_dev,
struct msm_vfe_axi_halt_cmd *halt_cmd);
int msm_isp_axi_reset(struct vfe_device *vfe_dev,
struct msm_vfe_axi_reset_cmd *reset_cmd);
int msm_isp_axi_restart(struct vfe_device *vfe_dev,
struct msm_vfe_axi_restart_cmd *restart_cmd);
int msm_isp_axi_output_cfg(struct vfe_device *vfe_dev, void *arg);
void msm_isp_axi_stream_update(struct vfe_device *vfe_dev,
enum msm_vfe_input_src frame_src);
void msm_isp_update_framedrop_reg(struct vfe_device *vfe_dev,
enum msm_vfe_input_src frame_src);
void msm_isp_notify(struct vfe_device *vfe_dev, uint32_t event_type,
enum msm_vfe_input_src frame_src, struct msm_isp_timestamp *ts);
void msm_isp_process_axi_irq(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
uint32_t pingpong_status, struct msm_isp_timestamp *ts);
void msm_isp_axi_disable_all_wm(struct vfe_device *vfe_dev);
int msm_isp_print_ping_pong_address(struct vfe_device *vfe_dev,
unsigned long fault_addr);
void msm_isp_increment_frame_id(struct vfe_device *vfe_dev,
enum msm_vfe_input_src frame_src, struct msm_isp_timestamp *ts);
int msm_isp_drop_frame(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info, struct msm_isp_timestamp *ts,
struct msm_isp_sof_info *sof_info);
void msm_isp_halt(struct vfe_device *vfe_dev);
void msm_isp_halt_send_error(struct vfe_device *vfe_dev, uint32_t event);
void msm_isp_process_axi_irq_stream(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info,
uint32_t pingpong_status,
struct msm_isp_timestamp *ts);
static inline void msm_isp_cfg_wm_scratch(struct vfe_device *vfe_dev,
int wm,
uint32_t pingpong_bit)
{
vfe_dev->hw_info->vfe_ops.axi_ops.update_ping_pong_addr(
vfe_dev->vfe_base, wm,
pingpong_bit, vfe_dev->buf_mgr->scratch_buf_addr, 0);
}
static inline void msm_isp_cfg_stream_scratch(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info,
uint32_t pingpong_status)
{
int i;
uint32_t pingpong_bit;
pingpong_bit = (~(pingpong_status >> stream_info->wm[0]) & 0x1);
for (i = 0; i < stream_info->num_planes; i++)
msm_isp_cfg_wm_scratch(vfe_dev, stream_info->wm[i],
~pingpong_bit & 0x1);
stream_info->buf[pingpong_bit] = NULL;
}
int msm_isp_cfg_offline_ping_pong_address(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status,
uint32_t buf_idx);
#endif /* __MSM_ISP_AXI_UTIL_H__ */

View file

@ -0,0 +1,973 @@
/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/io.h>
#include <linux/atomic.h>
#include <media/v4l2-subdev.h>
#include <media/ais/msm_ais_isp.h>
#include "msm_isp_util.h"
#include "msm_isp_axi_util.h"
#include "msm_isp_stats_util.h"
static inline void msm_isp_stats_cfg_wm_scratch(struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info,
uint32_t pingpong_status)
{
vfe_dev->hw_info->vfe_ops.stats_ops.update_ping_pong_addr(
vfe_dev->vfe_base, stream_info,
pingpong_status, vfe_dev->buf_mgr->scratch_buf_addr);
}
static inline void msm_isp_stats_cfg_stream_scratch(struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info,
uint32_t pingpong_status)
{
uint32_t stats_idx = STATS_IDX(stream_info->stream_handle);
uint32_t pingpong_bit;
uint32_t stats_pingpong_offset =
vfe_dev->hw_info->stats_hw_info->stats_ping_pong_offset[
stats_idx];
pingpong_bit = (~(pingpong_status >> stats_pingpong_offset) & 0x1);
msm_isp_stats_cfg_wm_scratch(vfe_dev, stream_info,
pingpong_status);
stream_info->buf[pingpong_bit] = NULL;
}
static int msm_isp_stats_cfg_ping_pong_address(struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info, uint32_t pingpong_status)
{
int rc = -1, vfe_id = 0;
struct msm_isp_buffer *buf;
uint32_t pingpong_bit = 0;
uint32_t stats_pingpong_offset;
uint32_t bufq_handle = stream_info->bufq_handle;
uint32_t stats_idx = STATS_IDX(stream_info->stream_handle);
struct dual_vfe_resource *dual_vfe_res = NULL;
struct msm_vfe_stats_stream *dual_vfe_stream_info = NULL;
if (stats_idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type ||
stats_idx >= MSM_ISP_STATS_MAX) {
pr_err("%s Invalid stats index %d", __func__, stats_idx);
return -EINVAL;
}
stats_pingpong_offset =
vfe_dev->hw_info->stats_hw_info->stats_ping_pong_offset[
stats_idx];
pingpong_bit = (~(pingpong_status >> stats_pingpong_offset) & 0x1);
rc = vfe_dev->buf_mgr->ops->get_buf(vfe_dev->buf_mgr,
bufq_handle,
MSM_ISP_INVALID_BUF_INDEX, &buf);
if (rc == -EFAULT) {
msm_isp_halt_send_error(vfe_dev, ISP_EVENT_BUF_FATAL_ERROR);
return rc;
}
if (rc < 0 || NULL == buf)
vfe_dev->error_info.stats_framedrop_count[stats_idx]++;
if (buf && buf->num_planes != 1) {
pr_err("%s: Invalid buffer\n", __func__);
msm_isp_halt_send_error(vfe_dev, ISP_EVENT_BUF_FATAL_ERROR);
rc = -EINVAL;
goto buf_error;
}
if (vfe_dev->is_split) {
dual_vfe_res = vfe_dev->common_data->dual_vfe_res;
if (!dual_vfe_res->vfe_base[ISP_VFE0] ||
!dual_vfe_res->stats_data[ISP_VFE0] ||
!dual_vfe_res->vfe_base[ISP_VFE1] ||
!dual_vfe_res->stats_data[ISP_VFE1]) {
pr_err("%s:%d error vfe0 %pK %pK vfe1 %pK %pK\n",
__func__, __LINE__,
dual_vfe_res->vfe_base[ISP_VFE0],
dual_vfe_res->stats_data[ISP_VFE0],
dual_vfe_res->vfe_base[ISP_VFE1],
dual_vfe_res->stats_data[ISP_VFE1]);
} else {
for (vfe_id = 0; vfe_id < MAX_VFE; vfe_id++) {
dual_vfe_stream_info = &dual_vfe_res->
stats_data[vfe_id]->
stream_info[stats_idx];
if (buf)
vfe_dev->hw_info->vfe_ops.stats_ops.
update_ping_pong_addr(
dual_vfe_res->vfe_base[vfe_id],
dual_vfe_stream_info,
pingpong_status,
buf->mapped_info[0].paddr +
dual_vfe_stream_info->
buffer_offset);
else
msm_isp_stats_cfg_stream_scratch(
vfe_dev,
dual_vfe_stream_info,
pingpong_status);
dual_vfe_stream_info->buf[pingpong_bit]
= buf;
}
}
} else {
if (buf)
vfe_dev->hw_info->vfe_ops.stats_ops.
update_ping_pong_addr(
vfe_dev->vfe_base, stream_info,
pingpong_status, buf->mapped_info[0].paddr +
stream_info->buffer_offset);
else
msm_isp_stats_cfg_stream_scratch(vfe_dev,
stream_info, pingpong_status);
stream_info->buf[pingpong_bit] = buf;
}
if (buf)
buf->pingpong_bit = pingpong_bit;
return 0;
buf_error:
vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr,
buf->bufq_handle, buf->buf_idx);
return rc;
}
static int32_t msm_isp_stats_buf_divert(struct vfe_device *vfe_dev,
struct msm_isp_timestamp *ts,
struct msm_isp_event_data *buf_event,
struct msm_vfe_stats_stream *stream_info,
uint32_t *comp_stats_type_mask, uint32_t pingpong_status)
{
int32_t rc = 0, frame_id = 0, drop_buffer = 0;
struct msm_isp_stats_event *stats_event = NULL;
struct msm_isp_sw_framskip *sw_skip = NULL;
int32_t buf_index = -1;
uint32_t pingpong_bit;
struct msm_isp_buffer *done_buf;
uint32_t stats_pingpong_offset;
uint32_t stats_idx;
if (!vfe_dev || !ts || !buf_event || !stream_info) {
pr_err("%s:%d failed: invalid params %pK %pK %pK %pK\n",
__func__, __LINE__, vfe_dev, ts, buf_event,
stream_info);
return -EINVAL;
}
frame_id = vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
sw_skip = &stream_info->sw_skip;
stats_event = &buf_event->u.stats;
if (sw_skip->stats_type_mask &
(1 << stream_info->stats_type)) {
/* Hw stream output of this src is requested
* for drop
*/
if (sw_skip->skip_mode == SKIP_ALL) {
/* drop all buffers */
drop_buffer = 1;
} else if (sw_skip->skip_mode == SKIP_RANGE &&
(sw_skip->min_frame_id <= frame_id &&
sw_skip->max_frame_id >= frame_id)) {
drop_buffer = 1;
} else if (frame_id > sw_skip->max_frame_id) {
memset(sw_skip, 0, sizeof
(struct msm_isp_sw_framskip));
}
}
stats_idx = STATS_IDX(stream_info->stream_handle);
stats_pingpong_offset =
vfe_dev->hw_info->stats_hw_info->stats_ping_pong_offset[
stats_idx];
pingpong_bit = (~(pingpong_status >> stats_pingpong_offset) & 0x1);
done_buf = stream_info->buf[pingpong_bit];
if (done_buf)
buf_index = done_buf->buf_idx;
rc = vfe_dev->buf_mgr->ops->update_put_buf_cnt(
vfe_dev->buf_mgr, vfe_dev->pdev->id, stream_info->bufq_handle,
buf_index, &ts->buf_time,
frame_id, pingpong_bit);
if (rc < 0) {
if (rc == -EFAULT)
msm_isp_halt_send_error(vfe_dev,
ISP_EVENT_PING_PONG_MISMATCH);
pr_err("stats_buf_divert: update put buf cnt fail\n");
return rc;
}
if (rc > 0) {
ISP_DBG("%s: vfe_id %d buf_id %d bufq %x put_cnt 1\n", __func__,
vfe_dev->pdev->id, buf_index,
stream_info->bufq_handle);
return rc;
}
/* Program next buffer */
rc = msm_isp_stats_cfg_ping_pong_address(vfe_dev, stream_info,
pingpong_status);
if (rc)
return rc;
if (drop_buffer && done_buf) {
rc = vfe_dev->buf_mgr->ops->buf_done(
vfe_dev->buf_mgr,
done_buf->bufq_handle,
done_buf->buf_idx, &ts->buf_time, frame_id, 0);
if (rc == -EFAULT)
msm_isp_halt_send_error(vfe_dev,
ISP_EVENT_BUF_FATAL_ERROR);
return rc;
}
if (done_buf) {
stats_event->stats_buf_idxs
[stream_info->stats_type] =
done_buf->buf_idx;
if (comp_stats_type_mask == NULL) {
stats_event->stats_mask =
1 << stream_info->stats_type;
ISP_DBG("%s: stats frameid: 0x%x %d bufq %x\n",
__func__, buf_event->frame_id,
stream_info->stats_type, done_buf->bufq_handle);
msm_isp_send_event(vfe_dev,
ISP_EVENT_STATS_NOTIFY +
stream_info->stats_type,
buf_event);
} else {
*comp_stats_type_mask |=
1 << stream_info->stats_type;
}
}
return rc;
}
static int32_t msm_isp_stats_configure(struct vfe_device *vfe_dev,
uint32_t stats_irq_mask, struct msm_isp_timestamp *ts,
uint32_t pingpong_status, bool is_composite)
{
int i, rc = 0;
struct msm_isp_event_data buf_event;
struct msm_isp_stats_event *stats_event = &buf_event.u.stats;
struct msm_vfe_stats_stream *stream_info = NULL;
uint32_t comp_stats_type_mask = 0;
int result = 0;
memset(&buf_event, 0, sizeof(struct msm_isp_event_data));
buf_event.timestamp = ts->buf_time;
buf_event.frame_id = vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
for (i = 0; i < vfe_dev->hw_info->stats_hw_info->num_stats_type; i++) {
if (!(stats_irq_mask & (1 << i)))
continue;
stream_info = &vfe_dev->stats_data.stream_info[i];
if (stream_info->state == STATS_INACTIVE) {
pr_debug("%s: Warning! Stream already inactive. Drop irq handling\n",
__func__);
continue;
}
rc = msm_isp_stats_buf_divert(vfe_dev, ts,
&buf_event, stream_info,
is_composite ? &comp_stats_type_mask : NULL,
pingpong_status);
if (rc < 0) {
pr_err("%s:%d failed: stats buf divert rc %d\n",
__func__, __LINE__, rc);
result = rc;
}
}
if (is_composite && comp_stats_type_mask) {
ISP_DBG("%s:vfe_id %d comp_stats frameid %x,comp_mask %x\n",
__func__, vfe_dev->pdev->id, buf_event.frame_id,
comp_stats_type_mask);
stats_event->stats_mask = comp_stats_type_mask;
msm_isp_send_event(vfe_dev,
ISP_EVENT_COMP_STATS_NOTIFY, &buf_event);
comp_stats_type_mask = 0;
}
return result;
}
void msm_isp_process_stats_irq(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
uint32_t pingpong_status, struct msm_isp_timestamp *ts)
{
int j, rc;
uint32_t atomic_stats_mask = 0;
uint32_t stats_comp_mask = 0, stats_irq_mask = 0;
bool comp_flag = false;
uint32_t num_stats_comp_mask =
vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask;
stats_comp_mask = vfe_dev->hw_info->vfe_ops.stats_ops.
get_comp_mask(irq_status0, irq_status1);
stats_irq_mask = vfe_dev->hw_info->vfe_ops.stats_ops.
get_wm_mask(irq_status0, irq_status1);
if (!(stats_comp_mask || stats_irq_mask))
return;
ISP_DBG("%s: vfe %d status: 0x%x\n", __func__, vfe_dev->pdev->id,
irq_status0);
/* Clear composite mask irq bits, they will be restored by comp mask */
for (j = 0; j < num_stats_comp_mask; j++) {
stats_irq_mask &= ~atomic_read(
&vfe_dev->stats_data.stats_comp_mask[j]);
}
/* Process non-composite irq */
if (stats_irq_mask) {
rc = msm_isp_stats_configure(vfe_dev, stats_irq_mask, ts,
pingpong_status, comp_flag);
}
/* Process composite irq */
if (stats_comp_mask) {
for (j = 0; j < num_stats_comp_mask; j++) {
if (!(stats_comp_mask & (1 << j)))
continue;
atomic_stats_mask = atomic_read(
&vfe_dev->stats_data.stats_comp_mask[j]);
rc = msm_isp_stats_configure(vfe_dev, atomic_stats_mask,
ts, pingpong_status, !comp_flag);
}
}
}
int msm_isp_stats_create_stream(struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream_request_cmd *stream_req_cmd)
{
int rc = -1;
struct msm_vfe_stats_stream *stream_info = NULL;
struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
uint32_t stats_idx;
if (!(vfe_dev->hw_info->stats_hw_info->stats_capability_mask &
(1 << stream_req_cmd->stats_type))) {
pr_err("%s: Stats type not supported\n", __func__);
return rc;
}
stats_idx = vfe_dev->hw_info->vfe_ops.stats_ops.
get_stats_idx(stream_req_cmd->stats_type);
if (stats_idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) {
pr_err("%s Invalid stats index %d", __func__, stats_idx);
return -EINVAL;
}
stream_info = &stats_data->stream_info[stats_idx];
if (stream_info->state != STATS_AVAILABLE) {
pr_err("%s: Stats already requested\n", __func__);
return rc;
}
if (stream_req_cmd->framedrop_pattern >= MAX_SKIP) {
pr_err("%s: Invalid framedrop pattern\n", __func__);
return rc;
}
if (stream_req_cmd->irq_subsample_pattern >= MAX_SKIP) {
pr_err("%s: Invalid irq subsample pattern\n", __func__);
return rc;
}
stream_info->session_id = stream_req_cmd->session_id;
stream_info->stream_id = stream_req_cmd->stream_id;
stream_info->composite_flag = stream_req_cmd->composite_flag;
stream_info->stats_type = stream_req_cmd->stats_type;
stream_info->buffer_offset = stream_req_cmd->buffer_offset;
stream_info->framedrop_pattern = stream_req_cmd->framedrop_pattern;
stream_info->init_stats_frame_drop = stream_req_cmd->init_frame_drop;
stream_info->irq_subsample_pattern =
stream_req_cmd->irq_subsample_pattern;
stream_info->state = STATS_INACTIVE;
if ((vfe_dev->stats_data.stream_handle_cnt << 8) == 0)
vfe_dev->stats_data.stream_handle_cnt++;
stream_req_cmd->stream_handle =
(++vfe_dev->stats_data.stream_handle_cnt) << 8 | stats_idx;
stream_info->stream_handle = stream_req_cmd->stream_handle;
return 0;
}
int msm_isp_request_stats_stream(struct vfe_device *vfe_dev, void *arg)
{
int rc = -1;
struct msm_vfe_stats_stream_request_cmd *stream_req_cmd = arg;
struct msm_vfe_stats_stream *stream_info = NULL;
struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
uint32_t framedrop_period;
uint32_t stats_idx;
rc = msm_isp_stats_create_stream(vfe_dev, stream_req_cmd);
if (rc < 0) {
pr_err("%s: create stream failed\n", __func__);
return rc;
}
stats_idx = STATS_IDX(stream_req_cmd->stream_handle);
if (stats_idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) {
pr_err("%s Invalid stats index %d", __func__, stats_idx);
return -EINVAL;
}
stream_info = &stats_data->stream_info[stats_idx];
framedrop_period = msm_isp_get_framedrop_period(
stream_req_cmd->framedrop_pattern);
if (stream_req_cmd->framedrop_pattern == SKIP_ALL)
stream_info->framedrop_pattern = 0x0;
else
stream_info->framedrop_pattern = 0x1;
stream_info->framedrop_period = framedrop_period - 1;
if (stream_info->init_stats_frame_drop == 0)
vfe_dev->hw_info->vfe_ops.stats_ops.cfg_wm_reg(vfe_dev,
stream_info);
msm_isp_stats_cfg_stream_scratch(vfe_dev, stream_info,
VFE_PING_FLAG);
msm_isp_stats_cfg_stream_scratch(vfe_dev, stream_info,
VFE_PONG_FLAG);
return rc;
}
int msm_isp_release_stats_stream(struct vfe_device *vfe_dev, void *arg)
{
int rc = -1;
struct msm_vfe_stats_stream_cfg_cmd stream_cfg_cmd;
struct msm_vfe_stats_stream_release_cmd *stream_release_cmd = arg;
struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
int stats_idx = STATS_IDX(stream_release_cmd->stream_handle);
struct msm_vfe_stats_stream *stream_info = NULL;
if (stats_idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) {
pr_err("%s Invalid stats index %d", __func__, stats_idx);
return -EINVAL;
}
stream_info = &stats_data->stream_info[stats_idx];
if (stream_info->state == STATS_AVAILABLE) {
pr_err("%s: stream already release\n", __func__);
return rc;
} else if (stream_info->state != STATS_INACTIVE) {
stream_cfg_cmd.enable = 0;
stream_cfg_cmd.num_streams = 1;
stream_cfg_cmd.stream_handle[0] =
stream_release_cmd->stream_handle;
rc = msm_isp_cfg_stats_stream(vfe_dev, &stream_cfg_cmd);
}
vfe_dev->hw_info->vfe_ops.stats_ops.clear_wm_reg(vfe_dev, stream_info);
memset(stream_info, 0, sizeof(struct msm_vfe_stats_stream));
return 0;
}
static int msm_isp_init_stats_ping_pong_reg(
struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info)
{
int rc = 0;
stream_info->bufq_handle =
vfe_dev->buf_mgr->ops->get_bufq_handle(
vfe_dev->buf_mgr, stream_info->session_id,
stream_info->stream_id);
if (stream_info->bufq_handle == 0) {
pr_err("%s: no buf configured for stream: 0x%x\n",
__func__, stream_info->stream_handle);
return -EINVAL;
}
if ((vfe_dev->is_split && vfe_dev->pdev->id == 1) ||
!vfe_dev->is_split) {
rc = msm_isp_stats_cfg_ping_pong_address(vfe_dev,
stream_info, VFE_PING_FLAG);
if (rc < 0) {
pr_err("%s: No free buffer for ping\n", __func__);
return rc;
}
rc = msm_isp_stats_cfg_ping_pong_address(vfe_dev,
stream_info, VFE_PONG_FLAG);
if (rc < 0) {
pr_err("%s: No free buffer for pong\n", __func__);
return rc;
}
}
return rc;
}
void msm_isp_update_stats_framedrop_reg(struct vfe_device *vfe_dev)
{
int i;
struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
struct msm_vfe_stats_stream *stream_info = NULL;
for (i = 0; i < vfe_dev->hw_info->stats_hw_info->num_stats_type; i++) {
stream_info = &stats_data->stream_info[i];
if (stream_info->state != STATS_ACTIVE)
continue;
if (stream_info->init_stats_frame_drop) {
stream_info->init_stats_frame_drop--;
if (stream_info->init_stats_frame_drop == 0) {
vfe_dev->hw_info->vfe_ops.stats_ops.cfg_wm_reg(
vfe_dev, stream_info);
}
}
}
}
void msm_isp_stats_stream_update(struct vfe_device *vfe_dev)
{
int i;
uint32_t enable = 0;
uint8_t comp_flag = 0;
struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
struct msm_vfe_stats_ops *stats_ops =
&vfe_dev->hw_info->vfe_ops.stats_ops;
for (i = 0; i < vfe_dev->hw_info->stats_hw_info->num_stats_type; i++) {
if (stats_data->stream_info[i].state == STATS_START_PENDING ||
stats_data->stream_info[i].state ==
STATS_STOP_PENDING) {
enable = stats_data->stream_info[i].state ==
STATS_START_PENDING ? 1 : 0;
stats_data->stream_info[i].state =
stats_data->stream_info[i].state ==
STATS_START_PENDING ?
STATS_STARTING : STATS_STOPPING;
vfe_dev->hw_info->vfe_ops.stats_ops.enable_module(
vfe_dev, BIT(i), enable);
comp_flag = stats_data->stream_info[i].composite_flag;
if (comp_flag)
stats_ops->cfg_comp_mask(vfe_dev, BIT(i),
(comp_flag - 1), enable);
} else if (stats_data->stream_info[i].state == STATS_STARTING ||
stats_data->stream_info[i].state == STATS_STOPPING) {
stats_data->stream_info[i].state =
stats_data->stream_info[i].state ==
STATS_STARTING ? STATS_ACTIVE : STATS_INACTIVE;
}
}
atomic_sub(1, &stats_data->stats_update);
if (!atomic_read(&stats_data->stats_update))
complete(&vfe_dev->stats_config_complete);
}
static int msm_isp_stats_wait_for_cfg_done(struct vfe_device *vfe_dev)
{
int rc;
init_completion(&vfe_dev->stats_config_complete);
atomic_set(&vfe_dev->stats_data.stats_update, 2);
rc = wait_for_completion_timeout(
&vfe_dev->stats_config_complete,
msecs_to_jiffies(VFE_MAX_CFG_TIMEOUT));
if (rc == 0) {
pr_err("%s: wait timeout\n", __func__);
rc = -1;
} else {
rc = 0;
}
return rc;
}
static int msm_isp_stats_update_cgc_override(struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd)
{
int i;
uint32_t stats_mask = 0, idx;
if (stream_cfg_cmd->num_streams > MSM_ISP_STATS_MAX) {
pr_err("%s invalid num_streams %d\n", __func__,
stream_cfg_cmd->num_streams);
return -EINVAL;
}
for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]);
if (idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) {
pr_err("%s Invalid stats index %d", __func__, idx);
return -EINVAL;
}
stats_mask |= 1 << idx;
}
if (vfe_dev->hw_info->vfe_ops.stats_ops.update_cgc_override) {
vfe_dev->hw_info->vfe_ops.stats_ops.update_cgc_override(
vfe_dev, stats_mask, stream_cfg_cmd->enable);
}
return 0;
}
int msm_isp_stats_reset(struct vfe_device *vfe_dev)
{
int i = 0, rc = 0;
struct msm_vfe_stats_stream *stream_info = NULL;
struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
struct msm_isp_timestamp timestamp;
msm_isp_get_timestamp(&timestamp, vfe_dev);
for (i = 0; i < MSM_ISP_STATS_MAX; i++) {
stream_info = &stats_data->stream_info[i];
if (stream_info->state != STATS_ACTIVE)
continue;
rc = vfe_dev->buf_mgr->ops->flush_buf(vfe_dev->buf_mgr,
vfe_dev->pdev->id, stream_info->bufq_handle,
MSM_ISP_BUFFER_FLUSH_ALL, &timestamp.buf_time,
vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id);
if (rc == -EFAULT) {
msm_isp_halt_send_error(vfe_dev,
ISP_EVENT_BUF_FATAL_ERROR);
return rc;
}
}
return rc;
}
int msm_isp_stats_restart(struct vfe_device *vfe_dev)
{
int i = 0;
struct msm_vfe_stats_stream *stream_info = NULL;
struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
for (i = 0; i < MSM_ISP_STATS_MAX; i++) {
stream_info = &stats_data->stream_info[i];
if (stream_info->state < STATS_ACTIVE)
continue;
msm_isp_init_stats_ping_pong_reg(vfe_dev, stream_info);
}
return 0;
}
static int msm_isp_start_stats_stream(struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd)
{
int i, rc = 0;
uint32_t stats_mask = 0, idx;
uint32_t comp_stats_mask[MAX_NUM_STATS_COMP_MASK] = {0};
uint32_t num_stats_comp_mask = 0;
struct msm_vfe_stats_stream *stream_info;
struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
if (stream_cfg_cmd->num_streams > MSM_ISP_STATS_MAX) {
pr_err("%s invalid num_streams %d\n", __func__,
stream_cfg_cmd->num_streams);
return -EINVAL;
}
num_stats_comp_mask =
vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask;
rc = vfe_dev->hw_info->vfe_ops.stats_ops.check_streams(
stats_data->stream_info);
if (rc < 0)
return rc;
for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]);
if (idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) {
pr_err("%s Invalid stats index %d", __func__, idx);
return -EINVAL;
}
stream_info = &stats_data->stream_info[idx];
if (stream_info->stream_handle !=
stream_cfg_cmd->stream_handle[i]) {
pr_err("%s: Invalid stream handle: 0x%x received\n",
__func__, stream_cfg_cmd->stream_handle[i]);
continue;
}
if (stream_info->composite_flag > num_stats_comp_mask) {
pr_err("%s: comp grp %d exceed max %d\n",
__func__, stream_info->composite_flag,
num_stats_comp_mask);
return -EINVAL;
}
rc = msm_isp_init_stats_ping_pong_reg(vfe_dev, stream_info);
if (rc < 0) {
pr_err("%s: No buffer for stream%d\n", __func__, idx);
return rc;
}
if (!stream_info->composite_flag)
vfe_dev->hw_info->vfe_ops.stats_ops.
cfg_wm_irq_mask(vfe_dev, stream_info);
if (vfe_dev->axi_data.src_info[VFE_PIX_0].active)
stream_info->state = STATS_START_PENDING;
else
stream_info->state = STATS_ACTIVE;
stats_data->num_active_stream++;
stats_mask |= 1 << idx;
if (stream_info->composite_flag > 0)
comp_stats_mask[stream_info->composite_flag-1] |=
1 << idx;
ISP_DBG("%s: stats_mask %x %x active streams %d\n",
__func__, comp_stats_mask[0],
comp_stats_mask[1],
stats_data->num_active_stream);
}
if (vfe_dev->axi_data.src_info[VFE_PIX_0].active) {
rc = msm_isp_stats_wait_for_cfg_done(vfe_dev);
} else {
vfe_dev->hw_info->vfe_ops.stats_ops.enable_module(
vfe_dev, stats_mask, stream_cfg_cmd->enable);
for (i = 0; i < num_stats_comp_mask; i++) {
vfe_dev->hw_info->vfe_ops.stats_ops.cfg_comp_mask(
vfe_dev, comp_stats_mask[i], i, 1);
}
}
return rc;
}
static int msm_isp_stop_stats_stream(struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd)
{
int i, rc = 0;
uint32_t stats_mask = 0, idx;
uint32_t comp_stats_mask[MAX_NUM_STATS_COMP_MASK] = {0};
uint32_t num_stats_comp_mask = 0;
struct msm_vfe_stats_stream *stream_info;
struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
struct msm_isp_timestamp timestamp;
msm_isp_get_timestamp(&timestamp, vfe_dev);
num_stats_comp_mask =
vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask;
for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]);
if (idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) {
pr_err("%s Invalid stats index %d", __func__, idx);
return -EINVAL;
}
stream_info = &stats_data->stream_info[idx];
if (stream_info->stream_handle !=
stream_cfg_cmd->stream_handle[i]) {
pr_err("%s: Invalid stream handle: 0x%x received\n",
__func__, stream_cfg_cmd->stream_handle[i]);
continue;
}
if (stream_info->composite_flag > num_stats_comp_mask) {
pr_err("%s: comp grp %d exceed max %d\n",
__func__, stream_info->composite_flag,
num_stats_comp_mask);
return -EINVAL;
}
if (!stream_info->composite_flag)
vfe_dev->hw_info->vfe_ops.stats_ops.
clear_wm_irq_mask(vfe_dev, stream_info);
if (vfe_dev->axi_data.src_info[VFE_PIX_0].active)
stream_info->state = STATS_STOP_PENDING;
else
stream_info->state = STATS_INACTIVE;
stats_data->num_active_stream--;
stats_mask |= 1 << idx;
if (stream_info->composite_flag > 0)
comp_stats_mask[stream_info->composite_flag-1] |=
1 << idx;
msm_isp_stats_cfg_stream_scratch(vfe_dev, stream_info,
VFE_PING_FLAG);
msm_isp_stats_cfg_stream_scratch(vfe_dev, stream_info,
VFE_PONG_FLAG);
ISP_DBG("%s: stats_mask %x %x active streams %d\n",
__func__, comp_stats_mask[0],
comp_stats_mask[1],
stats_data->num_active_stream);
}
if (vfe_dev->axi_data.src_info[VFE_PIX_0].active) {
rc = msm_isp_stats_wait_for_cfg_done(vfe_dev);
} else {
vfe_dev->hw_info->vfe_ops.stats_ops.enable_module(
vfe_dev, stats_mask, stream_cfg_cmd->enable);
for (i = 0; i < num_stats_comp_mask; i++) {
vfe_dev->hw_info->vfe_ops.stats_ops.cfg_comp_mask(
vfe_dev, comp_stats_mask[i], i, 0);
}
}
for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]);
if (idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) {
pr_err("%s Invalid stats index %d", __func__, idx);
return -EINVAL;
}
stream_info = &stats_data->stream_info[idx];
rc = vfe_dev->buf_mgr->ops->flush_buf(vfe_dev->buf_mgr,
vfe_dev->pdev->id, stream_info->bufq_handle,
MSM_ISP_BUFFER_FLUSH_ALL, &timestamp.buf_time,
vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id);
if (rc == -EFAULT) {
msm_isp_halt_send_error(vfe_dev,
ISP_EVENT_BUF_FATAL_ERROR);
return rc;
}
}
return rc;
}
int msm_isp_cfg_stats_stream(struct vfe_device *vfe_dev, void *arg)
{
int rc = 0;
struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd = arg;
if (vfe_dev->stats_data.num_active_stream == 0)
vfe_dev->hw_info->vfe_ops.stats_ops.cfg_ub(vfe_dev);
if (stream_cfg_cmd->enable) {
msm_isp_stats_update_cgc_override(vfe_dev, stream_cfg_cmd);
rc = msm_isp_start_stats_stream(vfe_dev, stream_cfg_cmd);
} else {
rc = msm_isp_stop_stats_stream(vfe_dev, stream_cfg_cmd);
msm_isp_stats_update_cgc_override(vfe_dev, stream_cfg_cmd);
}
return rc;
}
int msm_isp_update_stats_stream(struct vfe_device *vfe_dev, void *arg)
{
int rc = 0, i;
struct msm_vfe_stats_stream *stream_info;
struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
struct msm_vfe_axi_stream_update_cmd *update_cmd = arg;
struct msm_vfe_axi_stream_cfg_update_info *update_info = NULL;
struct msm_isp_sw_framskip *sw_skip_info = NULL;
/* validate request */
for (i = 0; i < update_cmd->num_streams; i++) {
update_info = (struct msm_vfe_axi_stream_cfg_update_info *)
&update_cmd->update_info[i];
/* check array reference bounds */
if (STATS_IDX(update_info->stream_handle)
> vfe_dev->hw_info->stats_hw_info->num_stats_type) {
pr_err("%s: stats idx %d out of bound!", __func__,
STATS_IDX(update_info->stream_handle));
return -EINVAL;
}
}
for (i = 0; i < update_cmd->num_streams; i++) {
update_info = (struct msm_vfe_axi_stream_cfg_update_info *)
&update_cmd->update_info[i];
stream_info = &stats_data->stream_info[
STATS_IDX(
update_info->stream_handle)];
if (stream_info->stream_handle !=
update_info->stream_handle) {
pr_err("%s: stats stream handle %x %x mismatch!\n",
__func__, stream_info->stream_handle,
update_info->stream_handle);
continue;
}
switch (update_cmd->update_type) {
case UPDATE_STREAM_STATS_FRAMEDROP_PATTERN: {
uint32_t framedrop_period =
msm_isp_get_framedrop_period(
update_info->skip_pattern);
if (update_info->skip_pattern ==
SKIP_ALL)
stream_info->framedrop_pattern = 0x0;
else
stream_info->framedrop_pattern = 0x1;
stream_info->framedrop_period = framedrop_period - 1;
if (stream_info->init_stats_frame_drop == 0)
vfe_dev->hw_info->vfe_ops.stats_ops.cfg_wm_reg(
vfe_dev, stream_info);
break;
}
case UPDATE_STREAM_SW_FRAME_DROP: {
sw_skip_info =
&update_info->sw_skip_info;
if (!stream_info->sw_skip.stream_src_mask)
stream_info->sw_skip = *sw_skip_info;
if (sw_skip_info->stats_type_mask != 0) {
/* No image buffer skip, only stats skip */
pr_debug("%s:%x skip type %x mode %d min %d max %d\n",
__func__, stream_info->stream_id,
sw_skip_info->stats_type_mask,
sw_skip_info->skip_mode,
sw_skip_info->min_frame_id,
sw_skip_info->max_frame_id);
stream_info->sw_skip.stats_type_mask =
sw_skip_info->stats_type_mask;
}
break;
}
default:
pr_err("%s: Invalid update type\n", __func__);
return -EINVAL;
}
}
return rc;
}
void msm_isp_stats_disable(struct vfe_device *vfe_dev)
{
int i;
unsigned int mask = 0;
if (!vfe_dev) {
pr_err("%s: error NULL ptr\n", __func__);
return;
}
for (i = 0; i < vfe_dev->hw_info->stats_hw_info->num_stats_type; i++)
mask |= 1 << i;
vfe_dev->hw_info->vfe_ops.stats_ops.enable_module(vfe_dev, mask, 0);
}

View file

@ -0,0 +1,31 @@
/* Copyright (c) 2013-2017, 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"
#define STATS_IDX(idx) (idx & 0xFF)
void msm_isp_process_stats_irq(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
uint32_t pingpong_status, struct msm_isp_timestamp *ts);
void msm_isp_stats_stream_update(struct vfe_device *vfe_dev);
int msm_isp_cfg_stats_stream(struct vfe_device *vfe_dev, void *arg);
int msm_isp_update_stats_stream(struct vfe_device *vfe_dev, void *arg);
int msm_isp_release_stats_stream(struct vfe_device *vfe_dev, void *arg);
int msm_isp_request_stats_stream(struct vfe_device *vfe_dev, void *arg);
void msm_isp_update_stats_framedrop_reg(struct vfe_device *vfe_dev);
void msm_isp_stats_disable(struct vfe_device *vfe_dev);
int msm_isp_stats_reset(struct vfe_device *vfe_dev);
int msm_isp_stats_restart(struct vfe_device *vfe_dev);
#endif /* __MSM_ISP_STATS_UTIL_H__ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,105 @@
/* Copyright (c) 2013-2017, 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"
#include <soc/qcom/ais.h>
#include "msm_camera_io_util.h"
/* #define CONFIG_MSM_ISP_DBG 1 */
#ifdef CONFIG_MSM_ISP_DBG
#define ISP_DBG(fmt, args...) printk(fmt, ##args)
#else
#define ISP_DBG(fmt, args...) pr_debug(fmt, ##args)
#endif
#define ALT_VECTOR_IDX(x) {x = 3 - x; }
#define MAX_ISP_PING_PONG_DUMP_SIZE 20
struct ping_pong_state {
uint32_t vfe_id;
uint32_t irq_status0;
uint32_t irq_status1;
uint32_t ping_pong_status;
uint32_t core;
struct msm_isp_timestamp ts;
};
struct dual_vfe_state {
struct ping_pong_state current_vfe_irq;
struct ping_pong_state other_vfe;
};
struct dump_ping_pong_state {
struct dual_vfe_state arr[MAX_ISP_PING_PONG_DUMP_SIZE];
uint32_t first;
uint32_t fill_count;
struct vfe_device *vfe_dev;
};
void msm_isp_dump_ping_pong_mismatch(void);
void msm_isp_get_status(struct vfe_device *vfe_dev,
uint32_t *irq_status0, uint32_t *irq_status1);
void msm_isp_dump_taskelet_debug(void);
uint32_t msm_isp_get_framedrop_period(
enum msm_vfe_frame_skip_pattern frame_skip_pattern);
void msm_isp_reset_burst_count_and_frame_drop(
struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info);
int msm_isp_init_bandwidth_mgr(struct vfe_device *vfe_dev,
enum msm_isp_hw_client client);
int msm_isp_update_bandwidth(enum msm_isp_hw_client client,
uint64_t ab, uint64_t ib);
void msm_isp_util_get_bandwidth_stats(struct vfe_device *vfe_dev,
struct msm_isp_statistics *stats);
void msm_isp_util_update_last_overflow_ab_ib(struct vfe_device *vfe_dev);
void msm_isp_util_update_clk_rate(long clock_rate);
void msm_isp_update_req_history(uint32_t client, uint64_t ab,
uint64_t ib,
struct msm_isp_bandwidth_info *client_info,
unsigned long long ts);
void msm_isp_deinit_bandwidth_mgr(enum msm_isp_hw_client client);
int msm_isp_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
struct v4l2_event_subscription *sub);
int msm_isp_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
struct v4l2_event_subscription *sub);
int msm_isp_proc_cmd(struct vfe_device *vfe_dev, void *arg);
int msm_isp_send_event(struct vfe_device *vfe_dev,
uint32_t type, struct msm_isp_event_data *event_data);
int msm_isp_cal_word_per_line(uint32_t output_format,
uint32_t pixel_per_line);
int msm_isp_get_bit_per_pixel(uint32_t output_format);
enum msm_isp_pack_fmt msm_isp_get_pack_format(uint32_t output_format);
irqreturn_t msm_isp_process_irq(int irq_num, void *data);
int msm_isp_set_src_state(struct vfe_device *vfe_dev, void *arg);
void msm_isp_do_tasklet(unsigned long data);
void msm_isp_update_error_frame_count(struct vfe_device *vfe_dev);
void msm_isp_process_error_info(struct vfe_device *vfe_dev);
int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh);
int msm_isp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh);
long msm_isp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg);
void msm_isp_fetch_engine_done_notify(struct vfe_device *vfe_dev,
struct msm_vfe_fetch_engine_info *fetch_engine_info);
void msm_isp_print_fourcc_error(const char *origin, uint32_t fourcc_format);
void msm_isp_flush_tasklet(struct vfe_device *vfe_dev);
void msm_isp_save_framedrop_values(struct vfe_device *vfe_dev,
enum msm_vfe_input_src frame_src);
void msm_isp_get_timestamp(struct msm_isp_timestamp *time_stamp,
struct vfe_device *vfe_dev);
void msm_isp_process_overflow_irq(
struct vfe_device *vfe_dev,
uint32_t *irq_status0, uint32_t *irq_status1,
uint32_t force_overflow);
#endif /* __MSM_ISP_UTIL_H__ */

View file

@ -0,0 +1,4 @@
ccflags-y += -Idrivers/media/platform/msm/ais
ccflags-y += -Idrivers/media/platform/msm/ais/common
ccflags-y += -Idrivers/media/platform/msm/ais/sensor/io
obj-$(CONFIG_MSM_AIS) += msm_ispif.o

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,82 @@
/* Copyright (c) 2013-2017, 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/ais/msm_ais_ispif.h>
#include "msm_sd.h"
/* Maximum number of voltage supply for ispif and vfe */
#define ISPIF_VDD_INFO_MAX 2
#define ISPIF_VFE_VDD_INFO_MAX 2
#define ISPIF_CLK_INFO_MAX 27
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 *irq;
void __iomem *base;
void __iomem *clk_mux_base;
struct mutex mutex;
uint8_t start_ack_pending;
uint32_t csid_version;
int enb_dump_reg;
uint32_t open_cnt;
struct ispif_sof_count sof_count[VFE_MAX];
struct ispif_intf_cmd applied_intf_cmd[VFE_MAX];
uint8_t vc_enable[VFE_MAX][INTF_MAX][VC_MAX];
enum msm_ispif_state_t ispif_state;
struct msm_ispif_vfe_info vfe_info;
struct clk **ahb_clk;
struct msm_cam_clk_info *ahb_clk_info;
struct clk **clks;
struct msm_cam_clk_info *clk_info;
struct completion reset_complete[VFE_MAX];
atomic_t reset_trig[VFE_MAX];
uint32_t hw_num_isps;
uint32_t num_ahb_clk;
uint32_t num_clk;
uint32_t clk_idx;
uint32_t ispif_sof_debug;
uint32_t ispif_rdi0_debug;
uint32_t ispif_rdi1_debug;
uint32_t ispif_rdi2_debug;
struct regulator *ispif_vdd[ISPIF_VDD_INFO_MAX];
int ispif_vdd_count;
struct regulator *vfe_vdd[ISPIF_VFE_VDD_INFO_MAX];
int vfe_vdd_count;
};
#endif

View file

@ -0,0 +1,124 @@
/* Copyright (c) 2013-2017, 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_V1_H__
#define __MSM_ISPIF_HWREG_V1_H__
/* common registers */
#define ISPIF_RST_CMD_ADDR 0x0000
#define ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR 0x0124
#define PIX0_LINE_BUF_EN_BIT 0
#define ISPIF_VFE(m) (0x0)
#define ISPIF_VFE_m_CTRL_0(m) (0x0008 + ISPIF_VFE(m))
#define ISPIF_VFE_m_IRQ_MASK_0(m) (0x0100 + ISPIF_VFE(m))
#define ISPIF_VFE_m_IRQ_MASK_1(m) (0x010C + ISPIF_VFE(m))
#define ISPIF_VFE_m_IRQ_MASK_2(m) (0x0118 + ISPIF_VFE(m))
#define ISPIF_VFE_m_IRQ_STATUS_0(m) (0x0108 + ISPIF_VFE(m))
#define ISPIF_VFE_m_IRQ_STATUS_1(m) (0x0114 + ISPIF_VFE(m))
#define ISPIF_VFE_m_IRQ_STATUS_2(m) (0x0120 + ISPIF_VFE(m))
#define ISPIF_VFE_m_IRQ_CLEAR_0(m) (0x0104 + ISPIF_VFE(m))
#define ISPIF_VFE_m_IRQ_CLEAR_1(m) (0x0110 + ISPIF_VFE(m))
#define ISPIF_VFE_m_IRQ_CLEAR_2(m) (0x011C + ISPIF_VFE(m))
#define ISPIF_VFE_m_INPUT_SEL(m) (0x000C + ISPIF_VFE(m))
#define ISPIF_VFE_m_INTF_CMD_0(m) (0x0004 + ISPIF_VFE(m))
#define ISPIF_VFE_m_INTF_CMD_1(m) (0x0030 + ISPIF_VFE(m))
#define ISPIF_VFE_m_PIX_INTF_n_CID_MASK(m, n) (0x0010 + ISPIF_VFE(m) + 4*(n))
#define ISPIF_VFE_m_RDI_INTF_n_CID_MASK(m, n) (0x0014 + ISPIF_VFE(m) + \
((n > 0) ? (0x20) : 0) \
+ 8*(n))
#define ISPIF_VFE_m_PIX_OUTPUT_n_MISR(m, n) (0x0290 + ISPIF_VFE(m) + 4*(n))
#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_0(m, n) (0x001C + ISPIF_VFE(m) + \
((n > 0) ? (0x24) : 0) \
+ 0xc*(n))
#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_1(m, n) (0x0020 + ISPIF_VFE(m) + \
((n > 0) ? (0x24) : 0) \
+ 0xc*(n))
#define ISPIF_VFE_m_PIX_INTF_n_STATUS(m, n) (0x0024 + ISPIF_VFE(m) + 4*(n))
#define ISPIF_VFE_m_RDI_INTF_n_STATUS(m, n) (0x0028 + ISPIF_VFE(m) + \
((n > 0) ? (0x34) : 0) \
+ 8*(n))
/* Defines for compatibility with newer ISPIF versions */
#define ISPIF_RST_CMD_1_ADDR (0x0000)
#define ISPIF_VFE_m_PIX_INTF_n_CROP(m, n) (0x0000 + ISPIF_VFE(m) + 4*(n))
#define ISPIF_VFE_m_3D_THRESHOLD(m) (0x0000 + ISPIF_VFE(m))
#define ISPIF_VFE_m_OUTPUT_SEL(m) (0x0000 + ISPIF_VFE(m))
#define ISPIF_VFE_m_3D_DESKEW_SIZE(m) (0x0000 + ISPIF_VFE(m))
/* CSID CLK MUX SEL REGISTERS */
#define ISPIF_RDI_CLK_MUX_SEL_ADDR 0x8
/* ISPIF RESET BITS */
#define VFE_CLK_DOMAIN_RST BIT(31)
#define RDI_CLK_DOMAIN_RST BIT(30)
#define PIX_CLK_DOMAIN_RST BIT(29)
#define AHB_CLK_DOMAIN_RST BIT(28)
#define RDI_1_CLK_DOMAIN_RST BIT(27)
#define PIX_1_CLK_DOMAIN_RST BIT(26)
#define RDI_2_CLK_DOMAIN_RST BIT(25)
#define RDI_2_MISR_RST_STB BIT(20)
#define RDI_2_VFE_RST_STB BIT(19)
#define RDI_2_CSID_RST_STB BIT(18)
#define RDI_1_MISR_RST_STB BIT(14)
#define RDI_1_VFE_RST_STB BIT(13)
#define RDI_1_CSID_RST_STB BIT(12)
#define PIX_1_VFE_RST_STB BIT(10)
#define PIX_1_CSID_RST_STB BIT(9)
#define RDI_0_MISR_RST_STB BIT(8)
#define RDI_0_VFE_RST_STB BIT(7)
#define RDI_0_CSID_RST_STB BIT(6)
#define PIX_0_MISR_RST_STB BIT(5)
#define PIX_0_VFE_RST_STB BIT(4)
#define PIX_0_CSID_RST_STB BIT(3)
#define SW_REG_RST_STB BIT(2)
#define MISC_LOGIC_RST_STB BIT(1)
#define STROBED_RST_EN BIT(0)
#define ISPIF_RST_CMD_MASK 0xFE1C77FF
#define ISPIF_RST_CMD_1_MASK 0xFFFFFFFF /* undefined */
#define ISPIF_RST_CMD_MASK_RESTART 0x00001FF9
#define ISPIF_RST_CMD_1_MASK_RESTART 0x00001FF9 /* undefined */
/* irq_mask_0 */
#define PIX_INTF_0_OVERFLOW_IRQ BIT(12)
#define RAW_INTF_0_OVERFLOW_IRQ BIT(25)
#define RESET_DONE_IRQ BIT(27)
/* irq_mask_1 */
#define PIX_INTF_1_OVERFLOW_IRQ BIT(12)
#define RAW_INTF_1_OVERFLOW_IRQ BIT(25)
/* irq_mask_2 */
#define RAW_INTF_2_OVERFLOW_IRQ BIT(12)
#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 0x000249
#define ISPIF_IRQ_STATUS_RDI0_SOF_MASK 0x492000
#define ISPIF_IRQ_STATUS_RDI1_SOF_MASK 0x492000
#define ISPIF_IRQ_STATUS_RDI2_SOF_MASK 0x000249
#define ISPIF_IRQ_GLOBAL_CLEAR_CMD 0x000001
#define ISPIF_STOP_INTF_IMMEDIATELY 0xAAAAAAAA
/* ISPIF RDI pack mode not supported */
static inline void msm_ispif_cfg_pack_mode(struct ispif_device *ispif,
uint8_t intftype, uint8_t vfe_intf, uint32_t *pack_cfg_mask)
{
}
#endif /* __MSM_ISPIF_HWREG_V1_H__ */

View file

@ -0,0 +1,104 @@
/* Copyright (c) 2013-2017, 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_V2_H__
#define __MSM_ISPIF_HWREG_V2_H__
/* common registers */
#define ISPIF_RST_CMD_ADDR 0x008
#define ISPIF_RST_CMD_1_ADDR 0x00C
#define ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR 0x01C
#define PIX0_LINE_BUF_EN_BIT 6
#define ISPIF_VFE(m) ((m) * 0x200)
#define ISPIF_VFE_m_CTRL_0(m) (0x200 + ISPIF_VFE(m))
#define ISPIF_VFE_m_IRQ_MASK_0(m) (0x208 + ISPIF_VFE(m))
#define ISPIF_VFE_m_IRQ_MASK_1(m) (0x20C + ISPIF_VFE(m))
#define ISPIF_VFE_m_IRQ_MASK_2(m) (0x210 + ISPIF_VFE(m))
#define ISPIF_VFE_m_IRQ_STATUS_0(m) (0x21C + ISPIF_VFE(m))
#define ISPIF_VFE_m_IRQ_STATUS_1(m) (0x220 + ISPIF_VFE(m))
#define ISPIF_VFE_m_IRQ_STATUS_2(m) (0x224 + ISPIF_VFE(m))
#define ISPIF_VFE_m_IRQ_CLEAR_0(m) (0x230 + ISPIF_VFE(m))
#define ISPIF_VFE_m_IRQ_CLEAR_1(m) (0x234 + ISPIF_VFE(m))
#define ISPIF_VFE_m_IRQ_CLEAR_2(m) (0x238 + ISPIF_VFE(m))
#define ISPIF_VFE_m_INPUT_SEL(m) (0x244 + ISPIF_VFE(m))
#define ISPIF_VFE_m_INTF_CMD_0(m) (0x248 + ISPIF_VFE(m))
#define ISPIF_VFE_m_INTF_CMD_1(m) (0x24C + ISPIF_VFE(m))
#define ISPIF_VFE_m_PIX_INTF_n_CID_MASK(m, n) (0x254 + ISPIF_VFE(m) + 4*(n))
#define ISPIF_VFE_m_RDI_INTF_n_CID_MASK(m, n) (0x264 + ISPIF_VFE(m) + 4*(n))
#define ISPIF_VFE_m_PIX_INTF_n_CROP(m, n) (0x278 + ISPIF_VFE(m) + 4*(n))
#define ISPIF_VFE_m_3D_THRESHOLD(m) (0x288 + ISPIF_VFE(m))
#define ISPIF_VFE_m_OUTPUT_SEL(m) (0x28C + ISPIF_VFE(m))
#define ISPIF_VFE_m_PIX_OUTPUT_n_MISR(m, n) (0x290 + ISPIF_VFE(m) + 4*(n))
#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_0(m, n) (0x298 + ISPIF_VFE(m) + 8*(n))
#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_1(m, n) (0x29C + ISPIF_VFE(m) + 8*(n))
#define ISPIF_VFE_m_PIX_INTF_n_STATUS(m, n) (0x2C0 + ISPIF_VFE(m) + 4*(n))
#define ISPIF_VFE_m_RDI_INTF_n_STATUS(m, n) (0x2D0 + ISPIF_VFE(m) + 4*(n))
#define ISPIF_VFE_m_3D_DESKEW_SIZE(m) (0x2E4 + ISPIF_VFE(m))
/* CSID CLK MUX SEL REGISTERS */
#define ISPIF_RDI_CLK_MUX_SEL_ADDR 0x8
/* ISPIF RESET BITS */
#define VFE_CLK_DOMAIN_RST BIT(31)
#define PIX_1_CLK_DOMAIN_RST BIT(30)
#define PIX_CLK_DOMAIN_RST BIT(29)
#define RDI_2_CLK_DOMAIN_RST BIT(28)
#define RDI_1_CLK_DOMAIN_RST BIT(27)
#define RDI_CLK_DOMAIN_RST BIT(26)
#define AHB_CLK_DOMAIN_RST BIT(25)
#define RDI_2_VFE_RST_STB BIT(12)
#define RDI_2_CSID_RST_STB BIT(11)
#define RDI_1_VFE_RST_STB BIT(10)
#define RDI_1_CSID_RST_STB BIT(9)
#define RDI_0_VFE_RST_STB BIT(8)
#define RDI_0_CSID_RST_STB BIT(7)
#define PIX_1_VFE_RST_STB BIT(6)
#define PIX_1_CSID_RST_STB BIT(5)
#define PIX_0_VFE_RST_STB BIT(4)
#define PIX_0_CSID_RST_STB BIT(3)
#define SW_REG_RST_STB BIT(2)
#define MISC_LOGIC_RST_STB BIT(1)
#define STROBED_RST_EN BIT(0)
#define ISPIF_RST_CMD_MASK 0xFE0F1FFF
#define ISPIF_RST_CMD_1_MASK 0xFC0F1FF9
#define ISPIF_RST_CMD_MASK_RESTART 0x00001FF9
#define ISPIF_RST_CMD_1_MASK_RESTART 0x00001FF9
#define PIX_INTF_0_OVERFLOW_IRQ BIT(12)
#define RAW_INTF_0_OVERFLOW_IRQ BIT(25)
#define RAW_INTF_1_OVERFLOW_IRQ BIT(25)
#define RAW_INTF_2_OVERFLOW_IRQ BIT(12)
#define RESET_DONE_IRQ BIT(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_GLOBAL_CLEAR_CMD 0x1
#define ISPIF_STOP_INTF_IMMEDIATELY 0xAAAAAAAA
/* ISPIF RDI pack mode not supported */
static inline void msm_ispif_cfg_pack_mode(struct ispif_device *ispif,
uint8_t intftype, uint8_t vfe_intf, uint32_t *pack_cfg_mask)
{
}
#endif /* __MSM_ISPIF_HWREG_V2_H__ */

View file

@ -0,0 +1,135 @@
/* Copyright (c) 2013-2017, 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_V3_H__
#define __MSM_ISPIF_HWREG_V3_H__
/* common registers */
#define ISPIF_RST_CMD_ADDR 0x008
#define ISPIF_RST_CMD_1_ADDR 0x00C
#define ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR 0x01C
#define PIX0_LINE_BUF_EN_BIT 6
#define ISPIF_VFE(m) ((m) * 0x200)
#define ISPIF_VFE_m_CTRL_0(m) (0x200 + ISPIF_VFE(m))
#define ISPIF_VFE_m_CTRL_1(m) (0x204 + ISPIF_VFE(m))
#define ISPIF_VFE_m_IRQ_MASK_0(m) (0x208 + ISPIF_VFE(m))
#define ISPIF_VFE_m_IRQ_MASK_1(m) (0x20C + ISPIF_VFE(m))
#define ISPIF_VFE_m_IRQ_MASK_2(m) (0x210 + ISPIF_VFE(m))
#define ISPIF_VFE_m_IRQ_STATUS_0(m) (0x21C + ISPIF_VFE(m))
#define ISPIF_VFE_m_IRQ_STATUS_1(m) (0x220 + ISPIF_VFE(m))
#define ISPIF_VFE_m_IRQ_STATUS_2(m) (0x224 + ISPIF_VFE(m))
#define ISPIF_VFE_m_IRQ_CLEAR_0(m) (0x230 + ISPIF_VFE(m))
#define ISPIF_VFE_m_IRQ_CLEAR_1(m) (0x234 + ISPIF_VFE(m))
#define ISPIF_VFE_m_IRQ_CLEAR_2(m) (0x238 + ISPIF_VFE(m))
#define ISPIF_VFE_m_INPUT_SEL(m) (0x244 + ISPIF_VFE(m))
#define ISPIF_VFE_m_INTF_CMD_0(m) (0x248 + ISPIF_VFE(m))
#define ISPIF_VFE_m_INTF_CMD_1(m) (0x24C + ISPIF_VFE(m))
#define ISPIF_VFE_m_PIX_INTF_n_CID_MASK(m, n) (0x254 + ISPIF_VFE(m) + 4*(n))
#define ISPIF_VFE_m_RDI_INTF_n_CID_MASK(m, n) (0x264 + ISPIF_VFE(m) + 4*(n))
#define ISPIF_VFE_m_RDI_INTF_n_PACK_0(m, n) (0x270 + ISPIF_VFE(m) + 4*(n))
#define ISPIF_VFE_m_RDI_INTF_n_PACK_1(m, n) (0x27C + ISPIF_VFE(m) + 4*(n))
#define ISPIF_VFE_m_PIX_INTF_n_CROP(m, n) (0x288 + ISPIF_VFE(m) + 4*(n))
#define ISPIF_VFE_m_3D_THRESHOLD(m) (0x290 + ISPIF_VFE(m))
#define ISPIF_VFE_m_OUTPUT_SEL(m) (0x294 + ISPIF_VFE(m))
#define ISPIF_VFE_m_PIX_OUTPUT_n_MISR(m, n) (0x298 + ISPIF_VFE(m) + 4*(n))
#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_0(m, n) (0x29C + ISPIF_VFE(m) + 8*(n))
#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_1(m, n) (0x2A0 + ISPIF_VFE(m) + 8*(n))
#define ISPIF_VFE_m_PIX_INTF_n_STATUS(m, n) (0x2C0 + ISPIF_VFE(m) + 4*(n))
#define ISPIF_VFE_m_RDI_INTF_n_STATUS(m, n) (0x2D0 + ISPIF_VFE(m) + 4*(n))
#define ISPIF_VFE_m_3D_DESKEW_SIZE(m) (0x2E4 + ISPIF_VFE(m))
/* CSID CLK MUX SEL REGISTERS */
#define ISPIF_RDI_CLK_MUX_SEL_ADDR 0x8
/* ISPIF RESET BITS */
#define VFE_CLK_DOMAIN_RST BIT(31)
#define PIX_1_CLK_DOMAIN_RST BIT(30)
#define PIX_CLK_DOMAIN_RST BIT(29)
#define RDI_2_CLK_DOMAIN_RST BIT(28)
#define RDI_1_CLK_DOMAIN_RST BIT(27)
#define RDI_CLK_DOMAIN_RST BIT(26)
#define AHB_CLK_DOMAIN_RST BIT(25)
#define RDI_2_VFE_RST_STB BIT(12)
#define RDI_2_CSID_RST_STB BIT(11)
#define RDI_1_VFE_RST_STB BIT(10)
#define RDI_1_CSID_RST_STB BIT(9)
#define RDI_0_VFE_RST_STB BIT(8)
#define RDI_0_CSID_RST_STB BIT(7)
#define PIX_1_VFE_RST_STB BIT(6)
#define PIX_1_CSID_RST_STB BIT(5)
#define PIX_0_VFE_RST_STB BIT(4)
#define PIX_0_CSID_RST_STB BIT(3)
#define SW_REG_RST_STB BIT(2)
#define MISC_LOGIC_RST_STB BIT(1)
#define STROBED_RST_EN BIT(0)
#define ISPIF_RST_CMD_MASK 0xFE7F1FFF
#define ISPIF_RST_CMD_1_MASK 0xFC7F1FF9
#define ISPIF_RST_CMD_MASK_RESTART 0x7F1FF9
#define ISPIF_RST_CMD_1_MASK_RESTART 0x7F1FF9
#define PIX_INTF_0_OVERFLOW_IRQ BIT(12)
#define RAW_INTF_0_OVERFLOW_IRQ BIT(25)
#define RAW_INTF_1_OVERFLOW_IRQ BIT(25)
#define RAW_INTF_2_OVERFLOW_IRQ BIT(12)
#define RESET_DONE_IRQ BIT(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_GLOBAL_CLEAR_CMD 0x1
#define ISPIF_STOP_INTF_IMMEDIATELY 0xAAAAAAAA
/* ISPIF RDI pack mode support */
static inline void msm_ispif_cfg_pack_mode(struct ispif_device *ispif,
uint8_t intftype, uint8_t vfe_intf, uint32_t *pack_cfg_mask)
{
uint32_t pack_addr[2];
WARN_ON(!ispif);
switch (intftype) {
case RDI0:
pack_addr[0] = ISPIF_VFE_m_RDI_INTF_n_PACK_0(vfe_intf, 0);
pack_addr[1] = ISPIF_VFE_m_RDI_INTF_n_PACK_1(vfe_intf, 0);
break;
case RDI1:
pack_addr[0] = ISPIF_VFE_m_RDI_INTF_n_PACK_0(vfe_intf, 1);
pack_addr[1] = ISPIF_VFE_m_RDI_INTF_n_PACK_1(vfe_intf, 1);
break;
case RDI2:
pack_addr[0] = ISPIF_VFE_m_RDI_INTF_n_PACK_0(vfe_intf, 2);
pack_addr[1] = ISPIF_VFE_m_RDI_INTF_n_PACK_1(vfe_intf, 2);
break;
default:
pr_debug("%s: pack_mode not supported on intftype=%d\n",
__func__, intftype);
return;
}
pr_debug("%s: intftype %d pack_mask %x: 0x%x, %x:0x%x\n",
__func__, intftype, pack_addr[0],
pack_cfg_mask[0], pack_addr[1],
pack_cfg_mask[1]);
msm_camera_io_w_mb(pack_cfg_mask[0], ispif->base + pack_addr[0]);
msm_camera_io_w_mb(pack_cfg_mask[1], ispif->base + pack_addr[1]);
}
#endif /* __MSM_ISPIF_HWREG_V3_H__ */

View file

@ -0,0 +1,7 @@
GCC_VERSION := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc)
ccflags-y += -Idrivers/media/platform/msm/ais/jpeg_10
ccflags-y += -Idrivers/media/platform/msm/ais/sensor/io
ccflags-y += -Idrivers/media/platform/msm/ais/common
obj-$(CONFIG_MSM_AIS_JPEG) += msm_jpeg_dev.o msm_jpeg_sync.o msm_jpeg_core.o msm_jpeg_hw.o msm_jpeg_platform.o

View file

@ -0,0 +1,38 @@
/* Copyright (c) 2012-2017, 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_JPEG_COMMON_H
#define MSM_JPEG_COMMON_H
#define JPEG_DBG(fmt, args...) pr_debug(fmt, ##args)
#define JPEG_PR_ERR pr_err
#define JPEG_DBG_HIGH pr_debug
#define JPEG_BUS_VOTED(pgmn_dev) (pgmn_dev->jpeg_bus_vote = 1)
#define JPEG_BUS_UNVOTED(pgmn_dev) (pgmn_dev->jpeg_bus_vote = 0)
enum JPEG_MODE {
JPEG_MODE_DISABLE,
JPEG_MODE_OFFLINE,
JPEG_MODE_REALTIME,
JPEG_MODE_REALTIME_ROTATION
};
enum JPEG_ROTATION {
JPEG_ROTATION_0,
JPEG_ROTATION_90,
JPEG_ROTATION_180,
JPEG_ROTATION_270
};
#endif /* MSM_JPEG_COMMON_H */

View file

@ -0,0 +1,384 @@
/* Copyright (c) 2012-2017, 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 <linux/sched.h>
#include "msm_jpeg_hw.h"
#include "msm_jpeg_core.h"
#include "msm_jpeg_platform.h"
#include "msm_jpeg_common.h"
int msm_jpeg_core_reset(struct msm_jpeg_device *pgmn_dev, uint8_t op_mode,
void *base, int size) {
unsigned long flags;
int rc = 0;
int tm = 500; /*500ms*/
JPEG_DBG("%s:%d] reset", __func__, __LINE__);
memset(&pgmn_dev->fe_pingpong_buf, 0,
sizeof(pgmn_dev->fe_pingpong_buf));
pgmn_dev->fe_pingpong_buf.is_fe = 1;
memset(&pgmn_dev->we_pingpong_buf, 0,
sizeof(pgmn_dev->we_pingpong_buf));
spin_lock_irqsave(&pgmn_dev->reset_lock, flags);
pgmn_dev->reset_done_ack = 0;
if (pgmn_dev->core_type == MSM_JPEG_CORE_CODEC)
msm_jpeg_hw_reset(base, size);
else
msm_jpeg_hw_reset_dma(base, size);
spin_unlock_irqrestore(&pgmn_dev->reset_lock, flags);
rc = wait_event_timeout(
pgmn_dev->reset_wait,
pgmn_dev->reset_done_ack,
msecs_to_jiffies(tm));
if (!pgmn_dev->reset_done_ack) {
JPEG_DBG("%s: reset ACK failed %d", __func__, rc);
return -EBUSY;
}
JPEG_DBG("%s: reset_done_ack rc %d", __func__, rc);
spin_lock_irqsave(&pgmn_dev->reset_lock, flags);
pgmn_dev->reset_done_ack = 0;
pgmn_dev->state = MSM_JPEG_RESET;
spin_unlock_irqrestore(&pgmn_dev->reset_lock, flags);
return 0;
}
void msm_jpeg_core_release(struct msm_jpeg_device *pgmn_dev)
{
int i = 0;
for (i = 0; i < 2; i++) {
if (pgmn_dev->we_pingpong_buf.buf_status[i] &&
pgmn_dev->release_buf)
msm_jpeg_platform_p2v(pgmn_dev->iommu_hdl,
pgmn_dev->we_pingpong_buf.buf[i].ion_fd);
pgmn_dev->we_pingpong_buf.buf_status[i] = 0;
}
}
void msm_jpeg_core_init(struct msm_jpeg_device *pgmn_dev)
{
init_waitqueue_head(&pgmn_dev->reset_wait);
spin_lock_init(&pgmn_dev->reset_lock);
}
int msm_jpeg_core_fe_start(struct msm_jpeg_device *pgmn_dev)
{
msm_jpeg_hw_fe_start(pgmn_dev->base);
return 0;
}
/* fetch engine */
int msm_jpeg_core_fe_buf_update(struct msm_jpeg_device *pgmn_dev,
struct msm_jpeg_core_buf *buf)
{
int rc = 0;
if (buf->cbcr_len == 0)
buf->cbcr_buffer_addr = 0x0;
JPEG_DBG("%s:%d] 0x%08x %d 0x%08x %d\n", __func__, __LINE__,
(int) buf->y_buffer_addr, buf->y_len,
(int) buf->cbcr_buffer_addr, buf->cbcr_len);
if (pgmn_dev->core_type == MSM_JPEG_CORE_CODEC) {
rc = msm_jpeg_hw_pingpong_update(&pgmn_dev->fe_pingpong_buf,
buf, pgmn_dev->base);
if (rc < 0)
return rc;
msm_jpeg_hw_fe_mmu_prefetch(buf, pgmn_dev->base,
pgmn_dev->decode_flag);
} else {
rc = msm_jpegdma_hw_pingpong_update(
&pgmn_dev->fe_pingpong_buf, buf, pgmn_dev->base);
if (rc < 0)
return rc;
msm_jpegdma_hw_fe_mmu_prefetch(buf, pgmn_dev->base);
}
return rc;
}
void *msm_jpeg_core_fe_pingpong_irq(int jpeg_irq_status,
struct msm_jpeg_device *pgmn_dev)
{
return msm_jpeg_hw_pingpong_irq(&pgmn_dev->fe_pingpong_buf);
}
/* write engine */
int msm_jpeg_core_we_buf_update(struct msm_jpeg_device *pgmn_dev,
struct msm_jpeg_core_buf *buf) {
JPEG_DBG("%s:%d] 0x%08x 0x%08x %d\n", __func__, __LINE__,
(int) buf->y_buffer_addr, (int) buf->cbcr_buffer_addr,
buf->y_len);
pgmn_dev->we_pingpong_buf.buf[0] = *buf;
pgmn_dev->we_pingpong_buf.buf_status[0] = 1;
if (pgmn_dev->core_type == MSM_JPEG_CORE_CODEC) {
msm_jpeg_hw_we_buffer_update(
&pgmn_dev->we_pingpong_buf.buf[0], 0, pgmn_dev->base);
msm_jpeg_hw_we_mmu_prefetch(buf, pgmn_dev->base,
pgmn_dev->decode_flag);
} else {
msm_jpegdma_hw_we_buffer_update(
&pgmn_dev->we_pingpong_buf.buf[0], 0, pgmn_dev->base);
msm_jpegdma_hw_we_mmu_prefetch(buf, pgmn_dev->base);
}
return 0;
}
int msm_jpeg_core_we_buf_reset(struct msm_jpeg_device *pgmn_dev,
struct msm_jpeg_hw_buf *buf)
{
int i = 0;
for (i = 0; i < 2; i++) {
if (pgmn_dev->we_pingpong_buf.buf[i].y_buffer_addr
== buf->y_buffer_addr)
pgmn_dev->we_pingpong_buf.buf_status[i] = 0;
}
return 0;
}
void *msm_jpeg_core_we_pingpong_irq(int jpeg_irq_status,
struct msm_jpeg_device *pgmn_dev)
{
JPEG_DBG("%s:%d]\n", __func__, __LINE__);
return msm_jpeg_hw_pingpong_irq(&pgmn_dev->we_pingpong_buf);
}
void *msm_jpeg_core_framedone_irq(int jpeg_irq_status,
struct msm_jpeg_device *pgmn_dev)
{
struct msm_jpeg_hw_buf *buf_p;
JPEG_DBG("%s:%d]\n", __func__, __LINE__);
buf_p = msm_jpeg_hw_pingpong_active_buffer(
&pgmn_dev->we_pingpong_buf);
if (buf_p && !pgmn_dev->decode_flag) {
buf_p->framedone_len =
msm_jpeg_hw_encode_output_size(pgmn_dev->base);
JPEG_DBG("%s:%d] framedone_len %d\n", __func__, __LINE__,
buf_p->framedone_len);
}
return buf_p;
}
void *msm_jpeg_core_reset_ack_irq(int jpeg_irq_status,
struct msm_jpeg_device *pgmn_dev)
{
/* @todo return the status back to msm_jpeg_core_reset */
JPEG_DBG("%s:%d]\n", __func__, __LINE__);
return NULL;
}
void *msm_jpeg_core_err_irq(int jpeg_irq_status,
struct msm_jpeg_device *pgmn_dev)
{
JPEG_PR_ERR("%s: Error %x\n", __func__, jpeg_irq_status);
return NULL;
}
static int (*msm_jpeg_irq_handler)(int, void *, void *);
void msm_jpeg_core_return_buffers(struct msm_jpeg_device *pgmn_dev,
int jpeg_irq_status)
{
void *data = NULL;
data = msm_jpeg_core_fe_pingpong_irq(jpeg_irq_status,
pgmn_dev);
if (msm_jpeg_irq_handler)
msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_FE,
pgmn_dev, data);
data = msm_jpeg_core_we_pingpong_irq(jpeg_irq_status,
pgmn_dev);
if (msm_jpeg_irq_handler)
msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_WE,
pgmn_dev, data);
}
irqreturn_t msm_jpeg_core_irq(int irq_num, void *context)
{
void *data = NULL;
unsigned long flags;
int jpeg_irq_status;
struct msm_jpeg_device *pgmn_dev = (struct msm_jpeg_device *)context;
JPEG_DBG("%s:%d] irq_num = %d\n", __func__, __LINE__, irq_num);
jpeg_irq_status = msm_jpeg_hw_irq_get_status(pgmn_dev->base);
JPEG_DBG("%s:%d] jpeg_irq_status = %0x\n", __func__, __LINE__,
jpeg_irq_status);
/* For reset and framedone IRQs, clear all bits */
if (pgmn_dev->state == MSM_JPEG_IDLE) {
JPEG_DBG_HIGH("%s %d ] Error IRQ received state %d",
__func__, __LINE__, pgmn_dev->state);
JPEG_DBG_HIGH("%s %d ] Ignoring the Error", __func__,
__LINE__);
msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK,
JPEG_IRQ_CLEAR_ALL, pgmn_dev->base);
return IRQ_HANDLED;
} else if (jpeg_irq_status & 0x10000000) {
msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK,
JPEG_IRQ_CLEAR_ALL, pgmn_dev->base);
} else if (jpeg_irq_status & 0x1) {
msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK,
JPEG_IRQ_CLEAR_ALL, pgmn_dev->base);
if (pgmn_dev->decode_flag)
msm_jpeg_decode_status(pgmn_dev->base);
} else {
msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK,
jpeg_irq_status, pgmn_dev->base);
}
if (msm_jpeg_hw_irq_is_frame_done(jpeg_irq_status)) {
/* send fe ping pong irq */
JPEG_DBG_HIGH("%s:%d] Session done\n", __func__, __LINE__);
data = msm_jpeg_core_fe_pingpong_irq(jpeg_irq_status,
pgmn_dev);
if (msm_jpeg_irq_handler)
msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_FE,
context, data);
data = msm_jpeg_core_framedone_irq(jpeg_irq_status,
pgmn_dev);
if (msm_jpeg_irq_handler)
msm_jpeg_irq_handler(
MSM_JPEG_HW_MASK_COMP_FRAMEDONE,
context, data);
pgmn_dev->state = MSM_JPEG_INIT;
}
if (msm_jpeg_hw_irq_is_reset_ack(jpeg_irq_status)) {
data = msm_jpeg_core_reset_ack_irq(jpeg_irq_status,
pgmn_dev);
spin_lock_irqsave(&pgmn_dev->reset_lock, flags);
pgmn_dev->reset_done_ack = 1;
spin_unlock_irqrestore(&pgmn_dev->reset_lock, flags);
wake_up(&pgmn_dev->reset_wait);
if (msm_jpeg_irq_handler)
msm_jpeg_irq_handler(
MSM_JPEG_HW_MASK_COMP_RESET_ACK,
context, data);
}
/* Unexpected/unintended HW interrupt */
if (msm_jpeg_hw_irq_is_err(jpeg_irq_status)) {
if (pgmn_dev->state != MSM_JPEG_EXECUTING) {
/* Clear all the bits and ignore the IRQ */
JPEG_DBG_HIGH("%s %d ] Error IRQ received state %d",
__func__, __LINE__, pgmn_dev->state);
JPEG_DBG_HIGH("%s %d ] Ignoring the Error", __func__,
__LINE__);
msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK,
JPEG_IRQ_CLEAR_ALL, pgmn_dev->base);
return IRQ_HANDLED;
}
if (pgmn_dev->decode_flag)
msm_jpeg_decode_status(pgmn_dev->base);
msm_jpeg_core_return_buffers(pgmn_dev, jpeg_irq_status);
data = msm_jpeg_core_err_irq(jpeg_irq_status, pgmn_dev);
if (msm_jpeg_irq_handler) {
msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_ERR,
context, data);
}
}
return IRQ_HANDLED;
}
irqreturn_t msm_jpegdma_core_irq(int irq_num, void *context)
{
void *data = NULL;
unsigned long flags;
int jpeg_irq_status;
struct msm_jpeg_device *pgmn_dev = context;
JPEG_DBG("%s:%d] irq_num = %d\n", __func__, __LINE__, irq_num);
jpeg_irq_status = msm_jpegdma_hw_irq_get_status(pgmn_dev->base);
JPEG_DBG("%s:%d] jpeg_irq_status = %0x\n", __func__, __LINE__,
jpeg_irq_status);
/* For reset and framedone IRQs, clear all bits */
if (pgmn_dev->state == MSM_JPEG_IDLE) {
JPEG_DBG_HIGH("%s %d ] Error IRQ received state %d",
__func__, __LINE__, pgmn_dev->state);
JPEG_DBG_HIGH("%s %d ] Ignoring the Error", __func__,
__LINE__);
msm_jpegdma_hw_irq_clear(JPEGDMA_IRQ_CLEAR_BMSK,
JPEGDMA_IRQ_CLEAR_ALL, pgmn_dev->base);
return IRQ_HANDLED;
} else if (jpeg_irq_status & 0x00000400) {
msm_jpegdma_hw_irq_clear(JPEGDMA_IRQ_CLEAR_BMSK,
JPEGDMA_IRQ_CLEAR_ALL, pgmn_dev->base);
} else if (jpeg_irq_status & 0x1) {
msm_jpegdma_hw_irq_clear(JPEGDMA_IRQ_CLEAR_BMSK,
JPEGDMA_IRQ_CLEAR_ALL, pgmn_dev->base);
} else {
msm_jpegdma_hw_irq_clear(JPEGDMA_IRQ_CLEAR_BMSK,
jpeg_irq_status, pgmn_dev->base);
}
if (msm_jpegdma_hw_irq_is_frame_done(jpeg_irq_status)) {
/* send fe ping pong irq */
JPEG_DBG_HIGH("%s:%d] Session done\n", __func__, __LINE__);
data = msm_jpeg_core_fe_pingpong_irq(jpeg_irq_status,
pgmn_dev);
if (msm_jpeg_irq_handler)
msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_FE,
context, data);
data = msm_jpeg_core_framedone_irq(jpeg_irq_status,
pgmn_dev);
if (msm_jpeg_irq_handler)
msm_jpeg_irq_handler(
MSM_JPEG_HW_MASK_COMP_FRAMEDONE,
context, data);
pgmn_dev->state = MSM_JPEG_INIT;
}
if (msm_jpegdma_hw_irq_is_reset_ack(jpeg_irq_status)) {
data = msm_jpeg_core_reset_ack_irq(jpeg_irq_status,
pgmn_dev);
spin_lock_irqsave(&pgmn_dev->reset_lock, flags);
pgmn_dev->reset_done_ack = 1;
spin_unlock_irqrestore(&pgmn_dev->reset_lock, flags);
wake_up(&pgmn_dev->reset_wait);
if (msm_jpeg_irq_handler)
msm_jpeg_irq_handler(
MSM_JPEG_HW_MASK_COMP_RESET_ACK,
context, data);
}
return IRQ_HANDLED;
}
void msm_jpeg_core_irq_install(int (*irq_handler) (int, void *, void *))
{
msm_jpeg_irq_handler = irq_handler;
}
void msm_jpeg_core_irq_remove(void)
{
msm_jpeg_irq_handler = NULL;
}

View file

@ -0,0 +1,40 @@
/* Copyright (c) 2012-2017, 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_JPEG_CORE_H
#define MSM_JPEG_CORE_H
#include <linux/interrupt.h>
#include "msm_jpeg_hw.h"
#include "msm_jpeg_sync.h"
#define msm_jpeg_core_buf msm_jpeg_hw_buf
irqreturn_t msm_jpeg_core_irq(int irq_num, void *context);
irqreturn_t msm_jpegdma_core_irq(int irq_num, void *context);
void msm_jpeg_core_irq_install(int (*irq_handler) (int, void *, void *));
void msm_jpeg_core_irq_remove(void);
int msm_jpeg_core_fe_buf_update(struct msm_jpeg_device *pgmn_dev,
struct msm_jpeg_core_buf *buf);
int msm_jpeg_core_we_buf_update(struct msm_jpeg_device *pgmn_dev,
struct msm_jpeg_core_buf *buf);
int msm_jpeg_core_we_buf_reset(struct msm_jpeg_device *pgmn_dev,
struct msm_jpeg_hw_buf *buf);
int msm_jpeg_core_reset(struct msm_jpeg_device *pgmn_dev, uint8_t op_mode,
void *base, int size);
int msm_jpeg_core_fe_start(struct msm_jpeg_device *);
void msm_jpeg_core_release(struct msm_jpeg_device *);
void msm_jpeg_core_init(struct msm_jpeg_device *);
#endif /* MSM_JPEG_CORE_H */

View file

@ -0,0 +1,345 @@
/* Copyright (c) 2012-2017, 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/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <media/msm_jpeg.h>
#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
#include "msm_jpeg_sync.h"
#include "msm_jpeg_common.h"
#define MSM_JPEG_NAME "jpeg"
#define DEV_NAME_LEN 10
static int msm_jpeg_open(struct inode *inode, struct file *filp)
{
int rc = 0;
struct msm_jpeg_device *pgmn_dev = container_of(inode->i_cdev,
struct msm_jpeg_device, cdev);
filp->private_data = pgmn_dev;
JPEG_DBG("%s:%d]\n", __func__, __LINE__);
rc = __msm_jpeg_open(pgmn_dev);
JPEG_DBG(KERN_INFO "%s:%d] %s open_count = %d\n", __func__, __LINE__,
filp->f_path.dentry->d_name.name, pgmn_dev->open_count);
return rc;
}
static int msm_jpeg_release(struct inode *inode, struct file *filp)
{
int rc;
struct msm_jpeg_device *pgmn_dev = filp->private_data;
JPEG_DBG(KERN_INFO "%s:%d]\n", __func__, __LINE__);
rc = __msm_jpeg_release(pgmn_dev);
JPEG_DBG(KERN_INFO "%s:%d] %s open_count = %d\n", __func__, __LINE__,
filp->f_path.dentry->d_name.name, pgmn_dev->open_count);
return rc;
}
#ifdef CONFIG_COMPAT
static long msm_jpeg_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
int rc;
struct msm_jpeg_device *pgmn_dev = filp->private_data;
JPEG_DBG("%s:%d] cmd=%d pgmn_dev=0x%pK arg=0x%lx\n", __func__,
__LINE__, _IOC_NR(cmd), pgmn_dev,
(unsigned long)arg);
rc = __msm_jpeg_compat_ioctl(pgmn_dev, cmd, arg);
JPEG_DBG("%s:%d]\n", __func__, __LINE__);
return rc;
}
#endif
static long msm_jpeg_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
int rc;
struct msm_jpeg_device *pgmn_dev = filp->private_data;
JPEG_DBG("%s:%d] cmd=%d pgmn_dev=0x%pK arg=0x%lx\n", __func__,
__LINE__, _IOC_NR(cmd), pgmn_dev,
(unsigned long)arg);
rc = __msm_jpeg_ioctl(pgmn_dev, cmd, arg);
JPEG_DBG("%s:%d]\n", __func__, __LINE__);
return rc;
}
static const struct file_operations msm_jpeg_fops = {
.owner = THIS_MODULE,
.open = msm_jpeg_open,
.release = msm_jpeg_release,
.unlocked_ioctl = msm_jpeg_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = msm_jpeg_compat_ioctl,
#endif
};
int msm_jpeg_subdev_init(struct v4l2_subdev *jpeg_sd)
{
int rc;
struct msm_jpeg_device *pgmn_dev =
(struct msm_jpeg_device *)jpeg_sd->host_priv;
JPEG_DBG("%s:%d: jpeg_sd=0x%lx pgmn_dev=0x%pK\n",
__func__, __LINE__, (unsigned long)jpeg_sd,
pgmn_dev);
rc = __msm_jpeg_open(pgmn_dev);
JPEG_DBG("%s:%d: rc=%d\n",
__func__, __LINE__, rc);
return rc;
}
static long msm_jpeg_subdev_ioctl(struct v4l2_subdev *sd,
unsigned int cmd, void *arg)
{
long rc;
struct msm_jpeg_device *pgmn_dev =
(struct msm_jpeg_device *)sd->host_priv;
JPEG_DBG("%s: cmd=%d\n", __func__, cmd);
JPEG_DBG("%s: pgmn_dev 0x%pK", __func__, pgmn_dev);
JPEG_DBG("%s: Calling __msm_jpeg_ioctl\n", __func__);
rc = __msm_jpeg_ioctl(pgmn_dev, cmd, (unsigned long)arg);
pr_debug("%s: X\n", __func__);
return rc;
}
void msm_jpeg_subdev_release(struct v4l2_subdev *jpeg_sd)
{
int rc;
struct msm_jpeg_device *pgmn_dev =
(struct msm_jpeg_device *)jpeg_sd->host_priv;
JPEG_DBG("%s:pgmn_dev=0x%pK", __func__, pgmn_dev);
rc = __msm_jpeg_release(pgmn_dev);
JPEG_DBG("%s:rc=%d", __func__, rc);
}
static const struct v4l2_subdev_core_ops msm_jpeg_subdev_core_ops = {
.ioctl = msm_jpeg_subdev_ioctl,
};
static const struct v4l2_subdev_ops msm_jpeg_subdev_ops = {
.core = &msm_jpeg_subdev_core_ops,
};
struct msm_jpeg_priv_data {
enum msm_jpeg_core_type core_type;
};
static const struct msm_jpeg_priv_data msm_jpeg_priv_data_jpg = {
.core_type = MSM_JPEG_CORE_CODEC
};
static const struct msm_jpeg_priv_data msm_jpeg_priv_data_dma = {
.core_type = MSM_JPEG_CORE_DMA
};
static const struct of_device_id msm_jpeg_dt_match[] = {
{.compatible = "qcom,jpeg", .data = &msm_jpeg_priv_data_jpg},
{.compatible = "qcom,jpeg_dma", .data = &msm_jpeg_priv_data_dma},
{}
};
MODULE_DEVICE_TABLE(of, msm_jpeg_dt_match);
static int msm_jpeg_init_dev(struct platform_device *pdev)
{
int rc = -1;
struct device *dev;
struct msm_jpeg_device *msm_jpeg_device_p;
const struct of_device_id *device_id;
const struct msm_jpeg_priv_data *priv_data;
char devname[DEV_NAME_LEN];
msm_jpeg_device_p = kzalloc(sizeof(struct msm_jpeg_device), GFP_ATOMIC);
if (!msm_jpeg_device_p) {
JPEG_PR_ERR("%s: no mem\n", __func__);
return -EFAULT;
}
msm_jpeg_device_p->pdev = pdev;
device_id = of_match_device(msm_jpeg_dt_match, &pdev->dev);
if (!device_id) {
JPEG_PR_ERR("%s: device_id is NULL\n", __func__);
goto fail;
}
priv_data = device_id->data;
msm_jpeg_device_p->core_type = priv_data->core_type;
if (pdev->dev.of_node)
of_property_read_u32((&pdev->dev)->of_node, "cell-index",
&pdev->id);
snprintf(devname, sizeof(devname), "%s%d", MSM_JPEG_NAME, pdev->id);
rc = __msm_jpeg_init(msm_jpeg_device_p);
if (rc < -1) {
JPEG_PR_ERR("%s: initialization failed\n", __func__);
goto fail;
}
v4l2_subdev_init(&msm_jpeg_device_p->subdev, &msm_jpeg_subdev_ops);
v4l2_set_subdev_hostdata(&msm_jpeg_device_p->subdev, msm_jpeg_device_p);
JPEG_DBG("%s: msm_jpeg_device_p 0x%lx", __func__,
(unsigned long)msm_jpeg_device_p);
rc = alloc_chrdev_region(&msm_jpeg_device_p->msm_jpeg_devno, 0, 1,
devname);
if (rc < 0) {
JPEG_PR_ERR("%s: failed to allocate chrdev\n", __func__);
goto fail_1;
}
if (!msm_jpeg_device_p->msm_jpeg_class) {
msm_jpeg_device_p->msm_jpeg_class =
class_create(THIS_MODULE, devname);
if (IS_ERR(msm_jpeg_device_p->msm_jpeg_class)) {
rc = PTR_ERR(msm_jpeg_device_p->msm_jpeg_class);
JPEG_PR_ERR("%s: create device class failed\n",
__func__);
goto fail_2;
}
}
dev = device_create(msm_jpeg_device_p->msm_jpeg_class, NULL,
MKDEV(MAJOR(msm_jpeg_device_p->msm_jpeg_devno),
MINOR(msm_jpeg_device_p->msm_jpeg_devno)), NULL,
"%s%d", MSM_JPEG_NAME, pdev->id);
if (IS_ERR(dev)) {
JPEG_PR_ERR("%s: error creating device\n", __func__);
rc = -ENODEV;
goto fail_3;
}
cdev_init(&msm_jpeg_device_p->cdev, &msm_jpeg_fops);
msm_jpeg_device_p->cdev.owner = THIS_MODULE;
msm_jpeg_device_p->cdev.ops =
(const struct file_operations *) &msm_jpeg_fops;
rc = cdev_add(&msm_jpeg_device_p->cdev,
msm_jpeg_device_p->msm_jpeg_devno, 1);
if (rc < 0) {
JPEG_PR_ERR("%s: error adding cdev\n", __func__);
rc = -ENODEV;
goto fail_4;
}
platform_set_drvdata(pdev, &msm_jpeg_device_p);
JPEG_DBG("%s %s%d: success\n", __func__, MSM_JPEG_NAME, pdev->id);
return rc;
fail_4:
device_destroy(msm_jpeg_device_p->msm_jpeg_class,
msm_jpeg_device_p->msm_jpeg_devno);
fail_3:
class_destroy(msm_jpeg_device_p->msm_jpeg_class);
fail_2:
unregister_chrdev_region(msm_jpeg_device_p->msm_jpeg_devno, 1);
fail_1:
__msm_jpeg_exit(msm_jpeg_device_p);
return rc;
fail:
kfree(msm_jpeg_device_p);
return rc;
}
static void msm_jpeg_exit(struct msm_jpeg_device *msm_jpeg_device_p)
{
cdev_del(&msm_jpeg_device_p->cdev);
device_destroy(msm_jpeg_device_p->msm_jpeg_class,
msm_jpeg_device_p->msm_jpeg_devno);
class_destroy(msm_jpeg_device_p->msm_jpeg_class);
unregister_chrdev_region(msm_jpeg_device_p->msm_jpeg_devno, 1);
cam_smmu_destroy_handle(msm_jpeg_device_p->iommu_hdl);
__msm_jpeg_exit(msm_jpeg_device_p);
}
static int __msm_jpeg_probe(struct platform_device *pdev)
{
return msm_jpeg_init_dev(pdev);
}
static int __msm_jpeg_remove(struct platform_device *pdev)
{
struct msm_jpeg_device *msm_jpegd_device_p;
msm_jpegd_device_p = platform_get_drvdata(pdev);
if (msm_jpegd_device_p)
msm_jpeg_exit(msm_jpegd_device_p);
return 0;
}
static struct platform_driver msm_jpeg_driver = {
.probe = __msm_jpeg_probe,
.remove = __msm_jpeg_remove,
.driver = {
.name = "msm_jpeg",
.owner = THIS_MODULE,
.of_match_table = msm_jpeg_dt_match,
},
};
static int __init msm_jpeg_driver_init(void)
{
int rc;
rc = platform_driver_register(&msm_jpeg_driver);
return rc;
}
static void __exit msm_jpeg_driver_exit(void)
{
platform_driver_unregister(&msm_jpeg_driver);
}
MODULE_DESCRIPTION("msm jpeg jpeg driver");
MODULE_LICENSE("GPL v2");
module_init(msm_jpeg_driver_init);
module_exit(msm_jpeg_driver_exit);

View file

@ -0,0 +1,928 @@
/* Copyright (c) 2012-2017, 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 <linux/delay.h>
#include "msm_jpeg_hw.h"
#include "msm_jpeg_common.h"
#include "msm_camera_io_util.h"
#include <linux/io.h>
int msm_jpeg_hw_pingpong_update(struct msm_jpeg_hw_pingpong *pingpong_hw,
struct msm_jpeg_hw_buf *buf, void *base)
{
int buf_free_index = -1;
if (!pingpong_hw->buf_status[0]) {
buf_free_index = 0;
} else if (!pingpong_hw->buf_status[1]) {
buf_free_index = 1;
} else {
JPEG_PR_ERR("%s:%d: pingpong buffer busy\n",
__func__, __LINE__);
return -EBUSY;
}
pingpong_hw->buf[buf_free_index] = *buf;
pingpong_hw->buf_status[buf_free_index] = 1;
if (pingpong_hw->is_fe) {
/* it is fe */
msm_jpeg_hw_fe_buffer_update(
&pingpong_hw->buf[buf_free_index], buf_free_index,
base);
} else {
/* it is we */
msm_jpeg_hw_we_buffer_update(
&pingpong_hw->buf[buf_free_index], buf_free_index,
base);
}
return 0;
}
int msm_jpegdma_hw_pingpong_update(struct msm_jpeg_hw_pingpong *pingpong_hw,
struct msm_jpeg_hw_buf *buf, void *base)
{
int buf_free_index = -1;
if (!pingpong_hw->buf_status[0]) {
buf_free_index = 0;
} else if (!pingpong_hw->buf_status[1]) {
buf_free_index = 1;
} else {
JPEG_PR_ERR("%s:%d: pingpong buffer busy\n",
__func__, __LINE__);
return -EBUSY;
}
pingpong_hw->buf[buf_free_index] = *buf;
pingpong_hw->buf_status[buf_free_index] = 1;
if (pingpong_hw->is_fe) {
/* it is fe */
msm_jpegdma_hw_fe_buffer_update(
&pingpong_hw->buf[buf_free_index], buf_free_index,
base);
} else {
/* it is we */
msm_jpegdma_hw_we_buffer_update(
&pingpong_hw->buf[buf_free_index], buf_free_index,
base);
}
return 0;
}
void *msm_jpeg_hw_pingpong_irq(struct msm_jpeg_hw_pingpong *pingpong_hw)
{
struct msm_jpeg_hw_buf *buf_p = NULL;
if (pingpong_hw->buf_status[pingpong_hw->buf_active_index]) {
buf_p = &pingpong_hw->buf[pingpong_hw->buf_active_index];
pingpong_hw->buf_status[pingpong_hw->buf_active_index] = 0;
}
pingpong_hw->buf_active_index = !pingpong_hw->buf_active_index;
return (void *) buf_p;
}
void *msm_jpeg_hw_pingpong_active_buffer(
struct msm_jpeg_hw_pingpong *pingpong_hw)
{
struct msm_jpeg_hw_buf *buf_p = NULL;
if (pingpong_hw->buf_status[pingpong_hw->buf_active_index])
buf_p = &pingpong_hw->buf[pingpong_hw->buf_active_index];
return (void *) buf_p;
}
struct msm_jpeg_hw_cmd hw_cmd_irq_get_status[] = {
/* type, repeat n times, offset, mask, data or pdata */
{MSM_JPEG_HW_CMD_TYPE_READ, 1, JPEG_IRQ_STATUS_ADDR,
JPEG_IRQ_STATUS_BMSK, {0} },
};
int msm_jpeg_hw_irq_get_status(void *base)
{
uint32_t n_irq_status = 0;
n_irq_status = msm_jpeg_hw_read(&hw_cmd_irq_get_status[0], base);
return n_irq_status;
}
struct msm_jpeg_hw_cmd hw_cmd_irq_get_dmastatus[] = {
/* type, repeat n times, offset, mask, data or pdata */
{MSM_JPEG_HW_CMD_TYPE_READ, 1, JPEGDMA_IRQ_STATUS_ADDR,
JPEGDMA_IRQ_STATUS_BMSK, {0} },
};
int msm_jpegdma_hw_irq_get_status(void *base)
{
uint32_t n_irq_status = 0;
n_irq_status = msm_jpeg_hw_read(&hw_cmd_irq_get_dmastatus[0], base);
return n_irq_status;
}
struct msm_jpeg_hw_cmd hw_cmd_encode_output_size[] = {
/* type, repeat n times, offset, mask, data or pdata */
{MSM_JPEG_HW_CMD_TYPE_READ, 1,
JPEG_ENCODE_OUTPUT_SIZE_STATUS_ADDR,
JPEG_ENCODE_OUTPUT_SIZE_STATUS_BMSK, {0} },
};
long msm_jpeg_hw_encode_output_size(void *base)
{
uint32_t encode_output_size = 0;
encode_output_size = msm_jpeg_hw_read(&hw_cmd_encode_output_size[0],
base);
return encode_output_size;
}
void msm_jpeg_hw_irq_clear(uint32_t mask, uint32_t data, void *base)
{
struct msm_jpeg_hw_cmd cmd_irq_clear;
cmd_irq_clear.type = MSM_JPEG_HW_CMD_TYPE_WRITE;
cmd_irq_clear.n = 1;
cmd_irq_clear.offset = JPEG_IRQ_CLEAR_ADDR;
cmd_irq_clear.mask = mask;
cmd_irq_clear.data = data;
JPEG_DBG("%s:%d] mask %0x data %0x", __func__, __LINE__, mask, data);
msm_jpeg_hw_write(&cmd_irq_clear, base);
}
void msm_jpegdma_hw_irq_clear(uint32_t mask, uint32_t data, void *base)
{
struct msm_jpeg_hw_cmd cmd_irq_clear;
cmd_irq_clear.type = MSM_JPEG_HW_CMD_TYPE_WRITE;
cmd_irq_clear.n = 1;
cmd_irq_clear.offset = JPEGDMA_IRQ_CLEAR_ADDR;
cmd_irq_clear.mask = mask;
cmd_irq_clear.data = data;
JPEG_DBG("%s:%d] mask %0x data %0x", __func__, __LINE__, mask, data);
msm_jpeg_hw_write(&cmd_irq_clear, base);
}
struct msm_jpeg_hw_cmd hw_cmd_fe_ping_update[] = {
/* type, repeat n times, offset, mask, data or pdata */
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_MASK_ADDR,
JPEG_IRQ_MASK_BMSK, {JPEG_IRQ_ALLSOURCES_ENABLE} },
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_CMD_ADDR,
JPEG_CMD_BMSK, {JPEG_CMD_CLEAR_WRITE_PLN_QUEUES} },
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN0_RD_OFFSET_ADDR,
JPEG_PLN0_RD_OFFSET_BMSK, {0} },
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN0_RD_PNTR_ADDR,
JPEG_PLN0_RD_PNTR_BMSK, {0} },
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN1_RD_OFFSET_ADDR,
JPEG_PLN1_RD_OFFSET_BMSK, {0} },
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN1_RD_PNTR_ADDR,
JPEG_PLN1_RD_PNTR_BMSK, {0} },
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN2_RD_OFFSET_ADDR,
JPEG_PLN1_RD_OFFSET_BMSK, {0} },
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN2_RD_PNTR_ADDR,
JPEG_PLN2_RD_PNTR_BMSK, {0} },
};
void msm_jpeg_hw_fe_buffer_update(struct msm_jpeg_hw_buf *p_input,
uint8_t pingpong_index, void *base)
{
struct msm_jpeg_hw_cmd *hw_cmd_p;
struct msm_jpeg_hw_cmd tmp_hw_cmd;
if (pingpong_index == 0) {
hw_cmd_p = &hw_cmd_fe_ping_update[0];
/* ensure write is done */
wmb();
msm_jpeg_hw_write(hw_cmd_p++, base);
/* ensure write is done */
wmb();
msm_jpeg_hw_write(hw_cmd_p++, base);
/* ensure write is done */
wmb();
msm_jpeg_hw_write(hw_cmd_p++, base);
/* ensure write is done */
wmb();
tmp_hw_cmd = *hw_cmd_p++;
tmp_hw_cmd.data = p_input->y_buffer_addr;
msm_jpeg_hw_write(&tmp_hw_cmd, base);
/* ensure write is done */
wmb();
msm_jpeg_hw_write(hw_cmd_p++, base);
/* ensure write is done */
wmb();
tmp_hw_cmd = *hw_cmd_p++;
tmp_hw_cmd.data = p_input->cbcr_buffer_addr;
msm_jpeg_hw_write(&tmp_hw_cmd, base);
/* ensure write is done */
wmb();
msm_jpeg_hw_write(hw_cmd_p++, base);
/* ensure write is done */
wmb();
tmp_hw_cmd = *hw_cmd_p++;
tmp_hw_cmd.data = p_input->pln2_addr;
msm_jpeg_hw_write(&tmp_hw_cmd, base);
/* ensure write is done */
wmb();
}
}
struct msm_jpeg_hw_cmd hw_dma_cmd_fe_ping_update[] = {
/* type, repeat n times, offset, mask, data or pdata */
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEGDMA_IRQ_MASK_ADDR,
JPEGDMA_IRQ_MASK_BMSK, {JPEG_IRQ_ALLSOURCES_ENABLE} },
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEGDMA_CMD_ADDR,
JPEGDMA_CMD_BMSK, {JPEGDMA_CMD_CLEAR_READ_PLN_QUEUES} },
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEGDMA_FE_0_RD_PNTR,
JPEG_PLN0_RD_PNTR_BMSK, {0} },
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEGDMA_FE_1_RD_PNTR,
JPEG_PLN1_RD_PNTR_BMSK, {0} },
};
void msm_jpegdma_hw_fe_buffer_update(struct msm_jpeg_hw_buf *p_input,
uint8_t pingpong_index, void *base)
{
struct msm_jpeg_hw_cmd *hw_cmd_p;
struct msm_jpeg_hw_cmd tmp_hw_cmd;
if (pingpong_index != 0)
return;
hw_cmd_p = &hw_dma_cmd_fe_ping_update[0];
/* ensure write is done */
wmb();
msm_jpeg_hw_write(hw_cmd_p++, base);
/* ensure write is done */
wmb();
msm_jpeg_hw_write(hw_cmd_p++, base);
/* ensure write is done */
wmb();
tmp_hw_cmd = *hw_cmd_p++;
tmp_hw_cmd.data = p_input->y_buffer_addr;
msm_jpeg_hw_write(&tmp_hw_cmd, base);
/* ensure write is done */
wmb();
tmp_hw_cmd = *hw_cmd_p++;
tmp_hw_cmd.data = p_input->cbcr_buffer_addr;
msm_jpeg_hw_write(&tmp_hw_cmd, base);
/* ensure write is done */
wmb();
}
struct msm_jpeg_hw_cmd hw_cmd_fe_start[] = {
/* type, repeat n times, offset, mask, data or pdata */
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_CMD_ADDR,
JPEG_CMD_BMSK, {JPEG_OFFLINE_CMD_START} },
};
void msm_jpeg_hw_fe_start(void *base)
{
msm_jpeg_hw_write(&hw_cmd_fe_start[0], base);
}
struct msm_jpeg_hw_cmd hw_cmd_we_ping_update[] = {
/* type, repeat n times, offset, mask, data or pdata */
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN0_WR_PNTR_ADDR,
JPEG_PLN0_WR_PNTR_BMSK, {0} },
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN1_WR_PNTR_ADDR,
JPEG_PLN0_WR_PNTR_BMSK, {0} },
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN2_WR_PNTR_ADDR,
JPEG_PLN0_WR_PNTR_BMSK, {0} },
};
void msm_jpeg_decode_status(void *base)
{
uint32_t data;
data = msm_camera_io_r(base + JPEG_DECODE_MCUS_DECODED_STATUS);
JPEG_DBG_HIGH("Decode MCUs decode status %u", data);
data = msm_camera_io_r(base + JPEG_DECODE_BITS_CONSUMED_STATUS);
JPEG_DBG_HIGH("Decode bits consumed status %u", data);
data = msm_camera_io_r(base + JPEG_DECODE_PRED_Y_STATE);
JPEG_DBG_HIGH("Decode prediction Y state %u", data);
data = msm_camera_io_r(base + JPEG_DECODE_PRED_C_STATE);
JPEG_DBG_HIGH("Decode prediction C state %u", data);
data = msm_camera_io_r(base + JPEG_DECODE_RSM_STATE);
JPEG_DBG_HIGH("Decode prediction RSM state %u", data);
}
void msm_jpeg_hw_we_buffer_update(struct msm_jpeg_hw_buf *p_input,
uint8_t pingpong_index, void *base)
{
struct msm_jpeg_hw_cmd *hw_cmd_p;
struct msm_jpeg_hw_cmd tmp_hw_cmd;
if (pingpong_index == 0) {
hw_cmd_p = &hw_cmd_we_ping_update[0];
tmp_hw_cmd = *hw_cmd_p++;
tmp_hw_cmd.data = p_input->y_buffer_addr;
JPEG_DBG_HIGH("%s Output pln0 buffer address is %x\n", __func__,
p_input->y_buffer_addr);
msm_jpeg_hw_write(&tmp_hw_cmd, base);
tmp_hw_cmd = *hw_cmd_p++;
tmp_hw_cmd.data = p_input->cbcr_buffer_addr;
JPEG_DBG_HIGH("%s Output pln1 buffer address is %x\n", __func__,
p_input->cbcr_buffer_addr);
msm_jpeg_hw_write(&tmp_hw_cmd, base);
tmp_hw_cmd = *hw_cmd_p++;
tmp_hw_cmd.data = p_input->pln2_addr;
JPEG_DBG_HIGH("%s Output pln2 buffer address is %x\n", __func__,
p_input->pln2_addr);
msm_jpeg_hw_write(&tmp_hw_cmd, base);
}
}
struct msm_jpeg_hw_cmd hw_dma_cmd_we_ping_update[] = {
/* type, repeat n times, offset, mask, data or pdata */
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEGDMA_CMD_ADDR,
JPEGDMA_CMD_BMSK, {JPEGDMA_CMD_CLEAR_WRITE_PLN_QUEUES} },
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEGDMA_WE_0_WR_PNTR,
JPEG_PLN0_WR_PNTR_BMSK, {0} },
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEGDMA_WE_1_WR_PNTR,
JPEG_PLN0_WR_PNTR_BMSK, {0} },
};
void msm_jpegdma_hw_we_buffer_update(struct msm_jpeg_hw_buf *p_input,
uint8_t pingpong_index, void *base)
{
struct msm_jpeg_hw_cmd *hw_cmd_p;
struct msm_jpeg_hw_cmd tmp_hw_cmd;
if (pingpong_index != 0)
return;
hw_cmd_p = &hw_dma_cmd_we_ping_update[0];
msm_jpeg_hw_write(hw_cmd_p++, base);
/* ensure write is done */
wmb();
tmp_hw_cmd = *hw_cmd_p++;
tmp_hw_cmd.data = p_input->y_buffer_addr;
JPEG_DBG_HIGH("%s Output we 0 buffer address is %x\n", __func__,
p_input->y_buffer_addr);
msm_jpeg_hw_write(&tmp_hw_cmd, base);
/* ensure write is done */
wmb();
tmp_hw_cmd = *hw_cmd_p++;
tmp_hw_cmd.data = p_input->cbcr_buffer_addr;
JPEG_DBG_HIGH("%s Output we 1 buffer address is %x\n", __func__,
p_input->cbcr_buffer_addr);
msm_jpeg_hw_write(&tmp_hw_cmd, base);
/* ensure write is done */
wmb();
}
struct msm_jpeg_hw_cmd hw_cmd_fe_mmu_prefetch[] = {
/* type, repeat n times, offset, mask, data or pdata */
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEG_S0_MMU_PF_ADDR_MIN,
MSM_JPEG_S0_MMU_PF_ADDR_MIN_BMSK, {0} },
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEG_S0_MMU_PF_ADDR_MAX,
MSM_JPEG_S0_MMU_PF_ADDR_MAX_BMSK, {0} },
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEG_S1_MMU_PF_ADDR_MIN,
MSM_JPEG_S1_MMU_PF_ADDR_MIN_BMSK, {0} },
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEG_S1_MMU_PF_ADDR_MAX,
MSM_JPEG_S1_MMU_PF_ADDR_MAX_BMSK, {0} },
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEG_S2_MMU_PF_ADDR_MIN,
MSM_JPEG_S2_MMU_PF_ADDR_MIN_BMSK, {0} },
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEG_S2_MMU_PF_ADDR_MAX,
MSM_JPEG_S2_MMU_PF_ADDR_MAX_BMSK, {0} },
};
/*
* msm_jpeg_hw_fe_mmu_prefetch() - writes fe min/max addrs for each plane to
* MMU prefetch registers.
* @buf: Pointer to jpeg hw buffer.
* @base: Pointer to base address.
* @decode_flag: Jpeg decode flag.
*
* This function writes fe min/max address for each plane to MMU prefetch
* registers, MMU prefetch hardware will only prefetch address translations
* within this min/max boundary.
*
* Return: None.
*/
void msm_jpeg_hw_fe_mmu_prefetch(struct msm_jpeg_hw_buf *buf, void *base,
uint8_t decode_flag)
{
struct msm_jpeg_hw_cmd *hw_cmd_p;
struct msm_jpeg_hw_cmd tmp_hw_cmd;
hw_cmd_p = &hw_cmd_fe_mmu_prefetch[0];
tmp_hw_cmd = *hw_cmd_p++;
tmp_hw_cmd.data = buf->y_buffer_addr;
JPEG_DBG("%s:%d: MIN y_buf_addr %08x\n",
__func__, __LINE__, tmp_hw_cmd.data);
/* ensure write is done */
wmb();
msm_jpeg_hw_write(&tmp_hw_cmd, base);
tmp_hw_cmd = *hw_cmd_p++;
tmp_hw_cmd.data = buf->y_buffer_addr;
if (buf->y_len)
tmp_hw_cmd.data += buf->y_len - 1;
JPEG_DBG("%s:%d: MAX y_buf_addr %08x, y_len %d\n",
__func__, __LINE__, tmp_hw_cmd.data, buf->y_len);
msm_jpeg_hw_write(&tmp_hw_cmd, base);
if (!decode_flag) {
tmp_hw_cmd = *hw_cmd_p++;
tmp_hw_cmd.data = buf->cbcr_buffer_addr;
JPEG_DBG("%s:%d: MIN cbcr_buf_addr %08x\n",
__func__, __LINE__, tmp_hw_cmd.data);
msm_jpeg_hw_write(&tmp_hw_cmd, base);
tmp_hw_cmd = *hw_cmd_p++;
tmp_hw_cmd.data = buf->cbcr_buffer_addr;
if (buf->cbcr_len)
tmp_hw_cmd.data += buf->cbcr_len - 1;
JPEG_DBG("%s:%d: MAX cbcr_buf_addr %08x, cbcr_len %d\n"
, __func__, __LINE__, tmp_hw_cmd.data, buf->cbcr_len);
msm_jpeg_hw_write(&tmp_hw_cmd, base);
tmp_hw_cmd = *hw_cmd_p++;
tmp_hw_cmd.data = buf->pln2_addr;
JPEG_DBG("%s:%d: MIN pln2_buf_addr %08x\n",
__func__, __LINE__, tmp_hw_cmd.data);
msm_jpeg_hw_write(&tmp_hw_cmd, base);
tmp_hw_cmd = *hw_cmd_p++;
tmp_hw_cmd.data = buf->pln2_addr;
if (buf->pln2_len)
tmp_hw_cmd.data += buf->pln2_len - 1;
JPEG_DBG("%s:%d: MAX pln2_buf_addr %08x, pln2_len %d\n"
, __func__, __LINE__, tmp_hw_cmd.data, buf->pln2_len);
msm_jpeg_hw_write(&tmp_hw_cmd, base);
}
/* ensure write is done */
wmb();
}
struct msm_jpeg_hw_cmd hw_cmd_we_mmu_prefetch[] = {
/* type, repeat n times, offset, mask, data or pdata */
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEG_S1_MMU_PF_ADDR_MIN,
MSM_JPEG_S1_MMU_PF_ADDR_MIN_BMSK, {0} },
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEG_S1_MMU_PF_ADDR_MAX,
MSM_JPEG_S1_MMU_PF_ADDR_MAX_BMSK, {0} },
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEG_S2_MMU_PF_ADDR_MIN,
MSM_JPEG_S2_MMU_PF_ADDR_MIN_BMSK, {0} },
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEG_S2_MMU_PF_ADDR_MAX,
MSM_JPEG_S2_MMU_PF_ADDR_MAX_BMSK, {0} },
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEG_S3_MMU_PF_ADDR_MIN,
MSM_JPEG_S3_MMU_PF_ADDR_MIN_BMSK, {0} },
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEG_S3_MMU_PF_ADDR_MAX,
MSM_JPEG_S3_MMU_PF_ADDR_MAX_BMSK, {0} },
};
/*
* msm_jpeg_hw_we_mmu_prefetch() - write we min/max addrs for each plane to
* MMU prefetch registers.
* @buf: Pointer to jpeg hw buffer.
* @base: Pointer to base address.
* @decode_flag: Jpeg decode flag.
*
* This function writes we min/max address for each plane to MMU prefetch
* registers, MMU prefetch hardware will only prefetch address translations
* within this min/max boundary.
*
* Return: None.
*/
void msm_jpeg_hw_we_mmu_prefetch(struct msm_jpeg_hw_buf *buf, void *base,
uint8_t decode_flag)
{
struct msm_jpeg_hw_cmd *hw_cmd_p;
struct msm_jpeg_hw_cmd tmp_hw_cmd;
hw_cmd_p = &hw_cmd_we_mmu_prefetch[0];
/* ensure write is done */
wmb();
if (decode_flag) {
tmp_hw_cmd = *hw_cmd_p++;
tmp_hw_cmd.data = buf->y_buffer_addr;
JPEG_DBG("%s:%d: MIN y_buf_addr %08x\n",
__func__, __LINE__, tmp_hw_cmd.data);
msm_jpeg_hw_write(&tmp_hw_cmd, base);
tmp_hw_cmd = *hw_cmd_p++;
tmp_hw_cmd.data = buf->y_buffer_addr;
if (buf->y_len)
tmp_hw_cmd.data += buf->y_len - 1;
JPEG_DBG("%s:%d: MAX y_buf_addr %08x, y_len %d\n",
__func__, __LINE__, tmp_hw_cmd.data, buf->y_len);
msm_jpeg_hw_write(&tmp_hw_cmd, base);
tmp_hw_cmd = *hw_cmd_p++;
tmp_hw_cmd.data = buf->cbcr_buffer_addr;
JPEG_DBG("%s:%d: MIN cbcr_buf_addr %08x\n",
__func__, __LINE__, tmp_hw_cmd.data);
msm_jpeg_hw_write(&tmp_hw_cmd, base);
tmp_hw_cmd = *hw_cmd_p++;
tmp_hw_cmd.data = buf->cbcr_buffer_addr;
if (buf->cbcr_len)
tmp_hw_cmd.data += buf->cbcr_len - 1;
JPEG_DBG("%s:%d: MAX cbcr_buf_addr %08x, cbcr_len %d\n"
, __func__, __LINE__, tmp_hw_cmd.data, buf->cbcr_len);
msm_jpeg_hw_write(&tmp_hw_cmd, base);
tmp_hw_cmd = *hw_cmd_p++;
tmp_hw_cmd.data = buf->pln2_addr;
JPEG_DBG("%s:%d: MIN pln2_buf_addr %08x\n",
__func__, __LINE__, tmp_hw_cmd.data);
msm_jpeg_hw_write(&tmp_hw_cmd, base);
tmp_hw_cmd = *hw_cmd_p++;
tmp_hw_cmd.data = buf->pln2_addr;
if (buf->pln2_len)
tmp_hw_cmd.data += buf->pln2_len - 1;
JPEG_DBG("%s:%d: MIN pln2_buf_addr %08x, pln2_len %d\n"
, __func__, __LINE__, tmp_hw_cmd.data, buf->pln2_len);
msm_jpeg_hw_write(&tmp_hw_cmd, base);
} else {
hw_cmd_p += 4;
tmp_hw_cmd = *hw_cmd_p++;
tmp_hw_cmd.data = buf->y_buffer_addr;
JPEG_DBG("%s:%d: MIN y_buf_addr %08x\n",
__func__, __LINE__, tmp_hw_cmd.data);
msm_jpeg_hw_write(&tmp_hw_cmd, base);
tmp_hw_cmd = *hw_cmd_p++;
tmp_hw_cmd.data = buf->y_buffer_addr;
if (buf->y_len)
tmp_hw_cmd.data += buf->y_len - 1;
JPEG_DBG("%s:%d: MAX y_buf_addr %08x, y_len %d\n",
__func__, __LINE__, tmp_hw_cmd.data, buf->y_len);
msm_jpeg_hw_write(&tmp_hw_cmd, base);
}
/* ensure write is done */
wmb();
}
struct msm_jpeg_hw_cmd hw_dma_cmd_fe_mmu_prefetch[] = {
/* type, repeat n times, offset, mask, data or pdata */
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEGDMA_S0_MMU_PF_ADDR_MIN,
MSM_JPEGDMA_S0_MMU_PF_ADDR_MIN_BMSK, {0} },
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEGDMA_S0_MMU_PF_ADDR_MAX,
MSM_JPEGDMA_S0_MMU_PF_ADDR_MAX_BMSK, {0} },
};
/*
* msm_jpegdma_hw_fe_mmu_prefetch() - write DMA fe min/max addrs to
* MMU prefetch registers.
* @buf: Pointer to jpeg hw buffer.
* @base: Pointer to base address.
*
* This function writes DMA fe min/max address for each plane to MMU prefetch
* registers, MMU prefetch hardware will only prefetch address translations
* with in this min/max boundary.
*
* Return: None.
*/
void msm_jpegdma_hw_fe_mmu_prefetch(struct msm_jpeg_hw_buf *buf, void *base)
{
struct msm_jpeg_hw_cmd *hw_cmd_p;
struct msm_jpeg_hw_cmd tmp_hw_cmd;
hw_cmd_p = &hw_dma_cmd_fe_mmu_prefetch[0];
tmp_hw_cmd = *hw_cmd_p++;
tmp_hw_cmd.data = buf->y_buffer_addr;
JPEG_DBG("%s:%d: MIN DMA addr %08x , reg offset %08x\n",
__func__, __LINE__, tmp_hw_cmd.data, tmp_hw_cmd.offset);
/* ensure write is done */
wmb();
msm_jpeg_hw_write(&tmp_hw_cmd, base);
tmp_hw_cmd = *hw_cmd_p++;
tmp_hw_cmd.data = buf->y_buffer_addr;
if (buf->y_len)
tmp_hw_cmd.data += buf->y_len - 1;
JPEG_DBG("%s:%d: MAX DMA addr %08x , reg offset %08x , length %d\n",
__func__, __LINE__, tmp_hw_cmd.data, tmp_hw_cmd.offset,
buf->y_len);
msm_jpeg_hw_write(&tmp_hw_cmd, base);
/* ensure write is done */
wmb();
}
struct msm_jpeg_hw_cmd hw_dma_cmd_we_mmu_prefetch[] = {
/* type, repeat n times, offset, mask, data or pdata */
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEGDMA_S1_MMU_PF_ADDR_MIN,
MSM_JPEGDMA_S1_MMU_PF_ADDR_MIN_BMSK, {0} },
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, MSM_JPEGDMA_S1_MMU_PF_ADDR_MAX,
MSM_JPEGDMA_S1_MMU_PF_ADDR_MAX_BMSK, {0} },
};
/*
* msm_jpegdma_hw_we_mmu_prefetch() - write DMA we min/max addrs to
* MMU prefetch registers.
* @buf: Pointer to jpeg hw buffer.
* @base: Pointer to base address.
*
* This function writes DMA we min/max address for each plane to MMU prefetch
* registers, MMU prefetch hardware will only prefetch address translations
* with in this min/max boundary.
*
* Return: None.
*/
void msm_jpegdma_hw_we_mmu_prefetch(struct msm_jpeg_hw_buf *buf, void *base)
{
struct msm_jpeg_hw_cmd *hw_cmd_p;
struct msm_jpeg_hw_cmd tmp_hw_cmd;
hw_cmd_p = &hw_dma_cmd_we_mmu_prefetch[0];
tmp_hw_cmd = *hw_cmd_p++;
tmp_hw_cmd.data = buf->y_buffer_addr;
JPEG_DBG("%s:%d: MIN DMA addr %08x , reg offset %08x\n",
__func__, __LINE__, tmp_hw_cmd.data, tmp_hw_cmd.offset);
/* ensure write is done */
wmb();
msm_jpeg_hw_write(&tmp_hw_cmd, base);
tmp_hw_cmd = *hw_cmd_p++;
tmp_hw_cmd.data = buf->y_buffer_addr;
if (buf->y_len)
tmp_hw_cmd.data += buf->y_len - 1;
JPEG_DBG("%s:%d: MAX DMA addr %08x , reg offset %08x , length %d\n",
__func__, __LINE__, tmp_hw_cmd.data, tmp_hw_cmd.offset,
buf->y_len);
msm_jpeg_hw_write(&tmp_hw_cmd, base);
/* ensure write is done */
wmb();
}
struct msm_jpeg_hw_cmd hw_cmd_reset[] = {
/* type, repeat n times, offset, mask, data or pdata */
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_MASK_ADDR,
JPEG_IRQ_MASK_BMSK, {JPEG_IRQ_DISABLE_ALL} },
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_CLEAR_ADDR,
JPEG_IRQ_MASK_BMSK, {JPEG_IRQ_CLEAR_ALL} },
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_MASK_ADDR,
JPEG_IRQ_MASK_BMSK, {JPEG_IRQ_ALLSOURCES_ENABLE} },
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_RESET_CMD_ADDR,
JPEG_RESET_CMD_RMSK, {JPEG_RESET_DEFAULT} },
};
void msm_jpeg_hw_reset(void *base, int size)
{
struct msm_jpeg_hw_cmd *hw_cmd_p;
hw_cmd_p = &hw_cmd_reset[0];
/* ensure write is done */
wmb();
msm_jpeg_hw_write(hw_cmd_p++, base);
/* ensure write is done */
wmb();
msm_jpeg_hw_write(hw_cmd_p++, base);
/* ensure write is done */
wmb();
msm_jpeg_hw_write(hw_cmd_p++, base);
/* ensure write is done */
wmb();
msm_jpeg_hw_write(hw_cmd_p, base);
/* ensure write is done */
wmb();
}
struct msm_jpeg_hw_cmd hw_cmd_reset_dma[] = {
/* type, repeat n times, offset, mask, data or pdata */
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEGDMA_IRQ_MASK_ADDR,
JPEGDMA_IRQ_MASK_BMSK, {JPEGDMA_IRQ_DISABLE_ALL} },
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEGDMA_IRQ_CLEAR_ADDR,
JPEGDMA_IRQ_MASK_BMSK, {JPEGDMA_IRQ_CLEAR_ALL} },
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEGDMA_IRQ_MASK_ADDR,
JPEGDMA_IRQ_MASK_BMSK, {JPEGDMA_IRQ_ALLSOURCES_ENABLE} },
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEGDMA_RESET_CMD_ADDR,
JPEGDMA_RESET_CMD_BMSK, {JPEGDMA_RESET_DEFAULT} },
};
void msm_jpeg_hw_reset_dma(void *base, int size)
{
struct msm_jpeg_hw_cmd *hw_cmd_p;
hw_cmd_p = &hw_cmd_reset_dma[0];
/* ensure write is done */
wmb();
msm_jpeg_hw_write(hw_cmd_p++, base);
/* ensure write is done */
wmb();
msm_jpeg_hw_write(hw_cmd_p++, base);
/* ensure write is done */
wmb();
msm_jpeg_hw_write(hw_cmd_p++, base);
/* ensure write is done */
wmb();
msm_jpeg_hw_write(hw_cmd_p, base);
/* ensure write is done */
wmb();
}
uint32_t msm_jpeg_hw_read(struct msm_jpeg_hw_cmd *hw_cmd_p,
void *jpeg_region_base)
{
uint32_t *paddr;
uint32_t data;
paddr = jpeg_region_base + hw_cmd_p->offset;
data = msm_camera_io_r(paddr);
data &= hw_cmd_p->mask;
return data;
}
void msm_jpeg_hw_write(struct msm_jpeg_hw_cmd *hw_cmd_p,
void *jpeg_region_base)
{
uint32_t *paddr;
uint32_t old_data, new_data;
paddr = jpeg_region_base + hw_cmd_p->offset;
if (hw_cmd_p->mask == 0xffffffff) {
old_data = 0;
} else {
old_data = msm_camera_io_r(paddr);
old_data &= ~hw_cmd_p->mask;
}
new_data = hw_cmd_p->data & hw_cmd_p->mask;
new_data |= old_data;
JPEG_DBG("%s:%d] %pK %08x\n", __func__, __LINE__,
paddr, new_data);
msm_camera_io_w(new_data, paddr);
}
int msm_jpeg_hw_wait(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_us,
void *base)
{
int tm = hw_cmd_p->n;
uint32_t data;
uint32_t wait_data = hw_cmd_p->data & hw_cmd_p->mask;
data = msm_jpeg_hw_read(hw_cmd_p, base);
if (data != wait_data) {
while (tm) {
udelay(m_us);
data = msm_jpeg_hw_read(hw_cmd_p, base);
if (data == wait_data)
break;
tm--;
}
}
hw_cmd_p->data = data;
return tm;
}
void msm_jpeg_hw_delay(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_us)
{
int tm = hw_cmd_p->n;
while (tm) {
udelay(m_us);
tm--;
}
}
int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *hw_cmd_p, uint32_t m_cmds,
uint32_t max_size, void *base)
{
int is_copy_to_user = 0;
uint32_t data;
while (m_cmds--) {
if (hw_cmd_p->offset >= max_size) {
JPEG_PR_ERR("%s:%d] %d exceed hw region %d\n", __func__,
__LINE__, hw_cmd_p->offset, max_size);
return -EFAULT;
}
if (hw_cmd_p->offset & 0x3) {
JPEG_PR_ERR("%s:%d] %d Invalid alignment\n", __func__,
__LINE__, hw_cmd_p->offset);
return -EFAULT;
}
switch (hw_cmd_p->type) {
case MSM_JPEG_HW_CMD_TYPE_READ:
hw_cmd_p->data = msm_jpeg_hw_read(hw_cmd_p, base);
is_copy_to_user = 1;
break;
case MSM_JPEG_HW_CMD_TYPE_WRITE:
msm_jpeg_hw_write(hw_cmd_p, base);
break;
case MSM_JPEG_HW_CMD_TYPE_WRITE_OR:
data = msm_jpeg_hw_read(hw_cmd_p, base);
hw_cmd_p->data = (hw_cmd_p->data & hw_cmd_p->mask) |
data;
msm_jpeg_hw_write(hw_cmd_p, base);
break;
case MSM_JPEG_HW_CMD_TYPE_UWAIT:
msm_jpeg_hw_wait(hw_cmd_p, 1, base);
break;
case MSM_JPEG_HW_CMD_TYPE_MWAIT:
msm_jpeg_hw_wait(hw_cmd_p, 1000, base);
break;
case MSM_JPEG_HW_CMD_TYPE_UDELAY:
msm_jpeg_hw_delay(hw_cmd_p, 1);
break;
case MSM_JPEG_HW_CMD_TYPE_MDELAY:
msm_jpeg_hw_delay(hw_cmd_p, 1000);
break;
default:
JPEG_PR_ERR("wrong hw command type\n");
break;
}
hw_cmd_p++;
}
return is_copy_to_user;
}
void msm_jpeg_io_dump(void *base, int size)
{
char line_str[128], *p_str;
void __iomem *addr = (void __iomem *)base;
int i;
u32 *p = (u32 *) addr;
u32 data;
JPEG_DBG_HIGH("%s:%d] %pK %d", __func__, __LINE__, 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, "%08lx: ", (unsigned long)p);
p_str += 10;
}
data = msm_camera_io_r(p++);
snprintf(p_str, 12, "%08x ", data);
p_str += 9;
if ((i + 1) % 4 == 0) {
JPEG_DBG_HIGH("%s\n", line_str);
line_str[0] = '\0';
p_str = line_str;
}
}
if (line_str[0] != '\0')
JPEG_DBG_HIGH("%s\n", line_str);
}

View file

@ -0,0 +1,142 @@
/* Copyright (c) 2012-2017, 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_JPEG_HW_H
#define MSM_JPEG_HW_H
#include <media/msm_jpeg.h>
#include "msm_jpeg_hw_reg.h"
#include <linux/ion.h>
struct msm_jpeg_hw_buf {
struct msm_jpeg_buf vbuf;
struct file *file;
uint32_t framedone_len;
uint32_t y_buffer_addr;
uint32_t y_len;
uint32_t cbcr_buffer_addr;
uint32_t cbcr_len;
uint32_t num_of_mcu_rows;
int ion_fd;
uint32_t pln2_addr;
uint32_t pln2_len;
};
struct msm_jpeg_hw_pingpong {
uint8_t is_fe; /* 1: fe; 0: we */
struct msm_jpeg_hw_buf buf[2];
int buf_status[2];
int buf_active_index;
};
int msm_jpeg_hw_pingpong_update(struct msm_jpeg_hw_pingpong *pingpong_hw,
struct msm_jpeg_hw_buf *buf, void *);
int msm_jpegdma_hw_pingpong_update(struct msm_jpeg_hw_pingpong *pingpong_hw,
struct msm_jpeg_hw_buf *buf, void *);
void *msm_jpeg_hw_pingpong_irq(struct msm_jpeg_hw_pingpong *pingpong_hw);
void *msm_jpeg_hw_pingpong_active_buffer(struct msm_jpeg_hw_pingpong
*pingpong_hw);
void msm_jpeg_hw_irq_clear(uint32_t, uint32_t, void *);
void msm_jpegdma_hw_irq_clear(uint32_t, uint32_t, void *);
int msm_jpeg_hw_irq_get_status(void *);
int msm_jpegdma_hw_irq_get_status(void *);
long msm_jpeg_hw_encode_output_size(void *);
#define MSM_JPEG_HW_MASK_COMP_FRAMEDONE \
MSM_JPEG_HW_IRQ_STATUS_FRAMEDONE_MASK
#define MSM_JPEG_HW_MASK_COMP_FE \
MSM_JPEG_HW_IRQ_STATUS_FE_RD_DONE_MASK
#define MSM_JPEG_HW_MASK_COMP_WE \
(MSM_JPEG_HW_IRQ_STATUS_WE_Y_PINGPONG_MASK | \
MSM_JPEG_HW_IRQ_STATUS_WE_CBCR_PINGPONG_MASK)
#define MSM_JPEG_HW_MASK_COMP_RESET_ACK \
MSM_JPEG_HW_IRQ_STATUS_RESET_ACK_MASK
#define MSM_JPEG_HW_MASK_COMP_ERR \
(MSM_JPEG_HW_IRQ_STATUS_DCD_UNESCAPED_FF | \
MSM_JPEG_HW_IRQ_STATUS_DCD_HUFFMAN_ERROR | \
MSM_JPEG_HW_IRQ_STATUS_DCD_COEFFICIENT_ERR | \
MSM_JPEG_HW_IRQ_STATUS_DCD_MISSING_BIT_STUFF | \
MSM_JPEG_HW_IRQ_STATUS_DCD_SCAN_UNDERFLOW | \
MSM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM | \
MSM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM_SEQ | \
MSM_JPEG_HW_IRQ_STATUS_DCD_MISSING_RSM | \
MSM_JPEG_HW_IRQ_STATUS_VIOLATION_MASK)
#define msm_jpeg_hw_irq_is_frame_done(jpeg_irq_status) \
(jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_FRAMEDONE)
#define msm_jpeg_hw_irq_is_fe_pingpong(jpeg_irq_status) \
(jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_FE)
#define msm_jpeg_hw_irq_is_we_pingpong(jpeg_irq_status) \
(jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_WE)
#define msm_jpeg_hw_irq_is_reset_ack(jpeg_irq_status) \
(jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_RESET_ACK)
#define msm_jpeg_hw_irq_is_err(jpeg_irq_status) \
(jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_ERR)
#define MSM_JPEGDMA_HW_MASK_COMP_FRAMEDONE \
MSM_JPEGDMA_HW_IRQ_STATUS_FRAMEDONE_MASK
#define MSM_JPEGDMA_HW_MASK_COMP_FE \
MSM_JPEGDMA_HW_IRQ_STATUS_FE_RD_DONE_MASK
#define MSM_JPEGDMA_HW_MASK_COMP_WE \
(MSM_JPEGDMA_HW_IRQ_STATUS_WE_WR_DONE_MASK)
#define MSM_JPEGDMA_HW_MASK_COMP_RESET_ACK \
MSM_JPEGDMA_HW_IRQ_STATUS_RESET_ACK_MASK
#define msm_jpegdma_hw_irq_is_frame_done(jpeg_irq_status) \
(jpeg_irq_status & MSM_JPEGDMA_HW_MASK_COMP_FRAMEDONE)
#define msm_jpegdma_hw_irq_is_fe_pingpong(jpeg_irq_status) \
(jpeg_irq_status & MSM_JPEGDMA_HW_MASK_COMP_FE)
#define msm_jpegdma_hw_irq_is_we_pingpong(jpeg_irq_status) \
(jpeg_irq_status & MSM_JPEGDMA_HW_MASK_COMP_WE)
#define msm_jpegdma_hw_irq_is_reset_ack(jpeg_irq_status) \
(jpeg_irq_status & MSM_JPEGDMA_HW_MASK_COMP_RESET_ACK)
void msm_jpeg_hw_fe_buffer_update(struct msm_jpeg_hw_buf *p_input,
uint8_t pingpong_index, void *);
void msm_jpeg_hw_we_buffer_update(struct msm_jpeg_hw_buf *p_input,
uint8_t pingpong_index, void *);
void msm_jpegdma_hw_fe_buffer_update(struct msm_jpeg_hw_buf *p_input,
uint8_t pingpong_index, void *);
void msm_jpegdma_hw_we_buffer_update(struct msm_jpeg_hw_buf *p_input,
uint8_t pingpong_index, void *);
void msm_jpeg_hw_we_buffer_cfg(uint8_t is_realtime);
void msm_jpeg_hw_fe_mmu_prefetch(struct msm_jpeg_hw_buf *buf, void *,
uint8_t decode_flag);
void msm_jpeg_hw_we_mmu_prefetch(struct msm_jpeg_hw_buf *buf, void *,
uint8_t decode_flag);
void msm_jpegdma_hw_fe_mmu_prefetch(struct msm_jpeg_hw_buf *buf, void *);
void msm_jpegdma_hw_we_mmu_prefetch(struct msm_jpeg_hw_buf *buf, void *);
void msm_jpeg_hw_fe_start(void *);
void msm_jpeg_hw_clk_cfg(void);
void msm_jpeg_hw_reset(void *base, int size);
void msm_jpeg_hw_irq_cfg(void);
uint32_t msm_jpeg_hw_read(struct msm_jpeg_hw_cmd *, void *);
void msm_jpeg_hw_write(struct msm_jpeg_hw_cmd *, void *);
int msm_jpeg_hw_wait(struct msm_jpeg_hw_cmd *, int, void *);
void msm_jpeg_hw_delay(struct msm_jpeg_hw_cmd *, int);
int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *, uint32_t,
uint32_t, void *);
void msm_jpeg_hw_region_dump(int size);
void msm_jpeg_io_dump(void *base, int size);
void msm_jpeg_decode_status(void *base);
void msm_jpeg_hw_reset_dma(void *base, int size);
#endif /* MSM_JPEG_HW_H */

View file

@ -0,0 +1,210 @@
/* Copyright (c) 2012-2017, 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_JPEG_HW_REG_H
#define MSM_JPEG_HW_REG_H
#define JPEG_REG_BASE 0
#define MSM_JPEG_HW_IRQ_MASK_ADDR 0x00000018
#define MSM_JPEG_HW_IRQ_MASK_RMSK 0xFFFFFFFF
#define MSM_JPEG_HW_IRQ_ENABLE 0xFFFFFFFF
#define MSM_JPEG_HW_IRQ_STATUS_FRAMEDONE_MASK 0x00000001
#define MSM_JPEG_HW_IRQ_STATUS_FRAMEDONE_SHIFT 0x00000000
#define MSM_JPEG_HW_IRQ_STATUS_FE_RD_DONE_MASK 0x00000010
#define MSM_JPEG_HW_IRQ_STATUS_FE_RD_DONE_SHIFT 0x00000001
#define MSM_JPEG_HW_IRQ_STATUS_FE_RTOVF_MASK 0x00000004
#define MSM_JPEG_HW_IRQ_STATUS_FE_RTOVF_SHIFT 0x00000002
#define MSM_JPEG_HW_IRQ_STATUS_FE_VFE_OVERFLOW_MASK 0x00000008
#define MSM_JPEG_HW_IRQ_STATUS_FE_VFE_OVERFLOW_SHIFT 0x00000003
#define MSM_JPEG_HW_IRQ_STATUS_WE_Y_PINGPONG_MASK 0x00000010
#define MSM_JPEG_HW_IRQ_STATUS_WE_Y_PINGPONG_SHIFT 0x00000004
#define MSM_JPEG_HW_IRQ_STATUS_WE_CBCR_PINGPONG_MASK 0x00000020
#define MSM_JPEG_HW_IRQ_STATUS_WE_CBCR_PINGPONG_SHIFT 0x00000005
#define MSM_JPEG_HW_IRQ_STATUS_RESET_ACK_MASK 0x10000000
#define MSM_JPEG_HW_IRQ_STATUS_RESET_ACK_SHIFT 0x0000000a
#define MSM_JPEG_HW_IRQ_STATUS_BUS_ERROR_MASK 0x00000800
#define MSM_JPEG_HW_IRQ_STATUS_BUS_ERROR_SHIFT 0x0000000b
#define MSM_JPEG_HW_IRQ_STATUS_DCD_UNESCAPED_FF (0x1<<19)
#define MSM_JPEG_HW_IRQ_STATUS_DCD_HUFFMAN_ERROR (0x1<<20)
#define MSM_JPEG_HW_IRQ_STATUS_DCD_COEFFICIENT_ERR (0x1<<21)
#define MSM_JPEG_HW_IRQ_STATUS_DCD_MISSING_BIT_STUFF (0x1<<22)
#define MSM_JPEG_HW_IRQ_STATUS_DCD_SCAN_UNDERFLOW (0x1<<23)
#define MSM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM (0x1<<24)
#define MSM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM_SEQ (0x1<<25)
#define MSM_JPEG_HW_IRQ_STATUS_DCD_MISSING_RSM (0x1<<26)
#define MSM_JPEG_HW_IRQ_STATUS_VIOLATION_MASK (0x1<<29)
#define JPEG_OFFLINE_CMD_START 0x00000001
#define JPEG_RESET_DEFAULT 0x00032093
#define JPEG_IRQ_DISABLE_ALL 0x00000000
#define JPEG_IRQ_CLEAR_ALL 0xFFFFFFFF
#define JPEG_PLN0_RD_PNTR_ADDR (JPEG_REG_BASE + 0x00000038)
#define JPEG_PLN0_RD_PNTR_BMSK 0xFFFFFFFF
#define JPEG_PLN0_RD_OFFSET_ADDR 0x0000003C
#define JPEG_PLN0_RD_OFFSET_BMSK 0xFFFFFFFF
#define JPEG_PLN1_RD_PNTR_ADDR (JPEG_REG_BASE + 0x00000044)
#define JPEG_PLN1_RD_PNTR_BMSK 0xFFFFFFFF
#define JPEG_PLN1_RD_OFFSET_ADDR 0x00000048
#define JPEG_PLN1_RD_OFFSET_BMSK 0xFFFFFFFF
#define JPEG_PLN2_RD_PNTR_ADDR (JPEG_REG_BASE + 0x00000050)
#define JPEG_PLN2_RD_PNTR_BMSK 0xFFFFFFFF
#define JPEG_PLN2_RD_OFFSET_ADDR 0x00000054
#define JPEG_PLN2_RD_OFFSET_BMSK 0xFFFFFFFF
#define JPEG_CMD_ADDR (JPEG_REG_BASE + 0x00000010)
#define JPEG_CMD_BMSK 0xFFFFFFFF
#define JPEG_CMD_CLEAR_WRITE_PLN_QUEUES 0x700
#define JPEG_PLN0_WR_PNTR_ADDR (JPEG_REG_BASE + 0x000000cc)
#define JPEG_PLN0_WR_PNTR_BMSK 0xFFFFFFFF
#define JPEG_PLN1_WR_PNTR_ADDR (JPEG_REG_BASE + 0x000000D0)
#define JPEG_PLN1_WR_PNTR_BMSK 0xFFFFFFFF
#define JPEG_PLN2_WR_PNTR_ADDR (JPEG_REG_BASE + 0x000000D4)
#define JPEG_PLN2_WR_PNTR_BMSK 0xFFFFFFFF
#define JPEG_IRQ_MASK_ADDR (JPEG_REG_BASE + 0x00000018)
#define JPEG_IRQ_MASK_BMSK 0xFFFFFFFF
#define JPEG_IRQ_ALLSOURCES_ENABLE 0xFFFFFFFF
#define JPEG_IRQ_CLEAR_ADDR (JPEG_REG_BASE + 0x0000001c)
#define JPEG_IRQ_CLEAR_BMSK 0xFFFFFFFF
#define JPEG_RESET_CMD_ADDR (JPEG_REG_BASE + 0x00000008)
#define JPEG_RESET_CMD_RMSK 0xFFFFFFFF
#define JPEG_IRQ_STATUS_ADDR (JPEG_REG_BASE + 0x00000020)
#define JPEG_IRQ_STATUS_BMSK 0xFFFFFFFF
#define MSM_JPEG_S0_MMU_PF_ADDR_MIN (JPEG_REG_BASE + 0x00000310)
#define MSM_JPEG_S0_MMU_PF_ADDR_MIN_BMSK 0xFFFFFFFF
#define MSM_JPEG_S0_MMU_PF_ADDR_MAX (JPEG_REG_BASE + 0x00000314)
#define MSM_JPEG_S0_MMU_PF_ADDR_MAX_BMSK 0xFFFFFFFF
#define MSM_JPEG_S1_MMU_PF_ADDR_MIN (JPEG_REG_BASE + 0x0000031C)
#define MSM_JPEG_S1_MMU_PF_ADDR_MIN_BMSK 0xFFFFFFFF
#define MSM_JPEG_S1_MMU_PF_ADDR_MAX (JPEG_REG_BASE + 0x00000320)
#define MSM_JPEG_S1_MMU_PF_ADDR_MAX_BMSK 0xFFFFFFFF
#define MSM_JPEG_S2_MMU_PF_ADDR_MIN (JPEG_REG_BASE + 0x00000328)
#define MSM_JPEG_S2_MMU_PF_ADDR_MIN_BMSK 0xFFFFFFFF
#define MSM_JPEG_S2_MMU_PF_ADDR_MAX (JPEG_REG_BASE + 0x0000032C)
#define MSM_JPEG_S2_MMU_PF_ADDR_MAX_BMSK 0xFFFFFFFF
#define MSM_JPEG_S3_MMU_PF_ADDR_MIN (JPEG_REG_BASE + 0x00000334)
#define MSM_JPEG_S3_MMU_PF_ADDR_MIN_BMSK 0xFFFFFFFF
#define MSM_JPEG_S3_MMU_PF_ADDR_MAX (JPEG_REG_BASE + 0x00000338)
#define MSM_JPEG_S3_MMU_PF_ADDR_MAX_BMSK 0xFFFFFFFF
#define JPEG_ENCODE_OUTPUT_SIZE_STATUS_ADDR (JPEG_REG_BASE + 0x00000180)
#define JPEG_ENCODE_OUTPUT_SIZE_STATUS_BMSK 0x1FFFFFFF
#define JPEG_DECODE_MCUS_DECODED_STATUS (JPEG_REG_BASE + 0x00000258)
#define JPEG_DECODE_BITS_CONSUMED_STATUS (JPEG_REG_BASE + 0x0000025C)
#define JPEG_DECODE_PRED_Y_STATE (JPEG_REG_BASE + 0x00000260)
#define JPEG_DECODE_PRED_C_STATE (JPEG_REG_BASE + 0x00000264)
#define JPEG_DECODE_RSM_STATE (JPEG_REG_BASE + 0x00000268)
#define JPEG_HW_VERSION (JPEG_REG_BASE + 0x00000000)
#define VBIF_BASE_ADDRESS 0xFDA60000
#define VBIF_REGION_SIZE 0xC30
#define JPEG_VBIF_CLKON 0x4
#define JPEG_VBIF_IN_RD_LIM_CONF0 0xB0
#define JPEG_VBIF_IN_RD_LIM_CONF1 0xB4
#define JPEG_VBIF_IN_RD_LIM_CONF2 0xB8
#define JPEG_VBIF_IN_WR_LIM_CONF0 0xC0
#define JPEG_VBIF_IN_WR_LIM_CONF1 0xC4
#define JPEG_VBIF_IN_WR_LIM_CONF2 0xC8
#define JPEG_VBIF_OUT_RD_LIM_CONF0 0xD0
#define JPEG_VBIF_OUT_WR_LIM_CONF0 0xD4
#define JPEG_VBIF_DDR_OUT_MAX_BURST 0xD8
#define JPEG_VBIF_OCMEM_OUT_MAX_BURST 0xDC
#define JPEG_VBIF_ARB_CTL 0xF0
#define JPEG_VBIF_OUT_AXI_AOOO_EN 0x178
#define JPEG_VBIF_OUT_AXI_AOOO 0x17c
#define JPEG_VBIF_ROUND_ROBIN_QOS_ARB 0x124
#define JPEG_VBIF_OUT_AXI_AMEMTYPE_CONF0 0x160
#define JPEG_VBIF_OUT_AXI_AMEMTYPE_CONF1 0x164
#define JPEGDMA_IRQ_MASK_ADDR (JPEG_REG_BASE + 0x0000000C)
#define JPEGDMA_IRQ_MASK_BMSK 0xFFFFFFFF
#define JPEGDMA_IRQ_ALLSOURCES_ENABLE 0xFFFFFFFF
#define JPEGDMA_IRQ_CLEAR_ADDR (JPEG_REG_BASE + 0x00000014)
#define JPEGDMA_IRQ_CLEAR_BMSK 0xFFFFFFFF
#define JPEGDMA_RESET_CMD_ADDR (JPEG_REG_BASE + 0x00000008)
#define JPEGDMA_RESET_CMD_BMSK 0xFFFFFFFF
#define JPEGDMA_IRQ_STATUS_ADDR (JPEG_REG_BASE + 0x00000010)
#define JPEGDMA_IRQ_STATUS_BMSK 0xFFFFFFFF
#define JPEGDMA_RESET_DEFAULT 0x00032083
#define JPEGDMA_CMD_ADDR (JPEG_REG_BASE + 0x0000001C)
#define JPEGDMA_CMD_BMSK (0xFFFFFFFF)
#define JPEGDMA_CMD_CLEAR_READ_PLN_QUEUES 0x030
#define JPEGDMA_CMD_CLEAR_WRITE_PLN_QUEUES 0x300
#define JPEGDMA_IRQ_DISABLE_ALL 0x00000000
#define JPEGDMA_IRQ_CLEAR_ALL 0x00001FFF
#define MSM_JPEGDMA_HW_IRQ_STATUS_FRAMEDONE_MASK 0x00000001
#define MSM_JPEGDMA_HW_IRQ_STATUS_FRAMEDONE_SHIFT 0x00000000
#define MSM_JPEGDMA_HW_IRQ_STATUS_FE_RD_DONE_MASK 0x00000006
#define MSM_JPEGDMA_HW_IRQ_STATUS_FE_RD_DONE_SHIFT 0x00000001
#define MSM_JPEGDMA_HW_IRQ_STATUS_WE_WR_DONE_MASK 0x00000060
#define MSM_JPEGDMA_HW_IRQ_STATUS_WE_WR_DONE_SHIFT 0x00000005
#define MSM_JPEGDMA_HW_IRQ_STATUS_RESET_ACK_MASK 0x00000400
#define MSM_JPEGDMA_HW_IRQ_STATUS_RESET_ACK_SHIFT 0x0000000a
#define MSM_JPEGDMA_FE_0_RD_PNTR (JPEG_REG_BASE + 0x00000034)
#define MSM_JPEGDMA_FE_1_RD_PNTR (JPEG_REG_BASE + 0x00000078)
#define MSM_JPEGDMA_WE_0_WR_PNTR (JPEG_REG_BASE + 0x000000BC)
#define MSM_JPEGDMA_WE_1_WR_PNTR (JPEG_REG_BASE + 0x000000EC)
#define MSM_JPEGDMA_S0_MMU_PF_ADDR_MIN (JPEG_REG_BASE + 0x00000190)
#define MSM_JPEGDMA_S0_MMU_PF_ADDR_MIN_BMSK 0xFFFFFFFF
#define MSM_JPEGDMA_S0_MMU_PF_ADDR_MAX (JPEG_REG_BASE + 0x00000198)
#define MSM_JPEGDMA_S0_MMU_PF_ADDR_MAX_BMSK 0xFFFFFFFF
#define MSM_JPEGDMA_S1_MMU_PF_ADDR_MIN (JPEG_REG_BASE + 0x000001A4)
#define MSM_JPEGDMA_S1_MMU_PF_ADDR_MIN_BMSK 0xFFFFFFFF
#define MSM_JPEGDMA_S1_MMU_PF_ADDR_MAX (JPEG_REG_BASE + 0x000001AC)
#define MSM_JPEGDMA_S1_MMU_PF_ADDR_MAX_BMSK 0xFFFFFFFF
#endif /* MSM_JPEG_HW_REG_H */

View file

@ -0,0 +1,514 @@
/* Copyright (c) 2012-2017, 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 <linux/pm_qos.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/clk/msm-clk.h>
#include <linux/msm-bus.h>
#include <linux/msm-bus-board.h>
#include <linux/iommu.h>
#include <asm/dma-iommu.h>
#include <linux/dma-direction.h>
#include <linux/dma-attrs.h>
#include <linux/dma-buf.h>
#include "msm_camera_io_util.h"
#include "msm_jpeg_platform.h"
#include "msm_jpeg_sync.h"
#include "msm_jpeg_common.h"
#include "msm_jpeg_hw.h"
#define JPEG_DT_PROP_CNT 2
int msm_jpeg_get_clock_index(struct msm_jpeg_device *pgmn_dev,
const char *clk_name)
{
uint32_t i = 0;
for (i = 0; i < pgmn_dev->num_clk; i++) {
if (!strcmp(clk_name, pgmn_dev->jpeg_clk_info[i].clk_name))
return i;
}
return -EINVAL;
}
int msm_jpeg_platform_set_clk_rate(struct msm_jpeg_device *pgmn_dev,
long clk_rate)
{
int rc = 0;
uint32_t msm_jpeg_idx;
/* retrieve clock index from list of clocks */
msm_jpeg_idx = msm_jpeg_get_clock_index(pgmn_dev,
"core_clk");
if (msm_jpeg_idx < 0) {
JPEG_PR_ERR("%s:Fail to get clock index\n", __func__);
return -EINVAL;
}
/* set the rate */
msm_camera_clk_set_rate(&pgmn_dev->pdev->dev,
pgmn_dev->jpeg_clk[msm_jpeg_idx], clk_rate);
return rc;
}
void msm_jpeg_platform_p2v(int iommu_hdl, int fd)
{
cam_smmu_put_phy_addr(iommu_hdl, fd);
}
uint32_t msm_jpeg_platform_v2p(struct msm_jpeg_device *pgmn_dev, int fd,
uint32_t len, int iommu_hdl)
{
dma_addr_t paddr;
size_t size;
int rc;
rc = cam_smmu_get_phy_addr(pgmn_dev->iommu_hdl, fd, CAM_SMMU_MAP_RW,
&paddr, &size);
JPEG_DBG("%s:%d] addr 0x%x size %zu", __func__, __LINE__,
(uint32_t)paddr, size);
if (rc < 0) {
JPEG_PR_ERR("%s: fd %d got phy addr error %d\n", __func__, fd,
rc);
goto err_get_phy;
}
/* validate user input */
if (len > size) {
JPEG_PR_ERR("%s: invalid offset + len\n", __func__);
goto err_size;
}
return paddr;
err_size:
cam_smmu_put_phy_addr(pgmn_dev->iommu_hdl, fd);
err_get_phy:
return 0;
}
static void set_vbif_params(struct msm_jpeg_device *pgmn_dev,
void *jpeg_vbif_base)
{
msm_camera_io_w(0x1,
jpeg_vbif_base + JPEG_VBIF_CLKON);
if (pgmn_dev->hw_version != JPEG_8994) {
msm_camera_io_w(0x10101010,
jpeg_vbif_base + JPEG_VBIF_IN_RD_LIM_CONF0);
msm_camera_io_w(0x10101010,
jpeg_vbif_base + JPEG_VBIF_IN_RD_LIM_CONF1);
msm_camera_io_w(0x10101010,
jpeg_vbif_base + JPEG_VBIF_IN_RD_LIM_CONF2);
msm_camera_io_w(0x10101010,
jpeg_vbif_base + JPEG_VBIF_IN_WR_LIM_CONF0);
msm_camera_io_w(0x10101010,
jpeg_vbif_base + JPEG_VBIF_IN_WR_LIM_CONF1);
msm_camera_io_w(0x10101010,
jpeg_vbif_base + JPEG_VBIF_IN_WR_LIM_CONF2);
msm_camera_io_w(0x00001010,
jpeg_vbif_base + JPEG_VBIF_OUT_RD_LIM_CONF0);
msm_camera_io_w(0x00000110,
jpeg_vbif_base + JPEG_VBIF_OUT_WR_LIM_CONF0);
msm_camera_io_w(0x00000707,
jpeg_vbif_base + JPEG_VBIF_DDR_OUT_MAX_BURST);
msm_camera_io_w(0x00000FFF,
jpeg_vbif_base + JPEG_VBIF_OUT_AXI_AOOO_EN);
msm_camera_io_w(0x0FFF0FFF,
jpeg_vbif_base + JPEG_VBIF_OUT_AXI_AOOO);
msm_camera_io_w(0x2222,
jpeg_vbif_base + JPEG_VBIF_OUT_AXI_AMEMTYPE_CONF1);
}
msm_camera_io_w(0x7,
jpeg_vbif_base + JPEG_VBIF_OCMEM_OUT_MAX_BURST);
msm_camera_io_w(0x00000030,
jpeg_vbif_base + JPEG_VBIF_ARB_CTL);
/* FE and WE QOS configuration need to be set when
* QOS RR arbitration is enabled
*/
if (pgmn_dev->hw_version != JPEG_8974_V1)
msm_camera_io_w(0x00000003,
jpeg_vbif_base + JPEG_VBIF_ROUND_ROBIN_QOS_ARB);
else
msm_camera_io_w(0x00000001,
jpeg_vbif_base + JPEG_VBIF_ROUND_ROBIN_QOS_ARB);
msm_camera_io_w(0x22222222,
jpeg_vbif_base + JPEG_VBIF_OUT_AXI_AMEMTYPE_CONF0);
}
/*
* msm_jpeg_set_init_dt_parms() - get device tree config and write to registers.
* @pgmn_dev: Pointer to jpeg device.
* @dt_prop_name: Device tree property name.
* @base: Base address.
*
* This function reads register offsets and values from dtsi based on
* device tree property name and writes to jpeg registers.
*
* Return: 0 on success and negative error on failure.
*/
static int32_t msm_jpeg_set_init_dt_parms(struct msm_jpeg_device *pgmn_dev,
const char *dt_prop_name,
void *base)
{
struct device_node *of_node;
int32_t i = 0, rc = 0;
uint32_t *dt_reg_settings = NULL;
uint32_t dt_count = 0;
of_node = pgmn_dev->pdev->dev.of_node;
JPEG_DBG("%s:%d E\n", __func__, __LINE__);
if (!of_get_property(of_node, dt_prop_name,
&dt_count)) {
JPEG_DBG("%s: Error property does not exist\n",
__func__);
return -ENOENT;
}
if (dt_count % 8) {
JPEG_PR_ERR("%s: Error invalid entries\n",
__func__);
return -EINVAL;
}
dt_count /= 4;
if (dt_count != 0) {
dt_reg_settings = kcalloc(dt_count, sizeof(uint32_t),
GFP_KERNEL);
if (!dt_reg_settings) {
JPEG_PR_ERR("%s:%d No memory\n",
__func__, __LINE__);
return -ENOMEM;
}
rc = of_property_read_u32_array(of_node,
dt_prop_name,
dt_reg_settings,
dt_count);
if (rc < 0) {
JPEG_PR_ERR("%s: No reg info\n",
__func__);
kfree(dt_reg_settings);
return -EINVAL;
}
for (i = 0; i < dt_count; i = i + 2) {
JPEG_DBG("%s:%d] %pK %08x\n",
__func__, __LINE__,
base + dt_reg_settings[i],
dt_reg_settings[i + 1]);
msm_camera_io_w(dt_reg_settings[i + 1],
base + dt_reg_settings[i]);
}
kfree(dt_reg_settings);
}
return 0;
}
static int msm_jpeg_attach_iommu(struct msm_jpeg_device *pgmn_dev)
{
int rc;
rc = cam_smmu_ops(pgmn_dev->iommu_hdl, CAM_SMMU_ATTACH);
if (rc < 0) {
JPEG_PR_ERR("%s: Device attach failed\n", __func__);
return -ENODEV;
}
JPEG_DBG("%s:%d] handle %d attach\n",
__func__, __LINE__, pgmn_dev->iommu_hdl);
return 0;
}
static int msm_jpeg_detach_iommu(struct msm_jpeg_device *pgmn_dev)
{
JPEG_DBG("%s:%d] handle %d detach\n",
__func__, __LINE__, pgmn_dev->iommu_hdl);
cam_smmu_ops(pgmn_dev->iommu_hdl, CAM_SMMU_DETACH);
return 0;
}
int msm_jpeg_platform_init(irqreturn_t (*handler)(int, void *),
void *context)
{
int rc = -1;
struct msm_jpeg_device *pgmn_dev =
(struct msm_jpeg_device *) context;
struct platform_device *pdev = pgmn_dev->pdev;
pgmn_dev->state = MSM_JPEG_IDLE;
/* enable all regulators */
rc = msm_camera_regulator_enable(pgmn_dev->jpeg_vdd,
pgmn_dev->num_reg, true);
if (rc < 0) {
JPEG_PR_ERR("%s: failed to enable regulators\n", __func__);
goto err_reg_enable;
}
/* enable all clocks */
rc = msm_camera_clk_enable(&pgmn_dev->pdev->dev,
pgmn_dev->jpeg_clk_info, pgmn_dev->jpeg_clk,
pgmn_dev->num_clk, true);
if (rc < 0) {
JPEG_PR_ERR("%s: clk enable failed\n", __func__);
goto err_clk_enable;
}
/* attach the smmu context banks */
rc = msm_jpeg_attach_iommu(pgmn_dev);
if (rc < 0) {
JPEG_PR_ERR("%s: iommu attach failed\n", __func__);
goto err_fail_iommu;
}
rc = msm_jpeg_set_init_dt_parms(pgmn_dev, "qcom,vbif-reg-settings",
pgmn_dev->vbif_base);
if (rc == -ENOENT) {
JPEG_DBG("%s: No qcom,vbif-reg-settings property\n", __func__);
set_vbif_params(pgmn_dev, pgmn_dev->vbif_base);
} else if (rc < 0) {
JPEG_PR_ERR("%s: vbif params set fail\n", __func__);
goto err_fail_set_vbif;
}
/* register the interrupt handler */
rc = msm_camera_register_irq(pgmn_dev->pdev,
pgmn_dev->jpeg_irq_res, handler, IRQF_TRIGGER_RISING,
"jpeg", context);
if (rc < 0) {
JPEG_PR_ERR("%s: irq request fail\n", __func__);
goto err_reg_irq_fail;
}
pgmn_dev->hw_version = msm_camera_io_r(pgmn_dev->base +
JPEG_HW_VERSION);
JPEG_DBG_HIGH("%s:%d] jpeg HW version 0x%x", __func__, __LINE__,
pgmn_dev->hw_version);
pgmn_dev->state = MSM_JPEG_INIT;
return 0;
err_reg_irq_fail:
err_fail_set_vbif:
msm_jpeg_detach_iommu(pgmn_dev);
err_fail_iommu:
msm_camera_clk_enable(&pdev->dev, pgmn_dev->jpeg_clk_info,
pgmn_dev->jpeg_clk, pgmn_dev->num_clk, false);
err_clk_enable:
msm_camera_regulator_enable(pgmn_dev->jpeg_vdd,
pgmn_dev->num_reg, false);
err_reg_enable:
return rc;
}
int msm_jpeg_platform_setup(struct msm_jpeg_device *pgmn_dev)
{
int rc = -1;
struct resource *jpeg_irq_res;
void *jpeg_base, *vbif_base;
struct platform_device *pdev = pgmn_dev->pdev;
/* get the jpeg hardware device address */
jpeg_base = msm_camera_get_reg_base(pdev, "jpeg_hw", true);
if (!jpeg_base) {
JPEG_PR_ERR("%s: jpeg no mem resource?\n", __func__);
rc = -ENXIO;
goto out;
}
/* get the jpeg vbif device address */
vbif_base = msm_camera_get_reg_base(pdev, "jpeg_vbif", false);
if (!vbif_base) {
JPEG_PR_ERR("%s: vbif no mem resource?\n", __func__);
rc = -ENXIO;
goto err_vbif_base;
}
/* get the irq resource for the jpeg hardware */
jpeg_irq_res = msm_camera_get_irq(pdev, "jpeg");
if (!jpeg_irq_res) {
JPEG_PR_ERR("%s: no irq resource?\n", __func__);
rc = -ENXIO;
goto err_jpeg_irq_res;
}
/* get all the clocks information */
rc = msm_camera_get_clk_info(pdev, &pgmn_dev->jpeg_clk_info,
&pgmn_dev->jpeg_clk, &pgmn_dev->num_clk);
if (rc < 0) {
JPEG_PR_ERR("%s: failed to get the clocks\n", __func__);
rc = -ENXIO;
goto err_jpeg_clk;
}
/* get all the regulators information */
rc = msm_camera_get_regulator_info(pdev, &pgmn_dev->jpeg_vdd,
&pgmn_dev->num_reg);
if (rc < 0) {
JPEG_PR_ERR("%s: failed to get the regulators\n", __func__);
rc = -ENXIO;
goto err_jpeg_get_reg;
}
/* map the dtsi cell id to bus client id */
switch (pgmn_dev->pdev->id) {
case 0:
pgmn_dev->bus_client = CAM_BUS_CLIENT_JPEG_ENC0;
break;
case 1:
pgmn_dev->bus_client = CAM_BUS_CLIENT_JPEG_ENC1;
break;
case 2:
pgmn_dev->bus_client = CAM_BUS_CLIENT_JPEG_DEC;
break;
case 3:
pgmn_dev->bus_client = CAM_BUS_CLIENT_JPEG_DMA;
break;
default:
JPEG_PR_ERR("%s: invalid cell id :%d\n",
__func__, pgmn_dev->pdev->id);
goto err_jpeg_get_reg;
}
/* register the bus client */
rc = msm_camera_register_bus_client(pgmn_dev->pdev,
pgmn_dev->bus_client);
if (rc < 0) {
JPEG_PR_ERR("Fail to register bus client\n");
rc = -EINVAL;
goto err_reg_bus;
}
/* get the resource size of jpeg hardware */
pgmn_dev->res_size = msm_camera_get_res_size(pdev, "jpeg_hw");
if (!pgmn_dev->res_size) {
JPEG_PR_ERR("Fail to resource size\n");
rc = -EINVAL;
goto err_res_size;
}
pgmn_dev->base = jpeg_base;
pgmn_dev->vbif_base = vbif_base;
pgmn_dev->jpeg_irq_res = jpeg_irq_res;
return 0;
err_res_size:
msm_camera_unregister_bus_client(pgmn_dev->bus_client);
err_reg_bus:
msm_camera_put_regulators(pdev, &pgmn_dev->jpeg_vdd,
pgmn_dev->num_reg);
err_jpeg_get_reg:
msm_camera_put_clk_info(pdev, &pgmn_dev->jpeg_clk_info,
&pgmn_dev->jpeg_clk, pgmn_dev->num_clk);
err_jpeg_clk:
err_jpeg_irq_res:
msm_camera_put_reg_base(pdev, vbif_base, "jpeg_vbif", false);
err_vbif_base:
msm_camera_put_reg_base(pdev, jpeg_base, "jpeg_hw", true);
out:
return rc;
}
void msm_jpeg_platform_cleanup(struct msm_jpeg_device *pgmn_dev)
{
/* unregister the bus client */
msm_camera_unregister_bus_client(pgmn_dev->bus_client);
/* release the regulators */
msm_camera_put_regulators(pgmn_dev->pdev, &pgmn_dev->jpeg_vdd,
pgmn_dev->num_reg);
/* release all the clocks */
msm_camera_put_clk_info(pgmn_dev->pdev, &pgmn_dev->jpeg_clk_info,
&pgmn_dev->jpeg_clk, pgmn_dev->num_clk);
/* release the jpeg device memory */
msm_camera_put_reg_base(pgmn_dev->pdev, pgmn_dev->vbif_base,
"jpeg_vbif", false);
/* release the jpeg vbif device memory */
msm_camera_put_reg_base(pgmn_dev->pdev, pgmn_dev->base,
"jpeg_hw", true);
}
int msm_jpeg_platform_release(void *context)
{
int result = 0;
struct msm_jpeg_device *pgmn_dev =
(struct msm_jpeg_device *) context;
/* release the irq */
msm_camera_unregister_irq(pgmn_dev->pdev,
pgmn_dev->jpeg_irq_res, context);
msm_jpeg_detach_iommu(pgmn_dev);
if (pgmn_dev->bus_client) {
if (pgmn_dev->jpeg_bus_vote) {
/* update the bw with zeroth vector */
msm_camera_update_bus_vector(pgmn_dev->bus_client, 0);
JPEG_BUS_UNVOTED(pgmn_dev);
JPEG_DBG("%s:%d] Bus unvoted\n", __func__, __LINE__);
}
}
/* disable all the clocks */
msm_camera_clk_enable(&pgmn_dev->pdev->dev, pgmn_dev->jpeg_clk_info,
pgmn_dev->jpeg_clk, pgmn_dev->num_clk, false);
JPEG_DBG("%s:%d] clock disbale done", __func__, __LINE__);
/* disable all the regulators */
msm_camera_regulator_enable(pgmn_dev->jpeg_vdd,
pgmn_dev->num_reg, false);
JPEG_DBG("%s:%d] regulator disable done", __func__, __LINE__);
pgmn_dev->state = MSM_JPEG_IDLE;
JPEG_DBG("%s:%d] success\n", __func__, __LINE__);
return result;
}
/*
* msm_jpeg_platform_set_dt_config() - set jpeg device tree configuration.
* @pgmn_dev: Pointer to jpeg device.
*
* This function holds an array of device tree property names and calls
* msm_jpeg_set_init_dt_parms() for each property.
*
* Return: 0 on success and negative error on failure.
*/
int msm_jpeg_platform_set_dt_config(struct msm_jpeg_device *pgmn_dev)
{
int rc = 0;
uint8_t dt_prop_cnt = JPEG_DT_PROP_CNT;
char *dt_prop_name[JPEG_DT_PROP_CNT] = {"qcom,qos-reg-settings",
"qcom,prefetch-reg-settings"};
while (dt_prop_cnt) {
dt_prop_cnt--;
rc = msm_jpeg_set_init_dt_parms(pgmn_dev,
dt_prop_name[dt_prop_cnt],
pgmn_dev->base);
if (rc == -ENOENT) {
JPEG_DBG("%s: No %s property\n", __func__,
dt_prop_name[dt_prop_cnt]);
} else if (rc < 0) {
JPEG_PR_ERR("%s: %s params set fail\n", __func__,
dt_prop_name[dt_prop_cnt]);
return rc;
}
}
return rc;
}

View file

@ -0,0 +1,38 @@
/* Copyright (c) 2012-2017, 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_JPEG_PLATFORM_H
#define MSM_JPEG_PLATFORM_H
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/ion.h>
#include "msm_jpeg_sync.h"
#define JPEG_CLK_RATE 266670000
int msm_jpeg_platform_set_clk_rate(struct msm_jpeg_device *pgmn_dev,
long clk_rate);
void msm_jpeg_platform_p2v(int iommu_hdl, int fd);
uint32_t msm_jpeg_platform_v2p(struct msm_jpeg_device *pgmn_dev, int fd,
uint32_t len, int iommu_hdl);
int msm_jpeg_platform_clk_enable(void);
int msm_jpeg_platform_clk_disable(void);
int msm_jpeg_platform_init(irqreturn_t (*handler)(int, void *),
void *context);
int msm_jpeg_platform_release(void *context);
int msm_jpeg_platform_set_dt_config(struct msm_jpeg_device *pgmn_dev);
int msm_jpeg_platform_setup(struct msm_jpeg_device *pgmn_dev);
void msm_jpeg_platform_cleanup(struct msm_jpeg_device *pgmn_dev);
#endif /* MSM_JPEG_PLATFORM_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,139 @@
/* Copyright (c) 2012-2017, 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_JPEG_SYNC_H
#define MSM_JPEG_SYNC_H
#include <linux/fs.h>
#include <linux/list.h>
#include <linux/cdev.h>
#include <linux/platform_device.h>
#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
#include "msm_camera_io_util.h"
#include "msm_jpeg_hw.h"
#include "cam_smmu_api.h"
#include "cam_soc_api.h"
#define JPEG_8974_V1 0x10000000
#define JPEG_8974_V2 0x10010000
#define JPEG_8994 0x10020000
#define JPEG_CLK_MAX 16
#define JPEG_REGULATOR_MAX 3
enum msm_jpeg_state {
MSM_JPEG_INIT,
MSM_JPEG_RESET,
MSM_JPEG_EXECUTING,
MSM_JPEG_STOPPED,
MSM_JPEG_IDLE
};
enum msm_jpeg_core_type {
MSM_JPEG_CORE_CODEC,
MSM_JPEG_CORE_DMA
};
struct msm_jpeg_q {
char const *name;
struct list_head q;
spinlock_t lck;
wait_queue_head_t wait;
int unblck;
};
struct msm_jpeg_q_entry {
struct list_head list;
void *data;
};
struct msm_jpeg_device {
struct platform_device *pdev;
struct resource *jpeg_irq_res;
void *base;
void *vbif_base;
struct clk **jpeg_clk;
struct msm_cam_clk_info *jpeg_clk_info;
size_t num_clk;
int num_reg;
struct msm_cam_regulator *jpeg_vdd;
uint32_t hw_version;
struct device *device;
struct cdev cdev;
struct mutex lock;
char open_count;
uint8_t op_mode;
/* Flag to store the jpeg bus vote state
*/
int jpeg_bus_vote;
/* event queue including frame done & err indications
*/
struct msm_jpeg_q evt_q;
/* output return queue
*/
struct msm_jpeg_q output_rtn_q;
/* output buf queue
*/
struct msm_jpeg_q output_buf_q;
/* input return queue
*/
struct msm_jpeg_q input_rtn_q;
/* input buf queue
*/
struct msm_jpeg_q input_buf_q;
struct v4l2_subdev subdev;
struct class *msm_jpeg_class;
dev_t msm_jpeg_devno;
/* iommu domain and context */
int idx;
int iommu_hdl;
int decode_flag;
void *jpeg_vbif;
int release_buf;
struct msm_jpeg_hw_pingpong fe_pingpong_buf;
struct msm_jpeg_hw_pingpong we_pingpong_buf;
int we_pingpong_index;
int reset_done_ack;
spinlock_t reset_lock;
wait_queue_head_t reset_wait;
uint32_t res_size;
enum msm_jpeg_state state;
enum msm_jpeg_core_type core_type;
enum cam_bus_client bus_client;
};
int __msm_jpeg_open(struct msm_jpeg_device *pgmn_dev);
int __msm_jpeg_release(struct msm_jpeg_device *pgmn_dev);
long __msm_jpeg_ioctl(struct msm_jpeg_device *pgmn_dev,
unsigned int cmd, unsigned long arg);
#ifdef CONFIG_COMPAT
long __msm_jpeg_compat_ioctl(struct msm_jpeg_device *pgmn_dev,
unsigned int cmd, unsigned long arg);
#endif
int __msm_jpeg_init(struct msm_jpeg_device *pgmn_dev);
int __msm_jpeg_exit(struct msm_jpeg_device *pgmn_dev);
#endif /* MSM_JPEG_SYNC_H */

View file

@ -0,0 +1,4 @@
GCC_VERSION := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc)
ccflags-y += -Idrivers/media/video/msm
ccflags-y += -Idrivers/media/platform/msm/ais/common
obj-$(CONFIG_MSM_AIS_JPEGDMA) += msm_jpeg_dma_dev.o msm_jpeg_dma_hw.o

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,374 @@
/* Copyright (c) 2015-2017, 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_JPEG_DMA_DEV_H__
#define __MSM_JPEG_DMA_DEV_H__
#include <media/v4l2-device.h>
#include <media/v4l2-fh.h>
#include <media/v4l2-ctrls.h>
#include <linux/msm-bus.h>
#include "cam_soc_api.h"
/* Max number of clocks defined in device tree */
#define MSM_JPEGDMA_MAX_CLK 10
/* Core clock index */
#define MSM_JPEGDMA_CORE_CLK 0
/* Max number of regulators defined in device tree */
#define MSM_JPEGDMA_MAX_REGULATOR_NUM 3
/* Max number of planes supported */
#define MSM_JPEGDMA_MAX_PLANES 3
/* Max number of hw pipes supported */
#define MSM_JPEGDMA_MAX_PIPES 2
/* Max number of hw configurations supported */
#define MSM_JPEGDMA_MAX_CONFIGS 2
/* Dma default fps */
#define MSM_JPEGDMA_DEFAULT_FPS 30
/* Dma input output size limitations */
#define MSM_JPEGDMA_MAX_WIDTH 65536
#define MSM_JPEGDMA_MIN_WIDTH 32
#define MSM_JPEGDMA_MAX_HEIGHT 65536
#define MSM_JPEGDMA_MIN_HEIGHT 32
#define MSM_JPEGDMA_STRIDE_ALIGN 8
/*
* enum msm_jpegdma_plane_type - Dma format.
* @JPEGDMA_PLANE_TYPE_Y: Y plane type.
* @JPEGDMA_PLANE_TYPE_CR: Chroma CB plane.
* @JPEGDMA_PLANE_TYPE_CB: Chroma CR plane.
* @JPEGDMA_PLANE_TYPE_CBCR: Interlevaed CbCr plane.
*/
enum msm_jpegdma_plane_type {
JPEGDMA_PLANE_TYPE_Y,
JPEGDMA_PLANE_TYPE_CR,
JPEGDMA_PLANE_TYPE_CB,
JPEGDMA_PLANE_TYPE_CBCR,
};
/*
* struct msm_jpegdma_format - Dma format.
* @name: Format name.
* @fourcc: v4l2 fourcc code.
* @depth: Number of bits per pixel.
* @num_planes: number of planes.
* @colplane_h: Color plane horizontal subsample.
* @colplane_v: Color plane vertical subsample.
* @h_align: Horizontal align.
* @v_align: Vertical align.
* @planes: Array with plane types.
*/
struct msm_jpegdma_format {
char *name;
u32 fourcc;
int depth;
int num_planes;
int colplane_h;
int colplane_v;
int h_align;
int v_align;
enum msm_jpegdma_plane_type planes[MSM_JPEGDMA_MAX_PLANES];
};
/*
* struct msm_jpegdma_size - Dma size.
* @top: Top position.
* @left: Left position
* @width: Width
* @height: height.
* @scanline: Number of lines per plane.
* @stride: Stride bytes per line.
*/
struct msm_jpegdma_size {
unsigned int top;
unsigned int left;
unsigned int width;
unsigned int height;
unsigned int scanline;
unsigned int stride;
};
/*
* struct msm_jpegdma_size_config - Dma engine size configuration.
* @in_size: Input size.
* @out_size: Output size.
* @format: Format.
* @fps: Requested frames per second.
*/
struct msm_jpegdma_size_config {
struct msm_jpegdma_size in_size;
struct msm_jpegdma_size out_size;
struct msm_jpegdma_format format;
unsigned int fps;
};
/*
* struct msm_jpegdma_block - Dma hw block.
* @div: Block divider.
* @width: Block width.
* @reg_val: Block register value.
*/
struct msm_jpegdma_block {
unsigned int div;
unsigned int width;
unsigned int reg_val;
};
/*
* struct msm_jpegdma_block_config - Dma hw block configuration.
* @block: Block settings.
* @blocks_per_row: Blocks per row.
* @blocks_per_col: Blocks per column.
* @h_step: Horizontal step value
* @v_step: Vertical step value
* @h_step_last: Last horizontal step.
* @v_step_last: Last vertical step.
*/
struct msm_jpegdma_block_config {
struct msm_jpegdma_block block;
unsigned int blocks_per_row;
unsigned int blocks_per_col;
unsigned int h_step;
unsigned int v_step;
unsigned int h_step_last;
unsigned int v_step_last;
};
/*
* msm_jpegdma_scale - Dma hw scale configuration.
* @enable: Scale enable.
* @hor_scale: Horizontal scale factor in Q21 format.
* @ver_scale: Vertical scale factor in Q21 format.
*/
struct msm_jpegdma_scale {
int enable;
unsigned int hor_scale;
unsigned int ver_scale;
};
/*
* struct msm_jpegdma_config - Dma hw configuration.
* @size_cfg: Size configuration.
* @scale_cfg: Scale configuration
* @block_cfg: Block configuration.
* @phase: Starting phase.
* @in_offset: Input offset.
* @out_offset: Output offset.
*/
struct msm_jpegdma_config {
struct msm_jpegdma_size_config size_cfg;
struct msm_jpegdma_scale scale_cfg;
struct msm_jpegdma_block_config block_cfg;
unsigned int phase;
unsigned int in_offset;
unsigned int out_offset;
};
/*
* struct msm_jpegdma_plane_config - Contain input output address.
* @bus_ab: Bus average bandwidth.
* @bus_ib: Bus instantaneous bandwidth.
* @core_clock: Core clock freq.
*/
struct msm_jpegdma_speed {
u64 bus_ab;
u64 bus_ib;
u64 core_clock;
};
/*
* struct msm_jpegdma_plane_config - Contain input output address.
* @active_pipes: Number of active pipes.
* @config: Plane configurations.
* @type: Plane type.
*/
struct msm_jpegdma_plane {
unsigned int active_pipes;
struct msm_jpegdma_config config[MSM_JPEGDMA_MAX_PIPES];
enum msm_jpegdma_plane_type type;
};
/*
* struct msm_jpegdma_plane_config - Contain input output address.
* @num_planes: Number of planes.
* @plane: Plane configuration.
* @speed: Processing speed.
*/
struct msm_jpegdma_plane_config {
unsigned int num_planes;
struct msm_jpegdma_plane plane[MSM_JPEGDMA_MAX_PLANES];
struct msm_jpegdma_speed speed;
};
/*
* struct msm_jpegdma_addr - Contain input output address.
* @in_addr: Input dma address.
* @out_addr: Output dma address.
*/
struct msm_jpegdma_addr {
u32 in_addr;
u32 out_addr;
};
/*
* struct msm_jpegdma_buf_handle - Structure contain dma buffer information.
* @fd: ion dma from which this buffer is imported.
* @dma: Pointer to jpeg dma device.
* @size: Size of the buffer.
* @addr: Adders of dma mmu mapped buffer. This address should be set to dma hw.
*/
struct msm_jpegdma_buf_handle {
int fd;
struct msm_jpegdma_device *dma;
unsigned long size;
ion_phys_addr_t addr;
};
/*
* @jpegdma_ctx - Structure contains per open file handle context.
* @lock: Lock protecting dma ctx.
* @jdma_device: Pointer to dma device.
* @active: Set if context is active.
* @completion: Context processing completion.
* @fh: V4l2 file handle.
* @m2m_ctx: Memory to memory context.
* @format_cap: Current capture format.
* @format_out: Current output format.
* @crop: Current crop.
* @timeperframe: Time per frame in seconds.
* @config_idx: Plane configuration active index.
* @plane_config: Array of plane configurations.
* @pending_config: Flag set if there is pending plane configuration.
* @plane_idx: Processing plane index.
* @format_idx: Current format index.
*/
struct jpegdma_ctx {
struct mutex lock;
struct msm_jpegdma_device *jdma_device;
atomic_t active;
struct completion completion;
struct v4l2_fh fh;
struct v4l2_m2m_ctx *m2m_ctx;
struct v4l2_format format_cap;
struct v4l2_format format_out;
struct v4l2_rect crop;
struct v4l2_fract timeperframe;
unsigned int config_idx;
struct msm_jpegdma_plane_config plane_config[MSM_JPEGDMA_MAX_CONFIGS];
unsigned int pending_config;
unsigned int plane_idx;
unsigned int format_idx;
};
/*
* struct jpegdma_reg_cfg - Registry values configuration
* @reg: Register offset.
* @val: Register value.
*/
struct jpegdma_reg_cfg {
unsigned int reg;
unsigned int val;
};
/*
* enum msm_jpegdma_mem_resources - jpegdma device iomem resources.
* @MSM_JPEGDMA_IOMEM_CORE: Index of jpegdma core registers.
* @MSM_JPEGDMA_IOMEM_VBIF: Index of jpegdma vbif registers.
* @MSM_JPEGDMA_IOMEM_LAST: Not valid.
*/
enum msm_jpegdma_mem_resources {
MSM_JPEGDMA_IOMEM_CORE,
MSM_JPEGDMA_IOMEM_VBIF,
MSM_JPEGDMA_IOMEM_LAST
};
/*
* struct msm_jpegdma_device - FD device structure.
* @lock: Lock protecting dma device.
* @ref_count: Device reference count.
* @irq_num: Face detection irq number.
* @res_mem: Array of memory resources used by Dma device.
* @iomem_base: Array of register mappings used by Dma device.
* @ioarea: Array of register ioarea used by Dma device.
* @vdd: Pointer to vdd regulator.
* @regulator_num: Number of regulators attached to the device.
* @clk_num: Number of clocks attached to the device.
* @clk: Array of clock resources used by dma device.
* @clk_rates: Array of clock rates.
* @vbif_regs_num: number of vbif regs.
* @vbif_regs: Array of vbif regs need to be set.
* @qos_regs_num: Number of qos regs .
* @qos_regs: Array of qos regs need to be set.
* @bus_client: Memory access bus client.
* @bus_vectors: Bus vector
* @bus_paths: Bus path.
* @bus_scale_data: Memory access bus scale data.
* @iommu_hndl: Dma device iommu handle.
* @iommu_attached_cnt: Iommu attached devices reference count.
* @iommu_dev: Pointer to Ion iommu device.
* @dev: Pointer to device struct.
* @v4l2_dev: V4l2 device.
* @video: Video device.
* @m2m_dev: Memory to memory device.
* @hw_num_pipes: Number of dma hw pipes.
* @active_clock_rate: Active clock rate index.
* @hw_reset_completion: Dma reset completion.
* @hw_halt_completion: Dma halt completion.
*/
struct msm_jpegdma_device {
struct mutex lock;
int ref_count;
int irq_num;
void __iomem *iomem_base[MSM_JPEGDMA_IOMEM_LAST];
struct resource *irq;
struct msm_cam_regulator *dma_vdd;
int num_reg;
struct clk **clk;
size_t num_clk;
struct msm_cam_clk_info *jpeg_clk_info;
unsigned int vbif_regs_num;
struct jpegdma_reg_cfg *vbif_regs;
unsigned int qos_regs_num;
struct jpegdma_reg_cfg *qos_regs;
unsigned int prefetch_regs_num;
struct jpegdma_reg_cfg *prefetch_regs;
enum cam_bus_client bus_client;
struct msm_bus_vectors bus_vectors;
struct msm_bus_paths bus_paths;
struct msm_bus_scale_pdata bus_scale_data;
int iommu_hndl;
unsigned int iommu_attached_cnt;
struct device *iommu_dev;
struct device *dev;
struct v4l2_device v4l2_dev;
struct video_device video;
struct v4l2_m2m_dev *m2m_dev;
int hw_num_pipes;
struct completion hw_reset_completion;
struct completion hw_halt_completion;
u64 active_clock_rate;
struct platform_device *pdev;
};
void msm_jpegdma_isr_processing_done(struct msm_jpegdma_device *dma);
#endif /* __MSM_JPEG_DMA_DEV_H__ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,78 @@
/* Copyright (c) 2015-2017, 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_JPEG_DMA_HW_H__
#define __MSM_JPEG_DMA_HW_H__
#include "msm_jpeg_dma_dev.h"
int msm_jpegdma_hw_check_config(struct msm_jpegdma_device *dma,
struct msm_jpegdma_size_config *size_cfg);
int msm_jpegdma_hw_set_config(struct msm_jpegdma_device *dma,
struct msm_jpegdma_size_config *size_cfg,
struct msm_jpegdma_plane_config *plane_cfg);
int msm_jpegdma_hw_start(struct msm_jpegdma_device *dma,
struct msm_jpegdma_addr *addr,
struct msm_jpegdma_plane *plane,
struct msm_jpegdma_speed *speed);
int msm_jpegdma_hw_abort(struct msm_jpegdma_device *dma);
int msm_jpegdma_hw_update_bus_data(struct msm_jpegdma_device *dma,
u64 ab, u64 ib);
int msm_jpegdma_hw_handle_irq(struct msm_jpegdma_device *dma);
int msm_jpegdma_hw_request_irq(struct platform_device *pdev,
struct msm_jpegdma_device *dma);
void msm_jpegdma_hw_release_irq(struct msm_jpegdma_device *dma);
void msm_jpegdma_hw_release_mem_resources(struct msm_jpegdma_device *dma);
int msm_jpegdma_hw_get_mem_resources(struct platform_device *pdev,
struct msm_jpegdma_device *dma);
int msm_jpegdma_hw_get_regulators(struct msm_jpegdma_device *dma);
void msm_jpegdma_hw_put_regulators(struct msm_jpegdma_device *dma);
int msm_jpegdma_hw_get_clocks(struct msm_jpegdma_device *dma);
int msm_jpegdma_hw_put_clocks(struct msm_jpegdma_device *dma);
int msm_jpegdma_hw_get_qos(struct msm_jpegdma_device *dma);
void msm_jpegdma_hw_put_qos(struct msm_jpegdma_device *dma);
int msm_jpegdma_hw_get_vbif(struct msm_jpegdma_device *dma);
void msm_jpegdma_hw_put_vbif(struct msm_jpegdma_device *dma);
int msm_jpegdma_hw_get_prefetch(struct msm_jpegdma_device *dma);
void msm_jpegdma_hw_put_prefetch(struct msm_jpegdma_device *dma);
int msm_jpegdma_hw_get_capabilities(struct msm_jpegdma_device *dma);
int msm_jpegdma_hw_get(struct msm_jpegdma_device *dma);
void msm_jpegdma_hw_put(struct msm_jpegdma_device *dma);
int msm_jpegdma_hw_map_buffer(struct msm_jpegdma_device *dma, int fd,
struct msm_jpegdma_buf_handle *buf);
void msm_jpegdma_hw_unmap_buffer(struct msm_jpegdma_buf_handle *buf);
#endif /* __MSM_JPEG_DMA_HW_H__ */

View file

@ -0,0 +1,122 @@
/* Copyright (c) 2015-2017, 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_JPEGDMA_REGS_H__
#define __MSM_JPEGDMA_REGS_H__
#define MSM_JPEGDMA_HW_REVISION 0x00
#define MSM_JPEGDMA_HW_CAPABILITY 0x04
#define MSM_JPEGDMA_HW_CAPABILITY_NUM_PIPES_BMSK 0x06
#define MSM_JPEGDMA_HW_CAPABILITY_NUM_PIPES_SHFT 0x01
#define MSM_JPEGDMA_IRQ_MASK_ADDR 0x0C
#define MSM_JPEGDMA_IRQ_MASK_SESSION_DONE (1 << 0)
#define MSM_JPEGDMA_IRQ_MASK_RD_BUF_DONE (1 << 1)
#define MSM_JPEGDMA_IRQ_MASK_WR_BUF_DONE (1 << 5)
#define MSM_JPEGDMA_IRQ_MASK_AXI_HALT (1 << 9)
#define MSM_JPEGDMA_IRQ_MASK_RST_DONE (1 << 10)
#define MSM_JPEGDMA_IRQ_STATUS 0x10
#define MSM_JPEGDMA_IRQ_STATUS_SESSION_DONE (1 << 0)
#define MSM_JPEGDMA_IRQ_STATUS_RD_BUF_DONE (1 << 1)
#define MSM_JPEGDMA_IRQ_STATUS_WR_BUF_DONE (1 << 5)
#define MSM_JPEGDMA_IRQ_STATUS_AXI_HALT (1 << 9)
#define MSM_JPEGDMA_IRQ_STATUS_RST_DONE (1 << 10)
#define MSM_JPEGDMA_IRQ_CLEAR_ADDR 0x14
#define MSM_JPEGDMA_IRQ_CLEAR_BMSK 0xFFFFFFFF
#define MSM_JPEGDMA_CORE_CFG_ADDR 0x18
#define MSM_JPEGDMA_CMD_ADDR 0x1C
#define MSM_JPEGDMA_CORE_CFG_TEST_BUS_ENABLE_SHFT 19
#define MSM_JPEGDMA_CORE_CFG_BRIDGE_ENABLE_SHFT 6
#define MSM_JPEGDMA_CORE_CFG_SCALE_1_ENABLE_SHFT 5
#define MSM_JPEGDMA_CORE_CFG_SCALE_0_ENABLE_SHFT 4
#define MSM_JPEGDMA_CORE_CFG_WE_1_ENABLE_SHFT 0x03
#define MSM_JPEGDMA_CORE_CFG_WE_0_ENABLE_SHFT 0x02
#define MSM_JPEGDMA_CORE_CFG_FE_1_ENABLE_SHFT 0x01
#define MSM_JPEGDMA_CORE_CFG_FE_0_ENABLE_SHFT 0x00
#define MSM_JPEGDMA_FE_0_CFG_ADDR 0x2C
#define MSM_JPEGDMA_FE_1_CFG_ADDR 0x70
#define MSM_JPEGDMA_FE_CFG_MAL_BOUNDARY_SHFT 25
#define MSM_JPEGDMA_FE_CFG_MAL_EN_SHFT 21
#define MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_CBCR 0x03
#define MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_CR 0x02
#define MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_CB 0x01
#define MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_Y 0x00
#define MSM_JPEGDMA_FE_CFG_PLN_BLOCK_TYPE_SHFT 19
#define MSM_JPEGDMA_FE_CFG_BLOCK_WIDTH_SHFT 0x04
#define MSM_JPEGDMA_FE_CFG_BURST_LENGTH_MAX_SHFT 0x00
#define MSM_JPEGDMA_FE_RD_0_PNTR_ADDR 0x34
#define MSM_JPEGDMA_FE_RD_1_PNTR_ADDR 0x78
#define MSM_JPEGDMA_FE_RD_BUFFER_SIZE_0_ADDR 0x44
#define MSM_JPEGDMA_FE_RD_BUFFER_SIZE_1_ADDR 0x88
#define MSM_JPEGDMA_FE_RD_BUFFER_SIZE_HEIGHT_SHFT 16
#define MSM_JPEGDMA_FE_RD_0_STRIDE_ADDR 0x48
#define MSM_JPEGDMA_FE_RD_1_STRIDE_ADDR 0x8C
#define MSM_JPEGDMA_FE_RD_0_HINIT_ADDR 0x4C
#define MSM_JPEGDMA_FE_RD_1_HINIT_ADDR 0x90
#define MSM_JPEGDMA_FE_RD_0_HINIT_INT_ADDR 0x50
#define MSM_JPEGDMA_FE_RD_1_HINIT_INT_ADDR 0x94
#define MSM_JPEGDMA_FE_RD_0_VINIT_INT_ADDR 0x58
#define MSM_JPEGDMA_FE_RD_1_VINIT_INT_ADDR 0x9C
#define MSM_JPEGDMA_WE_CFG_ADDR 0xB8
#define MSM_JPEGDMA_WE_CFG_MAL_BOUNDARY_SHFT 0x08
#define MSM_JPEGDMA_WE_CFG_MAL_EN_SHFT 0x07
#define MSM_JPEGDMA_WE_CFG_BURST_LENGTH_MAX_SHFT 0x00
#define MSM_JPEGDMA_WE_PLN_0_WR_PNTR_ADDR 0xBC
#define MSM_JPEGDMA_WE_PLN_1_WR_PNTR_ADDR 0xEC
#define MSM_JPEGDMA_WE_PLN_WR_BUFFER_SIZE_0_ADDR 0xC4
#define MSM_JPEGDMA_WE_PLN_WR_BUFFER_SIZE_1_ADDR 0xF4
#define MSM_JPEGDMA_WE_PLN_WR_BUFFER_SIZE_HEIGHT_SHFT 16
#define MSM_JPEGDMA_WE_PLN_0_WR_STRIDE_ADDR 0xC8
#define MSM_JPEGDMA_WE_PLN_1_WR_STRIDE_ADDR 0xF8
#define MSM_JPEGDMA_WE_PLN_0_WR_CFG_0_ADDR 0xCC
#define MSM_JPEGDMA_WE_PLN_1_WR_CFG_0_ADDR 0xFC
#define MSM_JPEGDMA_WE_PLN_WR_CFG_0_BLOCKS_PER_ROW_SHFT 16
#define MSM_JPEGDMA_WE_PLN_0_WR_CFG_1_ADDR 0xD0
#define MSM_JPEGDMA_WE_PLN_1_WR_CFG_1_ADDR 0x100
#define MSM_JPEGDMA_WE_PLN_WR_CFG_1_LAST_H_STEP_SHFT 16
#define MSM_JPEGDMA_WE_PLN_0_WR_CFG_2_ADDR 0xD4
#define MSM_JPEGDMA_WE_PLN_1_WR_CFG_2_ADDR 0x104
#define MSM_JPEGDMA_WE_PLN_WR_CFG_2_LAST_V_STEP_SHFT 16
#define MSM_JPEGDMA_WE_PLN_0_WR_CFG_3_ADDR 0xD8
#define MSM_JPEGDMA_WE_PLN_1_WR_CFG_3_ADDR 0x108
#define MSM_JPEGDMA_PP_0_SCALE_PHASEV_STEP_ADDR 0x19C
#define MSM_JPEGDMA_PP_1_SCALE_PHASEV_STEP_ADDR 0x1BC
#define MSM_JPEGDMA_PP_0_SCALE_PHASEH_STEP_ADDR 0x194
#define MSM_JPEGDMA_PP_1_SCALE_PHASEH_STEP_ADDR 0x1B4
#define MSM_JPEGDMA_PP_0_SCALE_CFG_ADDR 0x188
#define MSM_JPEGDMA_PP_1_SCALE_CFG_ADDR 0x1A8
#define MSM_JPEGDMA_PP_SCALE_CFG_VSCALE_ENABLE_SHFT 0x05
#define MSM_JPEGDMA_PP_SCALE_CFG_HSCALE_ENABLE_SHFT 0x04
#define MSM_JPEGDMA_S0_MMU_PF_ADDR_MIN 0x190
#define MSM_JPEGDMA_S0_MMU_PF_ADDR_MAX 0x198
#define MSM_JPEGDMA_S1_MMU_PF_ADDR_MIN 0x1A4
#define MSM_JPEGDMA_S1_MMU_PF_ADDR_MAX 0x1AC
#define MSM_JPEGDMA_CMD_CLEAR_READ_PLN_QUEUES 0x030
#define MSM_JPEGDMA_CMD_CLEAR_WRITE_PLN_QUEUES 0x300
#define MSM_HW_JPEGDMA_RESET 0x08
#define MSM_HW_JPEGDMA_RESET_DEFAULT 0x32083
#define MSM_JPEGDMA_RESET_CMD_BMSK 0xFFFFFFFF
#endif /* __MSM_JPEG_DMA_REGS_H__ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,145 @@
/* Copyright (c) 2012-2017, 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_H
#define _MSM_H
#include <linux/version.h>
#include <linux/completion.h>
#include <linux/i2c.h>
#include <linux/videodev2.h>
#include <linux/pm_qos.h>
#include <linux/msm_ion.h>
#include <linux/iommu.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-device.h>
#include <media/v4l2-fh.h>
#include <media/v4l2-event.h>
#include <media/v4l2-mediabus.h>
#include <media/videobuf2-dma-contig.h>
#include <media/ais/msm_ais.h>
/* Setting MAX timeout to 6.5seconds considering
* backend will operate @ .6fps in certain usecases
* like Long exposure usecase and isp needs max of 2 frames
* to stop the hardware which will be around 3 seconds
*/
#define MSM_POST_EVT_TIMEOUT 6500
#define MSM_POST_EVT_NOTIMEOUT 0xFFFFFFFF
#define MSM_CAMERA_STREAM_CNT_BITS 32
#define CAMERA_DISABLE_PC_LATENCY 100
#define CAMERA_ENABLE_PC_LATENCY PM_QOS_DEFAULT_VALUE
extern bool is_daemon_status;
struct msm_video_device {
struct video_device *vdev;
atomic_t opened;
};
struct msm_queue_head {
struct list_head list;
spinlock_t lock;
int len;
int max;
};
/** msm_event:
*
* event sent by imaging server
**/
struct msm_event {
struct video_device *vdev;
atomic_t on_heap;
};
struct msm_command {
struct list_head list;
struct v4l2_event event;
atomic_t on_heap;
};
/** struct msm_command_ack
*
* Object of command_ack_q, which is
* created per open operation
*
* contains struct msm_command
**/
struct msm_command_ack {
struct list_head list;
struct msm_queue_head command_q;
struct completion wait_complete;
int stream_id;
};
struct msm_v4l2_subdev {
/* FIXME: for session close and error handling such
* as daemon shutdown
*/
int close_sequence;
};
struct msm_session {
struct list_head list;
/* session index */
unsigned int session_id;
/* event queue sent by imaging server */
struct msm_event event_q;
/* ACK by imaging server. Object type of
* struct msm_command_ack per open,
* assumption is application can send
* command on every opened video node
*/
struct msm_queue_head command_ack_q;
/* real streams(either data or metadate) owned by one
* session struct msm_stream
*/
struct msm_queue_head stream_q;
struct mutex lock;
struct mutex lock_q;
struct mutex close_lock;
};
static inline bool msm_is_daemon_present(void)
{
return is_daemon_status;
}
void msm_pm_qos_update_request(int val);
int msm_post_event(struct v4l2_event *event, int timeout);
int msm_create_session(unsigned int session, struct video_device *vdev);
int msm_destroy_session(unsigned int session_id);
int msm_create_stream(unsigned int session_id,
unsigned int stream_id, struct vb2_queue *q);
void msm_delete_stream(unsigned int session_id, unsigned int stream_id);
int msm_create_command_ack_q(unsigned int session_id, unsigned int stream_id);
void msm_delete_command_ack_q(unsigned int session_id, unsigned int stream_id);
struct msm_stream *msm_get_stream(unsigned int session_id,
unsigned int stream_id);
struct vb2_queue *msm_get_stream_vb2q(unsigned int session_id,
unsigned int stream_id);
struct msm_stream *msm_get_stream_from_vb2q(struct vb2_queue *q);
struct msm_session *msm_session_find(unsigned int session_id);
#ifdef CONFIG_COMPAT
long msm_copy_camera_private_ioctl_args(unsigned long arg,
struct msm_camera_private_ioctl_arg *k_ioctl,
void __user **tmp_compat_ioctl_ptr);
#endif
#endif /*_MSM_H */

View file

@ -0,0 +1,2 @@
ccflags-y += -Idrivers/media/platform/msm/ais
obj-$(CONFIG_MSM_AIS) += msm_generic_buf_mgr.o

View file

@ -0,0 +1,896 @@
/* Copyright (c) 2013-2017, 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.
*/
#define pr_fmt(fmt) "CAM-BUFMGR %s:%d " fmt, __func__, __LINE__
#include "msm_generic_buf_mgr.h"
static struct msm_buf_mngr_device *msm_buf_mngr_dev;
struct v4l2_subdev *msm_buf_mngr_get_subdev(void)
{
return &msm_buf_mngr_dev->subdev.sd;
}
static int32_t msm_buf_mngr_hdl_cont_get_buf(struct msm_buf_mngr_device *dev,
struct msm_buf_mngr_info *buf_info)
{
unsigned int i;
struct msm_buf_mngr_user_buf_cont_info *cbuf, *cont_save;
list_for_each_entry_safe(cbuf, cont_save, &dev->cont_qhead, entry) {
if ((cbuf->sessid == buf_info->session_id) &&
(cbuf->index == buf_info->index) &&
(cbuf->strid == buf_info->stream_id)) {
buf_info->user_buf.buf_cnt = cbuf->paddr->buf_cnt;
if (buf_info->user_buf.buf_cnt >
MSM_CAMERA_MAX_USER_BUFF_CNT) {
pr_err("Invalid cnt%d,%d,%d\n",
cbuf->paddr->buf_cnt,
buf_info->session_id,
buf_info->stream_id);
return -EINVAL;
}
for (i = 0 ; i < buf_info->user_buf.buf_cnt; i++) {
buf_info->user_buf.buf_idx[i] =
cbuf->paddr->buf_idx[i];
}
break;
}
}
return 0;
}
static int32_t msm_buf_mngr_get_buf(struct msm_buf_mngr_device *dev,
void __user *argp)
{
unsigned long flags;
int32_t rc = 0;
struct msm_buf_mngr_info *buf_info =
(struct msm_buf_mngr_info *)argp;
struct msm_get_bufs *new_entry =
kzalloc(sizeof(struct msm_get_bufs), GFP_KERNEL);
if (!new_entry) {
pr_err("%s:No mem\n", __func__);
return -ENOMEM;
}
INIT_LIST_HEAD(&new_entry->entry);
new_entry->vb2_v4l2_buf = dev->vb2_ops.get_buf(buf_info->session_id,
buf_info->stream_id);
if (!new_entry->vb2_v4l2_buf) {
pr_debug("%s:Get buf is null\n", __func__);
kfree(new_entry);
return -EINVAL;
}
new_entry->session_id = buf_info->session_id;
new_entry->stream_id = buf_info->stream_id;
new_entry->index = new_entry->vb2_v4l2_buf->vb2_buf.index;
spin_lock_irqsave(&dev->buf_q_spinlock, flags);
list_add_tail(&new_entry->entry, &dev->buf_qhead);
spin_unlock_irqrestore(&dev->buf_q_spinlock, flags);
buf_info->index = new_entry->vb2_v4l2_buf->vb2_buf.index;
if (buf_info->type == MSM_CAMERA_BUF_MNGR_BUF_USER) {
mutex_lock(&dev->cont_mutex);
if (!list_empty(&dev->cont_qhead)) {
rc = msm_buf_mngr_hdl_cont_get_buf(dev, buf_info);
} else {
pr_err("Nothing mapped in user buf for %d,%d\n",
buf_info->session_id, buf_info->stream_id);
rc = -EINVAL;
}
mutex_unlock(&dev->cont_mutex);
}
return rc;
}
static int32_t msm_buf_mngr_get_buf_by_idx(struct msm_buf_mngr_device *dev,
void *argp)
{
unsigned long flags;
int32_t rc = 0;
struct msm_buf_mngr_info *buf_info =
(struct msm_buf_mngr_info *)argp;
struct msm_get_bufs *new_entry =
kzalloc(sizeof(struct msm_get_bufs), GFP_KERNEL);
if (!new_entry) {
pr_err("%s:No mem\n", __func__);
return -ENOMEM;
}
if (!buf_info) {
kfree(new_entry);
return -EIO;
}
INIT_LIST_HEAD(&new_entry->entry);
new_entry->vb2_v4l2_buf = dev->vb2_ops.get_buf_by_idx(
buf_info->session_id, buf_info->stream_id, buf_info->index);
if (!new_entry->vb2_v4l2_buf) {
pr_debug("%s:Get buf is null\n", __func__);
kfree(new_entry);
return -EINVAL;
}
new_entry->session_id = buf_info->session_id;
new_entry->stream_id = buf_info->stream_id;
new_entry->index = new_entry->vb2_v4l2_buf->vb2_buf.index;
spin_lock_irqsave(&dev->buf_q_spinlock, flags);
list_add_tail(&new_entry->entry, &dev->buf_qhead);
spin_unlock_irqrestore(&dev->buf_q_spinlock, flags);
if (buf_info->type == MSM_CAMERA_BUF_MNGR_BUF_USER) {
mutex_lock(&dev->cont_mutex);
if (!list_empty(&dev->cont_qhead)) {
rc = msm_buf_mngr_hdl_cont_get_buf(dev, buf_info);
} else {
pr_err("Nothing mapped in user buf for %d,%d\n",
buf_info->session_id, buf_info->stream_id);
rc = -EINVAL;
}
mutex_unlock(&dev->cont_mutex);
}
return rc;
}
static int32_t msm_buf_mngr_buf_done(struct msm_buf_mngr_device *buf_mngr_dev,
struct msm_buf_mngr_info *buf_info)
{
unsigned long flags;
struct msm_get_bufs *bufs, *save;
int32_t ret = -EINVAL;
spin_lock_irqsave(&buf_mngr_dev->buf_q_spinlock, flags);
list_for_each_entry_safe(bufs, save, &buf_mngr_dev->buf_qhead, entry) {
if ((bufs->session_id == buf_info->session_id) &&
(bufs->stream_id == buf_info->stream_id) &&
(bufs->vb2_v4l2_buf->vb2_buf.index ==
buf_info->index)) {
bufs->vb2_v4l2_buf->sequence = buf_info->frame_id;
bufs->vb2_v4l2_buf->timestamp = buf_info->timestamp;
ret = buf_mngr_dev->vb2_ops.buf_done
(bufs->vb2_v4l2_buf,
buf_info->session_id,
buf_info->stream_id,
buf_info->frame_id,
&buf_info->timestamp,
buf_info->reserved);
list_del_init(&bufs->entry);
kfree(bufs);
break;
}
}
spin_unlock_irqrestore(&buf_mngr_dev->buf_q_spinlock, flags);
return ret;
}
static int32_t msm_buf_mngr_put_buf(struct msm_buf_mngr_device *buf_mngr_dev,
struct msm_buf_mngr_info *buf_info)
{
unsigned long flags;
struct msm_get_bufs *bufs, *save;
int32_t ret = -EINVAL;
spin_lock_irqsave(&buf_mngr_dev->buf_q_spinlock, flags);
list_for_each_entry_safe(bufs, save, &buf_mngr_dev->buf_qhead, entry) {
if ((bufs->session_id == buf_info->session_id) &&
(bufs->stream_id == buf_info->stream_id) &&
(bufs->vb2_v4l2_buf->vb2_buf.index ==
buf_info->index)) {
ret = buf_mngr_dev->vb2_ops.put_buf(bufs->vb2_v4l2_buf,
buf_info->session_id, buf_info->stream_id);
list_del_init(&bufs->entry);
kfree(bufs);
break;
}
}
spin_unlock_irqrestore(&buf_mngr_dev->buf_q_spinlock, flags);
return ret;
}
static int32_t msm_generic_buf_mngr_flush(
struct msm_buf_mngr_device *buf_mngr_dev,
struct msm_buf_mngr_info *buf_info)
{
unsigned long flags;
struct msm_get_bufs *bufs, *save;
int32_t ret = -EINVAL;
struct timeval ts;
spin_lock_irqsave(&buf_mngr_dev->buf_q_spinlock, flags);
/*
* Sanity check on client buf list, remove buf mgr
* queue entries in case any
*/
list_for_each_entry_safe(bufs, save, &buf_mngr_dev->buf_qhead, entry) {
if ((bufs->session_id == buf_info->session_id) &&
(bufs->stream_id == buf_info->stream_id)) {
ret = buf_mngr_dev->vb2_ops.buf_done(bufs->vb2_v4l2_buf,
buf_info->session_id,
buf_info->stream_id, 0, &ts, 0);
pr_err("Bufs not flushed: str_id = %d buf_index = %d ret = %d\n",
buf_info->stream_id, bufs->vb2_v4l2_buf->vb2_buf.index,
ret);
list_del_init(&bufs->entry);
kfree(bufs);
}
}
spin_unlock_irqrestore(&buf_mngr_dev->buf_q_spinlock, flags);
/* Flush the remaining vb2 buffers in stream list */
ret = buf_mngr_dev->vb2_ops.flush_buf(buf_info->session_id,
buf_info->stream_id);
return ret;
}
static int32_t msm_buf_mngr_find_cont_stream(struct msm_buf_mngr_device *dev,
uint32_t *cnt, uint32_t *tstream,
struct msm_sd_close_ioctl *session)
{
struct msm_buf_mngr_user_buf_cont_info *cont_bufs, *cont_save;
int32_t ret = -1;
list_for_each_entry_safe(cont_bufs,
cont_save, &dev->cont_qhead, entry) {
if (cont_bufs->sessid == session->session) {
*cnt = cont_bufs->cnt;
*tstream = cont_bufs->strid;
return 0;
}
}
return ret;
}
static void msm_buf_mngr_contq_listdel(struct msm_buf_mngr_device *dev,
uint32_t session, int32_t stream,
bool unmap, uint32_t cnt)
{
struct msm_buf_mngr_user_buf_cont_info *cont_bufs, *cont_save;
list_for_each_entry_safe(cont_bufs,
cont_save, &dev->cont_qhead, entry) {
if ((cont_bufs->sessid == session) &&
(cont_bufs->strid == stream)) {
if ((cnt == 1) && (unmap == 1)) {
ion_unmap_kernel(dev->ion_client,
cont_bufs->ion_handle);
ion_free(dev->ion_client,
cont_bufs->ion_handle);
}
list_del_init(&cont_bufs->entry);
kfree(cont_bufs);
cnt--;
}
}
if (cnt != 0)
pr_err("Buffers pending cnt = %d\n", cnt);
}
static void msm_buf_mngr_contq_cleanup(struct msm_buf_mngr_device *dev,
struct msm_sd_close_ioctl *session)
{
int32_t stream = -1, found = -1;
uint32_t cnt = 0;
do {
found = msm_buf_mngr_find_cont_stream(dev, &cnt,
&stream, session);
if (found == -1)
break;
msm_buf_mngr_contq_listdel(dev, session->session,
stream, 1, cnt);
} while (found == 0);
}
static void msm_buf_mngr_sd_shutdown(struct msm_buf_mngr_device *dev,
struct msm_sd_close_ioctl *session)
{
unsigned long flags;
struct msm_get_bufs *bufs, *save;
if (WARN_ON(!dev) || WARN_ON(!session))
return;
spin_lock_irqsave(&dev->buf_q_spinlock, flags);
if (!list_empty(&dev->buf_qhead)) {
list_for_each_entry_safe(bufs,
save, &dev->buf_qhead, entry) {
pr_info("%s: Delete invalid bufs =%pK, session_id=%u, bufs->ses_id=%d, str_id=%d, idx=%d\n",
__func__, (void *)bufs, session->session,
bufs->session_id, bufs->stream_id,
bufs->index);
if (session->session == bufs->session_id) {
list_del_init(&bufs->entry);
kfree(bufs);
}
}
}
spin_unlock_irqrestore(&dev->buf_q_spinlock, flags);
mutex_lock(&dev->cont_mutex);
if (!list_empty(&dev->cont_qhead))
msm_buf_mngr_contq_cleanup(dev, session);
mutex_unlock(&dev->cont_mutex);
}
static int msm_buf_mngr_handle_cont_cmd(struct msm_buf_mngr_device *dev,
struct msm_buf_mngr_main_cont_info
*cont_cmd)
{
int rc = 0, i = 0;
struct ion_handle *ion_handle = NULL;
struct msm_camera_user_buf_cont_t *iaddr, *temp_addr;
struct msm_buf_mngr_user_buf_cont_info *new_entry, *bufs, *save;
size_t size;
if ((cont_cmd->cmd >= MSM_CAMERA_BUF_MNGR_CONT_MAX) ||
(cont_cmd->cmd < 0) ||
(cont_cmd->cnt > VB2_MAX_FRAME) ||
(cont_cmd->cont_fd < 0)) {
pr_debug("Invalid arg passed Cmd:%d, cnt:%d, fd:%d\n",
cont_cmd->cmd, cont_cmd->cnt,
cont_cmd->cont_fd);
return -EINVAL;
}
mutex_lock(&dev->cont_mutex);
if (cont_cmd->cmd == MSM_CAMERA_BUF_MNGR_CONT_MAP) {
if (!list_empty(&dev->cont_qhead)) {
list_for_each_entry_safe(bufs,
save, &dev->cont_qhead, entry) {
if ((bufs->sessid == cont_cmd->session_id) &&
(bufs->strid == cont_cmd->stream_id)) {
pr_err("Map exist %d,%d unmap first\n",
cont_cmd->session_id,
cont_cmd->stream_id);
rc = -EINVAL;
goto end;
}
}
}
ion_handle = ion_import_dma_buf(dev->ion_client,
cont_cmd->cont_fd);
if (IS_ERR_OR_NULL(ion_handle)) {
pr_err("Failed to create ion handle for fd %d\n",
cont_cmd->cont_fd);
rc = -EINVAL;
goto end;
}
if (ion_handle_get_size(dev->ion_client,
ion_handle, &size) < 0) {
pr_err("Get ion size failed\n");
rc = -EINVAL;
goto free_ion_handle;
}
if ((size == 0) || (size <
(sizeof(struct msm_camera_user_buf_cont_t) *
cont_cmd->cnt))) {
pr_err("Invalid or zero size ION buffer %zu\n", size);
rc = -EINVAL;
goto free_ion_handle;
}
iaddr = ion_map_kernel(dev->ion_client, ion_handle);
if (IS_ERR_OR_NULL(iaddr)) {
pr_err("Mapping cont buff failed\n");
rc = -EINVAL;
goto free_ion_handle;
}
for (i = 0; i < cont_cmd->cnt; i++) {
temp_addr = iaddr + i;
if (temp_addr->buf_cnt >
MSM_CAMERA_MAX_USER_BUFF_CNT) {
pr_err("%s:Invalid buf_cnt:%d for cont:%d\n",
__func__, temp_addr->buf_cnt, i);
rc = -EINVAL;
goto free_list;
}
new_entry = kzalloc(sizeof(
struct msm_buf_mngr_user_buf_cont_info),
GFP_KERNEL);
if (!new_entry) {
pr_err("%s:No mem\n", __func__);
rc = -ENOMEM;
goto free_list;
}
INIT_LIST_HEAD(&new_entry->entry);
new_entry->sessid = cont_cmd->session_id;
new_entry->strid = cont_cmd->stream_id;
new_entry->index = i;
new_entry->main_fd = cont_cmd->cont_fd;
new_entry->ion_handle = ion_handle;
new_entry->cnt = cont_cmd->cnt;
new_entry->paddr = temp_addr;
list_add_tail(&new_entry->entry, &dev->cont_qhead);
}
goto end;
} else if (cont_cmd->cmd == MSM_CAMERA_BUF_MNGR_CONT_UNMAP) {
if (!list_empty(&dev->cont_qhead)) {
msm_buf_mngr_contq_listdel(dev, cont_cmd->session_id,
cont_cmd->stream_id, 1, cont_cmd->cnt);
} else {
pr_err("Nothing mapped for %d,%d\n",
cont_cmd->session_id, cont_cmd->stream_id);
rc = -EINVAL;
}
goto end;
}
free_list:
if (i != 0) {
if (!list_empty(&dev->cont_qhead)) {
msm_buf_mngr_contq_listdel(dev, cont_cmd->session_id,
cont_cmd->stream_id, 0, i);
}
}
ion_unmap_kernel(dev->ion_client, ion_handle);
free_ion_handle:
ion_free(dev->ion_client, ion_handle);
end:
mutex_unlock(&dev->cont_mutex);
return rc;
}
static int msm_generic_buf_mngr_open(struct v4l2_subdev *sd,
struct v4l2_subdev_fh *fh)
{
int rc = 0;
struct msm_buf_mngr_device *buf_mngr_dev = v4l2_get_subdevdata(sd);
if (!buf_mngr_dev) {
pr_err("%s buf manager device NULL\n", __func__);
rc = -ENODEV;
return rc;
}
return rc;
}
static int msm_generic_buf_mngr_close(struct v4l2_subdev *sd,
struct v4l2_subdev_fh *fh)
{
int rc = 0;
struct msm_buf_mngr_device *buf_mngr_dev = v4l2_get_subdevdata(sd);
if (!buf_mngr_dev) {
pr_err("%s buf manager device NULL\n", __func__);
rc = -ENODEV;
return rc;
}
return rc;
}
int msm_cam_buf_mgr_ops(unsigned int cmd, void *argp)
{
int rc = 0;
if (!msm_buf_mngr_dev)
return -ENODEV;
if (!argp)
return -EINVAL;
switch (cmd) {
case VIDIOC_MSM_BUF_MNGR_GET_BUF:
rc = msm_buf_mngr_get_buf(msm_buf_mngr_dev, argp);
break;
case VIDIOC_MSM_BUF_MNGR_BUF_DONE:
rc = msm_buf_mngr_buf_done(msm_buf_mngr_dev, argp);
break;
case VIDIOC_MSM_BUF_MNGR_PUT_BUF:
rc = msm_buf_mngr_put_buf(msm_buf_mngr_dev, argp);
break;
case VIDIOC_MSM_BUF_MNGR_IOCTL_CMD: {
struct msm_camera_private_ioctl_arg *k_ioctl = argp;
switch (k_ioctl->id) {
case MSM_CAMERA_BUF_MNGR_IOCTL_ID_GET_BUF_BY_IDX: {
struct msm_buf_mngr_info *tmp = NULL;
if (!k_ioctl->ioctl_ptr)
return -EINVAL;
if (k_ioctl->size != sizeof(struct msm_buf_mngr_info))
return -EINVAL;
MSM_CAM_GET_IOCTL_ARG_PTR(&tmp, &k_ioctl->ioctl_ptr,
sizeof(tmp));
rc = msm_buf_mngr_get_buf_by_idx(msm_buf_mngr_dev,
tmp);
}
break;
default:
pr_debug("unimplemented id %d", k_ioctl->id);
return -EINVAL;
}
break;
}
default:
return -ENOIOCTLCMD;
}
return rc;
}
int msm_cam_buf_mgr_register_ops(struct msm_cam_buf_mgr_req_ops *cb_struct)
{
if (!msm_buf_mngr_dev)
return -ENODEV;
if (!cb_struct)
return -EINVAL;
cb_struct->msm_cam_buf_mgr_ops = msm_cam_buf_mgr_ops;
return 0;
}
static long msm_buf_mngr_subdev_ioctl(struct v4l2_subdev *sd,
unsigned int cmd, void *arg)
{
int32_t rc = 0;
struct msm_buf_mngr_device *buf_mngr_dev = v4l2_get_subdevdata(sd);
void __user *argp = (void __user *)arg;
if (!buf_mngr_dev) {
pr_err("%s buf manager device NULL\n", __func__);
rc = -ENOMEM;
return rc;
}
switch (cmd) {
case VIDIOC_MSM_BUF_MNGR_IOCTL_CMD: {
struct msm_camera_private_ioctl_arg k_ioctl, *ptr;
if (!arg)
return -EINVAL;
ptr = arg;
k_ioctl = *ptr;
switch (k_ioctl.id) {
case MSM_CAMERA_BUF_MNGR_IOCTL_ID_GET_BUF_BY_IDX: {
struct msm_buf_mngr_info buf_info, *tmp = NULL;
if (k_ioctl.size != sizeof(struct msm_buf_mngr_info))
return -EINVAL;
if (!k_ioctl.ioctl_ptr)
return -EINVAL;
MSM_CAM_GET_IOCTL_ARG_PTR(&tmp, &k_ioctl.ioctl_ptr,
sizeof(tmp));
if (copy_from_user(&buf_info, tmp,
sizeof(struct msm_buf_mngr_info))) {
return -EFAULT;
}
MSM_CAM_GET_IOCTL_ARG_PTR(&k_ioctl.ioctl_ptr,
&buf_info, sizeof(void *));
argp = &k_ioctl;
rc = msm_cam_buf_mgr_ops(cmd, argp);
}
break;
default:
pr_debug("unimplemented id %d", k_ioctl.id);
return -EINVAL;
}
}
break;
case VIDIOC_MSM_BUF_MNGR_GET_BUF:
case VIDIOC_MSM_BUF_MNGR_BUF_DONE:
case VIDIOC_MSM_BUF_MNGR_PUT_BUF:
rc = msm_cam_buf_mgr_ops(cmd, argp);
break;
case VIDIOC_MSM_BUF_MNGR_INIT:
rc = msm_generic_buf_mngr_open(sd, NULL);
break;
case VIDIOC_MSM_BUF_MNGR_DEINIT:
rc = msm_generic_buf_mngr_close(sd, NULL);
break;
case MSM_SD_NOTIFY_FREEZE:
break;
case VIDIOC_MSM_BUF_MNGR_FLUSH:
rc = msm_generic_buf_mngr_flush(buf_mngr_dev, argp);
break;
case MSM_SD_UNNOTIFY_FREEZE:
break;
case MSM_SD_SHUTDOWN:
msm_buf_mngr_sd_shutdown(buf_mngr_dev, argp);
break;
case VIDIOC_MSM_BUF_MNGR_CONT_CMD:
rc = msm_buf_mngr_handle_cont_cmd(buf_mngr_dev, argp);
break;
default:
return -ENOIOCTLCMD;
}
return rc;
}
#ifdef CONFIG_COMPAT
static long msm_camera_buf_mgr_fetch_buf_info(
struct msm_buf_mngr_info32_t *buf_info32,
struct msm_buf_mngr_info *buf_info, unsigned long arg)
{
if (!arg || !buf_info32 || !buf_info)
return -EINVAL;
if (copy_from_user(buf_info32, (void __user *)arg,
sizeof(struct msm_buf_mngr_info32_t)))
return -EFAULT;
buf_info->session_id = buf_info32->session_id;
buf_info->stream_id = buf_info32->stream_id;
buf_info->frame_id = buf_info32->frame_id;
buf_info->index = buf_info32->index;
buf_info->timestamp.tv_sec = (long) buf_info32->timestamp.tv_sec;
buf_info->timestamp.tv_usec = (long) buf_info32->
timestamp.tv_usec;
buf_info->reserved = buf_info32->reserved;
buf_info->type = buf_info32->type;
return 0;
}
static long msm_camera_buf_mgr_update_buf_info(
struct msm_buf_mngr_info32_t *buf_info32,
struct msm_buf_mngr_info *buf_info, unsigned long arg)
{
if (!arg || !buf_info32 || !buf_info)
return -EINVAL;
buf_info32->session_id = buf_info->session_id;
buf_info32->stream_id = buf_info->stream_id;
buf_info32->index = buf_info->index;
buf_info32->timestamp.tv_sec = (int32_t) buf_info->
timestamp.tv_sec;
buf_info32->timestamp.tv_usec = (int32_t) buf_info->timestamp.
tv_usec;
buf_info32->reserved = buf_info->reserved;
buf_info32->type = buf_info->type;
buf_info32->user_buf.buf_cnt = buf_info->user_buf.buf_cnt;
memcpy(&buf_info32->user_buf.buf_idx,
&buf_info->user_buf.buf_idx,
sizeof(buf_info->user_buf.buf_idx));
if (copy_to_user((void __user *)arg, buf_info32,
sizeof(struct msm_buf_mngr_info32_t)))
return -EFAULT;
return 0;
}
static long msm_camera_buf_mgr_internal_compat_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
struct video_device *vdev = video_devdata(file);
struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
long rc = 0;
struct msm_camera_private_ioctl_arg k_ioctl;
void __user *tmp_compat_ioctl_ptr = NULL;
rc = msm_copy_camera_private_ioctl_args(arg,
&k_ioctl, &tmp_compat_ioctl_ptr);
if (rc < 0) {
pr_err("Subdev cmd %d failed\n", cmd);
return rc;
}
switch (k_ioctl.id) {
case MSM_CAMERA_BUF_MNGR_IOCTL_ID_GET_BUF_BY_IDX: {
struct msm_buf_mngr_info32_t buf_info32;
struct msm_buf_mngr_info buf_info;
if (k_ioctl.size != sizeof(struct msm_buf_mngr_info32_t)) {
pr_err("Invalid size for id %d with size %d",
k_ioctl.id, k_ioctl.size);
return -EINVAL;
}
if (!tmp_compat_ioctl_ptr) {
pr_err("Invalid ptr for id %d", k_ioctl.id);
return -EINVAL;
}
k_ioctl.ioctl_ptr = (__u64)&buf_info;
rc = msm_camera_buf_mgr_fetch_buf_info(&buf_info32, &buf_info,
(unsigned long)tmp_compat_ioctl_ptr);
if (rc < 0) {
pr_err("Fetch buf info failed for cmd=%d", cmd);
return rc;
}
rc = v4l2_subdev_call(sd, core, ioctl, cmd, &k_ioctl);
if (rc < 0) {
pr_err("Subdev cmd %d failed for id %d", cmd,
k_ioctl.id);
return rc;
}
}
break;
default:
pr_debug("unimplemented id %d", k_ioctl.id);
return -EINVAL;
}
return 0;
}
static long msm_bmgr_subdev_fops_compat_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
struct video_device *vdev = video_devdata(file);
struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
int32_t rc = 0;
/* Convert 32 bit IOCTL ID's to 64 bit IOCTL ID's
* except VIDIOC_MSM_CPP_CFG32, which needs special
* processing
*/
switch (cmd) {
case VIDIOC_MSM_BUF_MNGR_GET_BUF32:
cmd = VIDIOC_MSM_BUF_MNGR_GET_BUF;
break;
case VIDIOC_MSM_BUF_MNGR_BUF_DONE32:
cmd = VIDIOC_MSM_BUF_MNGR_BUF_DONE;
break;
case VIDIOC_MSM_BUF_MNGR_PUT_BUF32:
cmd = VIDIOC_MSM_BUF_MNGR_PUT_BUF;
break;
case VIDIOC_MSM_BUF_MNGR_CONT_CMD:
break;
case VIDIOC_MSM_BUF_MNGR_FLUSH32:
cmd = VIDIOC_MSM_BUF_MNGR_FLUSH;
break;
case VIDIOC_MSM_BUF_MNGR_IOCTL_CMD:
break;
default:
pr_debug("unsupported compat type\n");
return -ENOIOCTLCMD;
}
switch (cmd) {
case VIDIOC_MSM_BUF_MNGR_GET_BUF:
case VIDIOC_MSM_BUF_MNGR_BUF_DONE:
case VIDIOC_MSM_BUF_MNGR_FLUSH:
case VIDIOC_MSM_BUF_MNGR_PUT_BUF: {
struct msm_buf_mngr_info32_t buf_info32;
struct msm_buf_mngr_info buf_info;
rc = msm_camera_buf_mgr_fetch_buf_info(&buf_info32, &buf_info,
arg);
if (rc < 0) {
pr_err("Fetch buf info failed for cmd=%d\n", cmd);
return rc;
}
rc = v4l2_subdev_call(sd, core, ioctl, cmd, &buf_info);
if (rc < 0) {
pr_debug("Subdev cmd %d fail\n", cmd);
return rc;
}
rc = msm_camera_buf_mgr_update_buf_info(&buf_info32, &buf_info,
arg);
if (rc < 0) {
pr_err("Update buf info failed for cmd=%d\n", cmd);
return rc;
}
}
break;
case VIDIOC_MSM_BUF_MNGR_IOCTL_CMD: {
rc = msm_camera_buf_mgr_internal_compat_ioctl(file, cmd, arg);
if (rc < 0) {
pr_debug("Subdev cmd %d fail\n", cmd);
return rc;
}
}
break;
case VIDIOC_MSM_BUF_MNGR_CONT_CMD: {
struct msm_buf_mngr_main_cont_info cont_cmd;
if (copy_from_user(&cont_cmd, (void __user *)arg,
sizeof(struct msm_buf_mngr_main_cont_info)))
return -EFAULT;
rc = v4l2_subdev_call(sd, core, ioctl, cmd, &cont_cmd);
if (rc < 0) {
pr_debug("Subdev cmd %d fail\n", cmd);
return rc;
}
}
break;
default:
pr_debug("unsupported compat type\n");
return -ENOIOCTLCMD;
}
return 0;
}
#endif
static struct v4l2_subdev_core_ops msm_buf_mngr_subdev_core_ops = {
.ioctl = msm_buf_mngr_subdev_ioctl,
};
static const struct v4l2_subdev_internal_ops
msm_generic_buf_mngr_subdev_internal_ops = {
.open = msm_generic_buf_mngr_open,
.close = msm_generic_buf_mngr_close,
};
static const struct v4l2_subdev_ops msm_buf_mngr_subdev_ops = {
.core = &msm_buf_mngr_subdev_core_ops,
};
static struct v4l2_file_operations msm_buf_v4l2_subdev_fops;
static long msm_bmgr_subdev_do_ioctl(
struct file *file, unsigned int cmd, void *arg)
{
struct video_device *vdev = video_devdata(file);
struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
}
static long msm_buf_subdev_fops_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
return video_usercopy(file, cmd, arg, msm_bmgr_subdev_do_ioctl);
}
static int32_t __init msm_buf_mngr_init(void)
{
int32_t rc = 0;
msm_buf_mngr_dev = kzalloc(sizeof(*msm_buf_mngr_dev),
GFP_KERNEL);
if (!msm_buf_mngr_dev)
return -ENOMEM;
/* Sub-dev */
v4l2_subdev_init(&msm_buf_mngr_dev->subdev.sd,
&msm_buf_mngr_subdev_ops);
msm_cam_copy_v4l2_subdev_fops(&msm_buf_v4l2_subdev_fops);
msm_buf_v4l2_subdev_fops.unlocked_ioctl = msm_buf_subdev_fops_ioctl;
#ifdef CONFIG_COMPAT
msm_buf_v4l2_subdev_fops.compat_ioctl32 =
msm_bmgr_subdev_fops_compat_ioctl;
#endif
snprintf(msm_buf_mngr_dev->subdev.sd.name,
ARRAY_SIZE(msm_buf_mngr_dev->subdev.sd.name), "msm_buf_mngr");
msm_buf_mngr_dev->subdev.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
v4l2_set_subdevdata(&msm_buf_mngr_dev->subdev.sd, msm_buf_mngr_dev);
media_entity_init(&msm_buf_mngr_dev->subdev.sd.entity, 0, NULL, 0);
msm_buf_mngr_dev->subdev.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
msm_buf_mngr_dev->subdev.sd.entity.group_id =
MSM_CAMERA_SUBDEV_BUF_MNGR;
msm_buf_mngr_dev->subdev.sd.internal_ops =
&msm_generic_buf_mngr_subdev_internal_ops;
msm_buf_mngr_dev->subdev.close_seq = MSM_SD_CLOSE_4TH_CATEGORY;
rc = msm_sd_register(&msm_buf_mngr_dev->subdev);
if (rc != 0) {
pr_err("%s: msm_sd_register error = %d\n", __func__, rc);
goto end;
}
msm_buf_mngr_dev->subdev.sd.devnode->fops = &msm_buf_v4l2_subdev_fops;
v4l2_subdev_notify(&msm_buf_mngr_dev->subdev.sd, MSM_SD_NOTIFY_REQ_CB,
&msm_buf_mngr_dev->vb2_ops);
INIT_LIST_HEAD(&msm_buf_mngr_dev->buf_qhead);
spin_lock_init(&msm_buf_mngr_dev->buf_q_spinlock);
mutex_init(&msm_buf_mngr_dev->cont_mutex);
INIT_LIST_HEAD(&msm_buf_mngr_dev->cont_qhead);
msm_buf_mngr_dev->ion_client =
msm_ion_client_create("msm_cam_generic_buf_mgr");
if (!msm_buf_mngr_dev->ion_client) {
pr_err("%s: Failed to create ion client\n", __func__);
rc = -EBADFD;
}
end:
return rc;
}
static void __exit msm_buf_mngr_exit(void)
{
msm_sd_unregister(&msm_buf_mngr_dev->subdev);
mutex_destroy(&msm_buf_mngr_dev->cont_mutex);
kfree(msm_buf_mngr_dev);
}
module_init(msm_buf_mngr_init);
module_exit(msm_buf_mngr_exit);
MODULE_DESCRIPTION("MSM Buffer Manager");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,65 @@
/* Copyright (c) 2013-2017, 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_BUF_GENERIC_MNGR_H__
#define __MSM_BUF_GENERIC_MNGR_H__
#include <linux/io.h>
#include <linux/of.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <media/v4l2-subdev.h>
#include <media/ais/msm_ais.h>
#include <media/ais/msm_ais_buf_mgr.h>
#include "msm.h"
#include "msm_sd.h"
struct msm_get_bufs {
struct list_head entry;
struct vb2_v4l2_buffer *vb2_v4l2_buf;
uint32_t session_id;
uint32_t stream_id;
uint32_t index;
};
struct msm_buf_mngr_device {
struct list_head buf_qhead;
spinlock_t buf_q_spinlock;
struct ion_client *ion_client;
struct msm_sd_subdev subdev;
struct msm_sd_req_vb2_q vb2_ops;
struct list_head cont_qhead;
struct mutex cont_mutex;
};
struct msm_buf_mngr_user_buf_cont_info {
struct list_head entry;
uint32_t sessid;
uint32_t strid;
uint32_t index;
int32_t main_fd;
struct msm_camera_user_buf_cont_t *paddr;
uint32_t cnt;
struct ion_handle *ion_handle;
};
/* kernel space functions*/
struct msm_cam_buf_mgr_req_ops {
int (*msm_cam_buf_mgr_ops)(unsigned int cmd, void *argp);
};
/* API to register callback from client. This assumes cb_struct is allocated by
* client.
*/
int msm_cam_buf_mgr_register_ops(struct msm_cam_buf_mgr_req_ops *cb_struct);
#endif

View file

@ -0,0 +1,100 @@
/* Copyright (c) 2012-2017, 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_SD_H
#define _MSM_SD_H
#include <media/v4l2-subdev.h>
#include <media/ais/msm_ais.h>
/* NOTE: this header file should ONLY be included by subdev drivers */
struct msm_sd_close_ioctl {
unsigned int session;
unsigned int stream;
};
#define MSM_SD_CLOSE_STREAM \
_IOWR('V', BASE_VIDIOC_PRIVATE + 26, struct msm_sd_close_ioctl)
#define MSM_SD_CLOSE_SESSION \
_IOWR('V', BASE_VIDIOC_PRIVATE + 27, struct msm_sd_close_ioctl)
#define MSM_SD_CLOSE_SESSION_AND_STREAM \
_IOWR('V', BASE_VIDIOC_PRIVATE + 28, struct msm_sd_close_ioctl)
#define MSM_SD_SHUTDOWN \
_IOWR('V', BASE_VIDIOC_PRIVATE + 29, struct msm_sd_close_ioctl)
#define MSM_SD_NOTIFY_FREEZE \
_IOWR('V', BASE_VIDIOC_PRIVATE + 30, struct msm_sd_close_ioctl)
#define MSM_SD_UNNOTIFY_FREEZE \
_IOWR('V', BASE_VIDIOC_PRIVATE + 31, struct msm_sd_close_ioctl)
/*
* This is used to install Sequence in msm_sd_register.
* During msm_close, proper close sequence will be triggered.
* For example:
*
* close_sequence = 0x00100001 (ISP)
* close_sequence = 0x00100002 (ISP)
* close_sequence = 0x00100003 (ISP)
* close_sequence = 0x00200001 (sensor)
* close_sequence = 0x00200002 (sensor)
* close_sequence = 0x00200003 (sensor)
*/
#define MSM_SD_CLOSE_1ST_CATEGORY 0x00010000
#define MSM_SD_CLOSE_2ND_CATEGORY 0x00020000
#define MSM_SD_CLOSE_3RD_CATEGORY 0x00030000
#define MSM_SD_CLOSE_4TH_CATEGORY 0x00040000
struct msm_sd_subdev {
struct v4l2_subdev sd;
int close_seq;
struct list_head list;
};
struct msm_sd_req_sd {
char *name;
struct v4l2_subdev *subdev;
};
struct msm_sd_req_vb2_q {
struct vb2_v4l2_buffer * (*get_buf)(int session_id,
unsigned int stream_id);
struct vb2_queue * (*get_vb2_queue)(int session_id,
unsigned int stream_id);
struct vb2_v4l2_buffer * (*get_buf_by_idx)(int session_id,
unsigned int stream_id, uint32_t index);
int (*put_buf)(struct vb2_v4l2_buffer *vb2_buf, int session_id,
unsigned int stream_id);
int (*buf_done)(struct vb2_v4l2_buffer *vb2_v4l2_buf, int session_id,
unsigned int stream_id, uint32_t sequence, struct timeval *ts,
uint32_t reserved);
int (*flush_buf)(int session_id, unsigned int stream_id);
};
#define MSM_SD_NOTIFY_GET_SD 0x00000001
#define MSM_SD_NOTIFY_PUT_SD 0x00000002
#define MSM_SD_NOTIFY_REQ_CB 0x00000003
#define MSM_CAM_GET_IOCTL_ARG_PTR(ptr, \
ioctl_ptr, len) memcpy(ptr, ioctl_ptr, len)
int msm_sd_register(struct msm_sd_subdev *msm_subdev);
int msm_sd_unregister(struct msm_sd_subdev *sd);
struct v4l2_subdev *msm_sd_get_subdev(struct v4l2_subdev *sd,
const char *get_name);
void msm_sd_put_subdev(struct v4l2_subdev *sd, struct v4l2_subdev *put);
void msm_cam_copy_v4l2_subdev_fops(struct v4l2_file_operations *d1);
#endif /*_MSM_SD_H */

View file

@ -0,0 +1,3 @@
ccflags-y += -Idrivers/media/platform/msm/ais
ccflags-y += -Idrivers/media/platform/msm/ais/msm_vb2
obj-$(CONFIG_MSM_AIS) += msm_vb2.o

View file

@ -0,0 +1,438 @@
/* Copyright (c) 2012-2017, 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.
*/
#define pr_fmt(fmt) "CAM-VB2 %s:%d " fmt, __func__, __LINE__
#include "msm_vb2.h"
static int msm_vb2_queue_setup(struct vb2_queue *q,
const void *parg,
unsigned int *num_buffers, unsigned int *num_planes,
unsigned int sizes[], void *alloc_ctxs[])
{
int i;
struct msm_v4l2_format_data *data = q->drv_priv;
if (!data) {
pr_err("%s: drv_priv NULL\n", __func__);
return -EINVAL;
}
if (data->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
if (WARN_ON(data->num_planes > VIDEO_MAX_PLANES))
return -EINVAL;
*num_planes = data->num_planes;
for (i = 0; i < data->num_planes; i++)
sizes[i] = data->plane_sizes[i];
} else {
pr_err("%s: Unsupported buf type :%d\n", __func__,
data->type);
return -EINVAL;
}
return 0;
}
int msm_vb2_buf_init(struct vb2_buffer *vb)
{
struct msm_stream *stream;
struct msm_vb2_buffer *msm_vb2_buf;
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
stream = msm_get_stream_from_vb2q(vb->vb2_queue);
if (!stream) {
pr_err("%s: Couldn't find stream\n", __func__);
return -EINVAL;
}
msm_vb2_buf = container_of(vbuf, struct msm_vb2_buffer, vb2_v4l2_buf);
msm_vb2_buf->in_freeq = 0;
return 0;
}
static void msm_vb2_buf_queue(struct vb2_buffer *vb)
{
struct msm_vb2_buffer *msm_vb2;
struct msm_stream *stream;
unsigned long flags;
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
msm_vb2 = container_of(vbuf, struct msm_vb2_buffer, vb2_v4l2_buf);
if (!msm_vb2) {
pr_err("%s:%d] vb2_buf NULL", __func__, __LINE__);
return;
}
stream = msm_get_stream_from_vb2q(vb->vb2_queue);
if (!stream) {
pr_err("%s:%d] NULL stream", __func__, __LINE__);
return;
}
spin_lock_irqsave(&stream->stream_lock, flags);
list_add_tail(&msm_vb2->list, &stream->queued_list);
spin_unlock_irqrestore(&stream->stream_lock, flags);
}
static void msm_vb2_buf_finish(struct vb2_buffer *vb)
{
struct msm_vb2_buffer *msm_vb2;
struct msm_stream *stream;
unsigned long flags;
struct msm_vb2_buffer *msm_vb2_entry, *temp;
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
msm_vb2 = container_of(vbuf, struct msm_vb2_buffer, vb2_v4l2_buf);
if (!msm_vb2) {
pr_err("%s:%d] vb2_buf NULL", __func__, __LINE__);
return;
}
stream = msm_get_stream_from_vb2q(vb->vb2_queue);
if (!stream) {
pr_err("%s:%d] NULL stream", __func__, __LINE__);
return;
}
spin_lock_irqsave(&stream->stream_lock, flags);
list_for_each_entry_safe(msm_vb2_entry, temp, &(stream->queued_list),
list) {
if (msm_vb2_entry == msm_vb2) {
list_del_init(&msm_vb2_entry->list);
break;
}
}
spin_unlock_irqrestore(&stream->stream_lock, flags);
}
static void msm_vb2_stop_stream(struct vb2_queue *q)
{
struct msm_vb2_buffer *msm_vb2, *temp;
struct msm_stream *stream;
unsigned long flags;
struct vb2_v4l2_buffer *vb2_v4l2_buf;
stream = msm_get_stream_from_vb2q(q);
if (!stream) {
pr_err_ratelimited("%s:%d] NULL stream", __func__, __LINE__);
return;
}
/*
* Release all the buffers enqueued to driver
* when streamoff is issued
*/
spin_lock_irqsave(&stream->stream_lock, flags);
list_for_each_entry_safe(msm_vb2, temp, &(stream->queued_list),
list) {
vb2_v4l2_buf = &(msm_vb2->vb2_v4l2_buf);
if (vb2_v4l2_buf->vb2_buf.state == VB2_BUF_STATE_DONE)
continue;
vb2_buffer_done(&vb2_v4l2_buf->vb2_buf,
VB2_BUF_STATE_DONE);
msm_vb2->in_freeq = 0;
}
spin_unlock_irqrestore(&stream->stream_lock, flags);
}
static struct vb2_ops msm_vb2_get_q_op = {
.queue_setup = msm_vb2_queue_setup,
.buf_init = msm_vb2_buf_init,
.buf_queue = msm_vb2_buf_queue,
.buf_finish = msm_vb2_buf_finish,
.stop_streaming = msm_vb2_stop_stream,
};
struct vb2_ops *msm_vb2_get_q_ops(void)
{
return &msm_vb2_get_q_op;
}
static void *msm_vb2_dma_contig_get_userptr(void *alloc_ctx,
unsigned long vaddr, unsigned long size,
enum dma_data_direction dma_dir)
{
struct msm_vb2_private_data *priv;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return ERR_PTR(-ENOMEM);
priv->vaddr = (void *)vaddr;
priv->size = size;
priv->alloc_ctx = alloc_ctx;
return priv;
}
static void msm_vb2_dma_contig_put_userptr(void *buf_priv)
{
kzfree(buf_priv);
}
static struct vb2_mem_ops msm_vb2_get_q_mem_op = {
.get_userptr = msm_vb2_dma_contig_get_userptr,
.put_userptr = msm_vb2_dma_contig_put_userptr,
};
struct vb2_mem_ops *msm_vb2_get_q_mem_ops(void)
{
return &msm_vb2_get_q_mem_op;
}
static struct vb2_queue *msm_vb2_get_queue(int session_id,
unsigned int stream_id)
{
return msm_get_stream_vb2q(session_id, stream_id);
}
static struct vb2_v4l2_buffer *msm_vb2_get_buf(int session_id,
unsigned int stream_id)
{
struct msm_stream *stream;
struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL;
struct msm_vb2_buffer *msm_vb2 = NULL;
unsigned long flags;
stream = msm_get_stream(session_id, stream_id);
if (IS_ERR_OR_NULL(stream))
return NULL;
spin_lock_irqsave(&stream->stream_lock, flags);
if (!stream->vb2_q) {
pr_err("%s: stream q not available\n", __func__);
goto end;
}
list_for_each_entry(msm_vb2, &(stream->queued_list), list) {
vb2_v4l2_buf = &(msm_vb2->vb2_v4l2_buf);
if (vb2_v4l2_buf->vb2_buf.state != VB2_BUF_STATE_ACTIVE)
continue;
if (msm_vb2->in_freeq)
continue;
msm_vb2->in_freeq = 1;
goto end;
}
msm_vb2 = NULL;
vb2_v4l2_buf = NULL;
end:
spin_unlock_irqrestore(&stream->stream_lock, flags);
return vb2_v4l2_buf;
}
static struct vb2_v4l2_buffer *msm_vb2_get_buf_by_idx(int session_id,
unsigned int stream_id, uint32_t index)
{
struct msm_stream *stream;
struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL;
struct msm_vb2_buffer *msm_vb2 = NULL;
unsigned long flags;
stream = msm_get_stream(session_id, stream_id);
if (IS_ERR_OR_NULL(stream))
return NULL;
spin_lock_irqsave(&stream->stream_lock, flags);
if (!stream->vb2_q) {
pr_err("%s: stream q not available\n", __func__);
goto end;
}
list_for_each_entry(msm_vb2, &(stream->queued_list), list) {
vb2_v4l2_buf = &(msm_vb2->vb2_v4l2_buf);
if ((vb2_v4l2_buf->vb2_buf.index != index) || msm_vb2->in_freeq
|| vb2_v4l2_buf->vb2_buf.state != VB2_BUF_STATE_ACTIVE)
continue;
msm_vb2->in_freeq = 1;
goto end;
}
msm_vb2 = NULL;
vb2_v4l2_buf = NULL;
end:
spin_unlock_irqrestore(&stream->stream_lock, flags);
return vb2_v4l2_buf;
}
static int msm_vb2_put_buf(struct vb2_v4l2_buffer *vb, int session_id,
unsigned int stream_id)
{
struct msm_stream *stream;
struct msm_vb2_buffer *msm_vb2;
struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL;
int rc = 0;
unsigned long flags;
stream = msm_get_stream(session_id, stream_id);
if (IS_ERR_OR_NULL(stream))
return -EINVAL;
spin_lock_irqsave(&stream->stream_lock, flags);
if (vb) {
list_for_each_entry(msm_vb2, &(stream->queued_list), list) {
vb2_v4l2_buf = &(msm_vb2->vb2_v4l2_buf);
if (vb2_v4l2_buf == vb)
break;
}
if (vb2_v4l2_buf != vb) {
pr_err("VB buffer is INVALID vb=%pK, ses_id=%d, str_id=%d\n",
vb, session_id, stream_id);
spin_unlock_irqrestore(&stream->stream_lock, flags);
return -EINVAL;
}
msm_vb2 =
container_of(vb2_v4l2_buf, struct msm_vb2_buffer,
vb2_v4l2_buf);
if (msm_vb2->in_freeq) {
msm_vb2->in_freeq = 0;
rc = 0;
} else
rc = -EINVAL;
} else {
pr_err(" VB buffer is null for ses_id=%d, str_id=%d\n",
session_id, stream_id);
rc = -EINVAL;
}
spin_unlock_irqrestore(&stream->stream_lock, flags);
return rc;
}
static int msm_vb2_buf_done(struct vb2_v4l2_buffer *vb, int session_id,
unsigned int stream_id, uint32_t sequence,
struct timeval *ts, uint32_t reserved)
{
unsigned long flags;
struct msm_vb2_buffer *msm_vb2;
struct msm_stream *stream;
struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL;
int rc = 0;
stream = msm_get_stream(session_id, stream_id);
if (IS_ERR_OR_NULL(stream))
return -EINVAL;
spin_lock_irqsave(&stream->stream_lock, flags);
if (vb) {
list_for_each_entry(msm_vb2, &(stream->queued_list), list) {
vb2_v4l2_buf = &(msm_vb2->vb2_v4l2_buf);
if (vb2_v4l2_buf == vb)
break;
}
if (vb2_v4l2_buf != vb) {
pr_err("VB buffer is INVALID ses_id=%d, str_id=%d, vb=%pK\n",
session_id, stream_id, vb);
spin_unlock_irqrestore(&stream->stream_lock, flags);
return -EINVAL;
}
msm_vb2 = container_of(vb2_v4l2_buf,
struct msm_vb2_buffer, vb2_v4l2_buf);
/* put buf before buf done */
if (msm_vb2->in_freeq) {
vb2_v4l2_buf->sequence = sequence;
vb2_v4l2_buf->timestamp = *ts;
vb2_buffer_done(&vb2_v4l2_buf->vb2_buf,
VB2_BUF_STATE_DONE);
msm_vb2->in_freeq = 0;
rc = 0;
} else
rc = -EINVAL;
} else {
pr_err(" VB buffer is NULL for ses_id=%d, str_id=%d\n",
session_id, stream_id);
rc = -EINVAL;
}
spin_unlock_irqrestore(&stream->stream_lock, flags);
return rc;
}
long msm_vb2_return_buf_by_idx(int session_id, unsigned int stream_id,
uint32_t index)
{
struct msm_stream *stream;
struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL;
struct msm_vb2_buffer *msm_vb2 = NULL;
unsigned long flags;
long rc = -EINVAL;
stream = msm_get_stream(session_id, stream_id);
if (IS_ERR_OR_NULL(stream))
return rc;
spin_lock_irqsave(&stream->stream_lock, flags);
if (!stream->vb2_q) {
pr_err("%s: stream q not available\n", __func__);
goto end;
}
list_for_each_entry(msm_vb2, &(stream->queued_list), list) {
vb2_v4l2_buf = &(msm_vb2->vb2_v4l2_buf);
if ((vb2_v4l2_buf->vb2_buf.index != index)
|| vb2_v4l2_buf->vb2_buf.state != VB2_BUF_STATE_ACTIVE)
continue;
if (!msm_vb2->in_freeq) {
vb2_buffer_done(&vb2_v4l2_buf->vb2_buf,
VB2_BUF_STATE_ERROR);
rc = 0;
} else {
rc = -EINVAL;
}
break;
}
end:
spin_unlock_irqrestore(&stream->stream_lock, flags);
return rc;
}
EXPORT_SYMBOL(msm_vb2_return_buf_by_idx);
static int msm_vb2_flush_buf(int session_id, unsigned int stream_id)
{
unsigned long flags;
struct msm_vb2_buffer *msm_vb2;
struct msm_stream *stream;
struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL;
stream = msm_get_stream(session_id, stream_id);
if (IS_ERR_OR_NULL(stream))
return -EINVAL;
spin_lock_irqsave(&stream->stream_lock, flags);
list_for_each_entry(msm_vb2, &(stream->queued_list), list) {
vb2_v4l2_buf = &(msm_vb2->vb2_v4l2_buf);
/* Do buf done for all buffers*/
vb2_buffer_done(&vb2_v4l2_buf->vb2_buf, VB2_BUF_STATE_DONE);
msm_vb2->in_freeq = 0;
}
spin_unlock_irqrestore(&stream->stream_lock, flags);
return 0;
}
int msm_vb2_request_cb(struct msm_sd_req_vb2_q *req)
{
if (!req) {
pr_err("%s: suddev is null\n", __func__);
return -EINVAL;
}
req->get_buf = msm_vb2_get_buf;
req->get_buf_by_idx = msm_vb2_get_buf_by_idx;
req->get_vb2_queue = msm_vb2_get_queue;
req->put_buf = msm_vb2_put_buf;
req->buf_done = msm_vb2_buf_done;
req->flush_buf = msm_vb2_flush_buf;
return 0;
}

View file

@ -0,0 +1,72 @@
/* Copyright (c) 2012-2017, 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_VB_H
#define _MSM_VB_H
#include <linux/version.h>
#include <linux/i2c.h>
#include <linux/videodev2.h>
#include <linux/pm_qos.h>
#include <linux/wakelock.h>
#include <linux/msm_ion.h>
#include <linux/iommu.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-device.h>
#include <media/v4l2-fh.h>
#include <media/v4l2-event.h>
#include <media/v4l2-mediabus.h>
#include <media/videobuf2-dma-contig.h>
#include <media/ais/msm_ais.h>
#include <media/videobuf2-core.h>
#include "msm.h"
#include "msm_sd.h"
struct msm_vb2_buffer {
/*
* vb2 buffer has to be first in the structure
* because both v4l2 frameworks and driver directly
* cast msm_vb2_buffer to a vb2_buf.
*/
struct vb2_v4l2_buffer vb2_v4l2_buf;
struct list_head list;
int in_freeq;
};
struct msm_vb2_private_data {
void *vaddr;
unsigned long size;
/* Offset of the plane inside the buffer */
void *alloc_ctx;
};
struct msm_stream {
struct list_head list;
/* stream index per session, same
* as stream_id but set through s_parm
*/
unsigned int stream_id;
/* vb2 buffer handling */
struct vb2_queue *vb2_q;
spinlock_t stream_lock;
struct list_head queued_list;
};
struct vb2_ops *msm_vb2_get_q_ops(void);
struct vb2_mem_ops *msm_vb2_get_q_mem_ops(void);
int msm_vb2_request_cb(struct msm_sd_req_vb2_q *req_sd);
long msm_vb2_return_buf_by_idx(int session_id, unsigned int stream_id,
uint32_t index);
#endif /*_MSM_VB_H */

View file

@ -0,0 +1 @@
obj-$(CONFIG_MSM_AIS_CPP) += cpp/

View file

@ -0,0 +1,6 @@
ccflags-y += -Idrivers/media/platform/msm/ais
ccflags-y += -Idrivers/media/platform/msm/ais/isp/
ccflags-y += -Idrivers/media/platform/msm/ais/sensor/io
ccflags-y += -Idrivers/media/platform/msm/ais/common
ccflags-y += -Idrivers/media/platform/msm/ais/msm_buf_mgr/
obj-$(CONFIG_MSM_AIS_CPP) += msm_cpp_soc.o msm_cpp.o

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,294 @@
/* Copyright (c) 2013-2017, 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_CPP_H__
#define __MSM_CPP_H__
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/list.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <media/v4l2-subdev.h>
#include "msm_generic_buf_mgr.h"
#include "msm_sd.h"
#include "cam_soc_api.h"
#include "cam_hw_ops.h"
#include <media/msmb_pproc.h>
/* hw version info:
* 31:28 Major version
* 27:16 Minor version
* 15:0 Revision bits
*/
#define CPP_HW_VERSION_1_1_0 0x10010000
#define CPP_HW_VERSION_1_1_1 0x10010001
#define CPP_HW_VERSION_2_0_0 0x20000000
#define CPP_HW_VERSION_4_0_0 0x40000000
#define CPP_HW_VERSION_4_1_0 0x40010000
#define CPP_HW_VERSION_5_0_0 0x50000000
#define CPP_HW_VERSION_5_1_0 0x50010000
#define VBIF_VERSION_2_3_0 0x20030000
#define MAX_ACTIVE_CPP_INSTANCE 8
#define MAX_CPP_PROCESSING_FRAME 2
#define MAX_CPP_V4l2_EVENTS 30
#define MSM_CPP_MICRO_BASE 0x4000
#define MSM_CPP_MICRO_HW_VERSION 0x0000
#define MSM_CPP_MICRO_IRQGEN_STAT 0x0004
#define MSM_CPP_MICRO_IRQGEN_CLR 0x0008
#define MSM_CPP_MICRO_IRQGEN_MASK 0x000C
#define MSM_CPP_MICRO_FIFO_TX_DATA 0x0010
#define MSM_CPP_MICRO_FIFO_TX_STAT 0x0014
#define MSM_CPP_MICRO_FIFO_RX_DATA 0x0018
#define MSM_CPP_MICRO_FIFO_RX_STAT 0x001C
#define MSM_CPP_MICRO_BOOT_START 0x0020
#define MSM_CPP_MICRO_BOOT_LDORG 0x0024
#define MSM_CPP_MICRO_CLKEN_CTL 0x0030
#define MSM_CPP_CMD_GET_BOOTLOADER_VER 0x1
#define MSM_CPP_CMD_FW_LOAD 0x2
#define MSM_CPP_CMD_EXEC_JUMP 0x3
#define MSM_CPP_CMD_RESET_HW 0x5
#define MSM_CPP_CMD_PROCESS_FRAME 0x6
#define MSM_CPP_CMD_FLUSH_STREAM 0x7
#define MSM_CPP_CMD_CFG_MEM_PARAM 0x8
#define MSM_CPP_CMD_ERROR_REQUEST 0x9
#define MSM_CPP_CMD_GET_STATUS 0xA
#define MSM_CPP_CMD_GET_FW_VER 0xB
#define MSM_CPP_CMD_GROUP_BUFFER_DUP 0x12
#define MSM_CPP_CMD_GROUP_BUFFER 0xF
#define MSM_CPP_MSG_ID_CMD 0x3E646D63
#define MSM_CPP_MSG_ID_OK 0x0A0A4B4F
#define MSM_CPP_MSG_ID_TRAILER 0xABCDEFAA
#define MSM_CPP_MSG_ID_JUMP_ACK 0x00000001
#define MSM_CPP_MSG_ID_FRAME_ACK 0x00000002
#define MSM_CPP_MSG_ID_FRAME_NACK 0x00000003
#define MSM_CPP_MSG_ID_FLUSH_ACK 0x00000004
#define MSM_CPP_MSG_ID_FLUSH_NACK 0x00000005
#define MSM_CPP_MSG_ID_CFG_MEM_ACK 0x00000006
#define MSM_CPP_MSG_ID_CFG_MEM_INV 0x00000007
#define MSM_CPP_MSG_ID_ERROR_STATUS 0x00000008
#define MSM_CPP_MSG_ID_INVALID_CMD 0x00000009
#define MSM_CPP_MSG_ID_GEN_STATUS 0x0000000A
#define MSM_CPP_MSG_ID_FLUSHED 0x0000000B
#define MSM_CPP_MSG_ID_FW_VER 0x0000000C
#define MSM_CPP_JUMP_ADDRESS 0x20
#define MSM_CPP_START_ADDRESS 0x0
#define MSM_CPP_END_ADDRESS 0x3F00
#define MSM_CPP_POLL_RETRIES 200
#define MSM_CPP_TASKLETQ_SIZE 16
#define MSM_CPP_TX_FIFO_LEVEL 16
#define MSM_CPP_RX_FIFO_LEVEL 512
enum cpp_vbif_error {
CPP_VBIF_ERROR_HANG,
CPP_VBIF_ERROR_MAX,
};
enum cpp_vbif_client {
VBIF_CLIENT_CPP,
VBIF_CLIENT_FD,
VBIF_CLIENT_MAX,
};
struct msm_cpp_vbif_data {
int (*err_handler[VBIF_CLIENT_MAX])(void *, uint32_t);
void *dev[VBIF_CLIENT_MAX];
};
struct cpp_subscribe_info {
struct v4l2_fh *vfh;
uint32_t active;
};
enum cpp_state {
CPP_STATE_BOOT,
CPP_STATE_IDLE,
CPP_STATE_ACTIVE,
CPP_STATE_OFF,
};
enum cpp_iommu_state {
CPP_IOMMU_STATE_DETACHED,
CPP_IOMMU_STATE_ATTACHED,
};
enum msm_queue {
MSM_CAM_Q_CTRL, /* control command or control command status */
MSM_CAM_Q_VFE_EVT, /* adsp event */
MSM_CAM_Q_VFE_MSG, /* adsp message */
MSM_CAM_Q_V4L2_REQ, /* v4l2 request */
MSM_CAM_Q_VPE_MSG, /* vpe message */
MSM_CAM_Q_PP_MSG, /* pp message */
};
struct msm_queue_cmd {
struct list_head list_config;
struct list_head list_control;
struct list_head list_frame;
struct list_head list_pict;
struct list_head list_vpe_frame;
struct list_head list_eventdata;
enum msm_queue type;
void *command;
atomic_t on_heap;
struct timespec ts;
uint32_t error_code;
uint32_t trans_code;
};
struct msm_device_queue {
struct list_head list;
spinlock_t lock;
wait_queue_head_t wait;
int max;
int len;
const char *name;
};
struct msm_cpp_tasklet_queue_cmd {
struct list_head list;
uint32_t irq_status;
uint32_t tx_fifo[MSM_CPP_TX_FIFO_LEVEL];
uint32_t tx_level;
uint8_t cmd_used;
};
struct msm_cpp_buffer_map_info_t {
unsigned long len;
dma_addr_t phy_addr;
int buf_fd;
struct msm_cpp_buffer_info_t buff_info;
};
struct msm_cpp_buffer_map_list_t {
struct msm_cpp_buffer_map_info_t map_info;
struct list_head entry;
};
struct msm_cpp_buff_queue_info_t {
uint32_t used;
uint16_t session_id;
uint16_t stream_id;
struct list_head vb2_buff_head;
struct list_head native_buff_head;
};
struct msm_cpp_work_t {
struct work_struct my_work;
struct cpp_device *cpp_dev;
};
struct msm_cpp_payload_params {
uint32_t stripe_base;
uint32_t stripe_size;
uint32_t plane_base;
uint32_t plane_size;
/* offsets for stripe/plane pointers in payload */
uint32_t rd_pntr_off;
uint32_t wr_0_pntr_off;
uint32_t rd_ref_pntr_off;
uint32_t wr_ref_pntr_off;
uint32_t wr_0_meta_data_wr_pntr_off;
uint32_t fe_mmu_pf_ptr_off;
uint32_t ref_fe_mmu_pf_ptr_off;
uint32_t we_mmu_pf_ptr_off;
uint32_t dup_we_mmu_pf_ptr_off;
uint32_t ref_we_mmu_pf_ptr_off;
uint32_t set_group_buffer_len;
uint32_t dup_frame_indicator_off;
};
struct cpp_device {
struct platform_device *pdev;
struct msm_sd_subdev msm_sd;
struct v4l2_subdev subdev;
struct resource *irq;
void __iomem *vbif_base;
void __iomem *base;
void __iomem *cpp_hw_base;
void __iomem *camss_cpp_base;
struct clk **cpp_clk;
struct msm_cam_clk_info *clk_info;
size_t num_clks;
struct msm_cam_regulator *cpp_vdd;
int num_reg;
struct mutex mutex;
enum cpp_state state;
enum cpp_iommu_state iommu_state;
uint8_t is_firmware_loaded;
char *fw_name_bin;
const struct firmware *fw;
struct workqueue_struct *timer_wq;
struct msm_cpp_work_t *work;
uint32_t fw_version;
uint8_t stream_cnt;
uint8_t timeout_trial_cnt;
uint8_t max_timeout_trial_cnt;
int domain_num;
struct iommu_domain *domain;
struct device *iommu_ctx;
uint32_t num_clk;
uint32_t min_clk_rate;
int iommu_hdl;
/* Reusing proven tasklet from msm isp */
atomic_t irq_cnt;
uint8_t taskletq_idx;
spinlock_t tasklet_lock;
struct list_head tasklet_q;
struct tasklet_struct cpp_tasklet;
struct msm_cpp_tasklet_queue_cmd
tasklet_queue_cmd[MSM_CPP_TASKLETQ_SIZE];
struct cpp_subscribe_info cpp_subscribe_list[MAX_ACTIVE_CPP_INSTANCE];
uint32_t cpp_open_cnt;
struct cpp_hw_info hw_info;
struct msm_device_queue eventData_q; /* V4L2 Event Payload Queue */
/* Processing Queue
* store frame info for frames sent to microcontroller
*/
struct msm_device_queue processing_q;
struct msm_cpp_buff_queue_info_t *buff_queue;
uint32_t num_buffq;
struct msm_cam_buf_mgr_req_ops buf_mgr_ops;
uint32_t bus_client;
uint32_t bus_idx;
uint32_t bus_master_flag;
struct msm_cpp_payload_params payload_params;
struct msm_cpp_vbif_data *vbif_data;
};
int msm_cpp_set_micro_clk(struct cpp_device *cpp_dev);
int msm_update_freq_tbl(struct cpp_device *cpp_dev);
int msm_cpp_get_clock_index(struct cpp_device *cpp_dev, const char *clk_name);
long msm_cpp_set_core_clk(struct cpp_device *cpp_dev, long rate, int idx);
void msm_cpp_fetch_dt_params(struct cpp_device *cpp_dev);
int msm_cpp_read_payload_params_from_dt(struct cpp_device *cpp_dev);
void msm_cpp_vbif_register_error_handler(void *dev,
enum cpp_vbif_client client,
int (*client_vbif_error_handler)(void *, uint32_t));
#endif /* __MSM_CPP_H__ */

View file

@ -0,0 +1,251 @@
/* Copyright (c) 2016-2017, 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.
*/
#define pr_fmt(fmt) "MSM-CPP-SOC %s:%d " fmt, __func__, __LINE__
#include <linux/clk/msm-clk.h>
#include <linux/clk/msm-clk-provider.h>
#include <linux/delay.h>
#include <media/msmb_pproc.h>
#include "msm_cpp.h"
#define CPP_DT_READ_U32_ERR(_dev, _key, _str, _ret, _out) { \
_key = _str; \
_ret = of_property_read_u32(_dev, _key, &_out); \
if (_ret) \
break; \
}
#define CPP_DT_READ_U32(_dev, _str, _out) { \
of_property_read_u32(_dev, _str, &_out); \
}
void msm_cpp_fetch_dt_params(struct cpp_device *cpp_dev)
{
int rc = 0;
struct device_node *of_node = cpp_dev->pdev->dev.of_node;
if (!of_node) {
pr_err("%s: invalid params\n", __func__);
return;
}
of_property_read_u32(of_node, "cell-index", &cpp_dev->pdev->id);
rc = of_property_read_u32(of_node, "qcom,min-clock-rate",
&cpp_dev->min_clk_rate);
if (rc < 0) {
pr_debug("min-clk-rate not defined, setting it to 0\n");
cpp_dev->min_clk_rate = 0;
}
rc = of_property_read_u32(of_node, "qcom,bus-master",
&cpp_dev->bus_master_flag);
if (rc)
cpp_dev->bus_master_flag = 0;
}
int msm_cpp_get_clock_index(struct cpp_device *cpp_dev, const char *clk_name)
{
uint32_t i = 0;
for (i = 0; i < cpp_dev->num_clks; i++) {
if (!strcmp(clk_name, cpp_dev->clk_info[i].clk_name))
return i;
}
return -EINVAL;
}
static int cpp_get_clk_freq_tbl(struct clk *clk, struct cpp_hw_info *hw_info,
uint32_t min_clk_rate)
{
uint32_t i;
uint32_t idx = 0;
signed long freq_tbl_entry = 0;
if ((clk == NULL) || (hw_info == NULL) || (clk->ops == NULL) ||
(clk->ops->list_rate == NULL)) {
pr_err("Bad parameter\n");
return -EINVAL;
}
for (i = 0; i < MAX_FREQ_TBL; i++) {
freq_tbl_entry = clk->ops->list_rate(clk, i);
pr_debug("entry=%ld\n", freq_tbl_entry);
if (freq_tbl_entry >= 0) {
if (freq_tbl_entry >= min_clk_rate) {
hw_info->freq_tbl[idx++] = freq_tbl_entry;
pr_debug("tbl[%d]=%ld\n", idx-1,
freq_tbl_entry);
}
} else {
pr_debug("freq table returned invalid entry/end %ld\n",
freq_tbl_entry);
break;
}
}
pr_debug("%s: idx %d", __func__, idx);
hw_info->freq_tbl_count = idx;
return 0;
}
int msm_cpp_set_micro_clk(struct cpp_device *cpp_dev)
{
#ifdef ENABLE_CPP_MICRO
uint32_t msm_micro_iface_idx;
int rc;
msm_micro_iface_idx = msm_cpp_get_clock_index(cpp_dev,
"micro_iface_clk");
if (msm_micro_iface_idx < 0) {
pr_err("Fail to get clock index\n");
return -EINVAL;
}
rc = msm_clk_reset(cpp_dev->cpp_clk[msm_micro_iface_idx],
CLK_RESET_ASSERT);
if (rc) {
pr_err("%s:micro_iface_clk assert failed\n",
__func__);
return -EINVAL;
}
/*
* Below usleep values are chosen based on experiments
* and this was the smallest number which works. This
* sleep is needed to leave enough time for Microcontroller
* to resets all its registers.
*/
usleep_range(1000, 1200);
rc = msm_clk_reset(cpp_dev->cpp_clk[msm_micro_iface_idx],
CLK_RESET_DEASSERT);
if (rc) {
pr_err("%s:micro_iface_clk de-assert failed\n", __func__);
return -EINVAL;
}
/*
* Below usleep values are chosen based on experiments
* and this was the smallest number which works. This
* sleep is needed to leave enough time for Microcontroller
* to resets all its registers.
*/
usleep_range(1000, 1200);
#endif
return 0;
}
int msm_update_freq_tbl(struct cpp_device *cpp_dev)
{
uint32_t msm_cpp_core_clk_idx;
int rc = 0;
msm_cpp_core_clk_idx = msm_cpp_get_clock_index(cpp_dev, "cpp_core_clk");
if (msm_cpp_core_clk_idx < 0) {
pr_err("%s: fail to get clock index\n", __func__);
rc = msm_cpp_core_clk_idx;
return rc;
}
rc = cpp_get_clk_freq_tbl(cpp_dev->cpp_clk[msm_cpp_core_clk_idx],
&cpp_dev->hw_info, cpp_dev->min_clk_rate);
if (rc < 0) {
pr_err("%s: fail to get frequency table\n", __func__);
return rc;
}
return rc;
}
long msm_cpp_set_core_clk(struct cpp_device *cpp_dev, long rate, int idx)
{
long rc = 0;
rc = msm_camera_clk_set_rate(&cpp_dev->pdev->dev,
cpp_dev->cpp_clk[idx], rate);
if (rc < 0) {
pr_err("%s: fail to get frequency table\n", __func__);
return rc;
}
return rc;
}
int msm_cpp_read_payload_params_from_dt(struct cpp_device *cpp_dev)
{
struct platform_device *pdev = cpp_dev->pdev;
struct device_node *fw_info_node = NULL, *dev_node = NULL;
char *key = "qcom,cpp-fw-payload-info";
struct msm_cpp_payload_params *payload_params;
int ret = 0;
if (!pdev || !pdev->dev.of_node) {
pr_err("%s: Invalid platform device/node\n", __func__);
ret = -ENODEV;
goto no_cpp_node;
}
dev_node = pdev->dev.of_node;
fw_info_node = of_find_node_by_name(dev_node, key);
if (!fw_info_node) {
ret = -ENODEV;
goto no_binding;
}
payload_params = &cpp_dev->payload_params;
memset(payload_params, 0x0, sizeof(struct msm_cpp_payload_params));
do {
CPP_DT_READ_U32_ERR(fw_info_node, key, "qcom,stripe-base", ret,
payload_params->stripe_base);
CPP_DT_READ_U32_ERR(fw_info_node, key, "qcom,plane-base", ret,
payload_params->plane_base);
CPP_DT_READ_U32_ERR(fw_info_node, key, "qcom,stripe-size", ret,
payload_params->stripe_size);
CPP_DT_READ_U32_ERR(fw_info_node, key, "qcom,plane-size", ret,
payload_params->plane_size);
CPP_DT_READ_U32_ERR(fw_info_node, key, "qcom,fe-ptr-off", ret,
payload_params->rd_pntr_off);
CPP_DT_READ_U32_ERR(fw_info_node, key, "qcom,we-ptr-off", ret,
payload_params->wr_0_pntr_off);
CPP_DT_READ_U32(fw_info_node, "qcom,ref-fe-ptr-off",
payload_params->rd_ref_pntr_off);
CPP_DT_READ_U32(fw_info_node, "qcom,ref-we-ptr-off",
payload_params->wr_ref_pntr_off);
CPP_DT_READ_U32(fw_info_node, "qcom,we-meta-ptr-off",
payload_params->wr_0_meta_data_wr_pntr_off);
CPP_DT_READ_U32(fw_info_node, "qcom,fe-mmu-pf-ptr-off",
payload_params->fe_mmu_pf_ptr_off);
CPP_DT_READ_U32(fw_info_node, "qcom,ref-fe-mmu-pf-ptr-off",
payload_params->ref_fe_mmu_pf_ptr_off);
CPP_DT_READ_U32(fw_info_node, "qcom,we-mmu-pf-ptr-off",
payload_params->we_mmu_pf_ptr_off);
CPP_DT_READ_U32(fw_info_node, "qcom,dup-we-mmu-pf-ptr-off",
payload_params->dup_we_mmu_pf_ptr_off);
CPP_DT_READ_U32(fw_info_node, "qcom,ref-we-mmu-pf-ptr-off",
payload_params->ref_we_mmu_pf_ptr_off);
CPP_DT_READ_U32(fw_info_node, "qcom,set-group-buffer-len",
payload_params->set_group_buffer_len);
CPP_DT_READ_U32(fw_info_node, "qcom,dup-frame-indicator-off",
payload_params->dup_frame_indicator_off);
} while (0);
no_binding:
if (ret)
pr_err("%s: Error reading binding %s, ret %d\n",
__func__, key, ret);
no_cpp_node:
return ret;
}

View file

@ -0,0 +1,3 @@
ccflags-y += -Idrivers/media/platform/msm/ais
ccflags-y += -Idrivers/media/platform/msm/ais/sensor/io
obj-$(CONFIG_MSM_AIS) += msm_vpe.o

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,258 @@
/* Copyright (c) 2013-2017, 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_VPE_H__
#define __MSM_VPE_H__
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <media/v4l2-fh.h>
#include <media/v4l2-subdev.h>
#include "msm_sd.h"
/*********** start of register offset *********************/
#define VPE_INTR_ENABLE_OFFSET 0x0020
#define VPE_INTR_STATUS_OFFSET 0x0024
#define VPE_INTR_CLEAR_OFFSET 0x0028
#define VPE_DL0_START_OFFSET 0x0030
#define VPE_HW_VERSION_OFFSET 0x0070
#define VPE_SW_RESET_OFFSET 0x0074
#define VPE_AXI_RD_ARB_CONFIG_OFFSET 0x0078
#define VPE_SEL_CLK_OR_HCLK_TEST_BUS_OFFSET 0x007C
#define VPE_CGC_EN_OFFSET 0x0100
#define VPE_CMD_STATUS_OFFSET 0x10008
#define VPE_PROFILE_EN_OFFSET 0x10010
#define VPE_PROFILE_COUNT_OFFSET 0x10014
#define VPE_CMD_MODE_OFFSET 0x10060
#define VPE_SRC_SIZE_OFFSET 0x10108
#define VPE_SRCP0_ADDR_OFFSET 0x1010C
#define VPE_SRCP1_ADDR_OFFSET 0x10110
#define VPE_SRC_YSTRIDE1_OFFSET 0x1011C
#define VPE_SRC_FORMAT_OFFSET 0x10124
#define VPE_SRC_UNPACK_PATTERN1_OFFSET 0x10128
#define VPE_OP_MODE_OFFSET 0x10138
#define VPE_SCALE_PHASEX_INIT_OFFSET 0x1013C
#define VPE_SCALE_PHASEY_INIT_OFFSET 0x10140
#define VPE_SCALE_PHASEX_STEP_OFFSET 0x10144
#define VPE_SCALE_PHASEY_STEP_OFFSET 0x10148
#define VPE_OUT_FORMAT_OFFSET 0x10150
#define VPE_OUT_PACK_PATTERN1_OFFSET 0x10154
#define VPE_OUT_SIZE_OFFSET 0x10164
#define VPE_OUTP0_ADDR_OFFSET 0x10168
#define VPE_OUTP1_ADDR_OFFSET 0x1016C
#define VPE_OUT_YSTRIDE1_OFFSET 0x10178
#define VPE_OUT_XY_OFFSET 0x1019C
#define VPE_SRC_XY_OFFSET 0x10200
#define VPE_SRC_IMAGE_SIZE_OFFSET 0x10208
#define VPE_SCALE_CONFIG_OFFSET 0x10230
#define VPE_DEINT_STATUS_OFFSET 0x30000
#define VPE_DEINT_DECISION_OFFSET 0x30004
#define VPE_DEINT_COEFF0_OFFSET 0x30010
#define VPE_SCALE_STATUS_OFFSET 0x50000
#define VPE_SCALE_SVI_PARAM_OFFSET 0x50010
#define VPE_SCALE_SHARPEN_CFG_OFFSET 0x50020
#define VPE_SCALE_COEFF_LSP_0_OFFSET 0x50400
#define VPE_SCALE_COEFF_MSP_0_OFFSET 0x50404
#define VPE_AXI_ARB_1_OFFSET 0x00408
#define VPE_AXI_ARB_2_OFFSET 0x0040C
#define VPE_SCALE_COEFF_LSBn(n) (0x50400 + 8 * (n))
#define VPE_SCALE_COEFF_MSBn(n) (0x50404 + 8 * (n))
#define VPE_SCALE_COEFF_NUM 32
#define VPE_SCALE_COEFF_MAX_N 127
/*********** end of register offset ********************/
#define VPE_HARDWARE_VERSION 0x00080308
#define VPE_SW_RESET_VALUE 0x00000010 /* bit 4 for PPP*/
#define VPE_AXI_RD_ARB_CONFIG_VALUE 0x124924
#define VPE_CMD_MODE_VALUE 0x1
#define VPE_DEFAULT_OP_MODE_VALUE 0x40FC0004
#define VPE_CGC_ENABLE_VALUE 0xffff
#define VPE_DEFAULT_SCALE_CONFIG 0x3c
#define VPE_NORMAL_MODE_CLOCK_RATE 150000000
#define VPE_TURBO_MODE_CLOCK_RATE 200000000
#define VPE_SUBDEV_MAX_EVENTS 30
/**************************************************/
/*********** End of command id ********************/
/**************************************************/
#define SCALER_PHASE_BITS 29
#define HAL_MDP_PHASE_STEP_2P50 0x50000000
#define HAL_MDP_PHASE_STEP_1P66 0x35555555
#define HAL_MDP_PHASE_STEP_1P25 0x28000000
#define MAX_ACTIVE_VPE_INSTANCE 8
#define MAX_VPE_PROCESSING_FRAME 2
#define MAX_VPE_V4l2_EVENTS 30
#define MSM_VPE_TASKLETQ_SIZE 16
/**
* The format of the msm_vpe_transaction_setup_cfg is as follows:
*
* - vpe_update_scale_coef (65*4 uint32_t's)
* - Each table is 65 uint32_t's long
* - 1st uint32_t in each table indicates offset
* - Following 64 uint32_t's are the data
*
* - vpe_input_plane_config (6 uint32_t's)
* - VPE_SRC_FORMAT_OFFSET
* - VPE_SRC_UNPACK_PATTERN1_OFFSET
* - VPE_SRC_IMAGE_SIZE_OFFSET
* - VPE_SRC_YSTRIDE1_OFFSET
* - VPE_SRC_SIZE_OFFSET
* - VPE_SRC_XY_OFFSET
*
* - vpe_output_plane_config (5 uint32_t's)
* - VPE_OUT_FORMAT_OFFSET
* - VPE_OUT_PACK_PATTERN1_OFFSET
* - VPE_OUT_YSTRIDE1_OFFSET
* - VPE_OUT_SIZE_OFFSET
* - VPE_OUT_XY_OFFSET
*
* - vpe_operation_config (1 uint32_t)
* - VPE_OP_MODE_OFFSET
*
*/
#define VPE_SCALER_CONFIG_LEN 260
#define VPE_INPUT_PLANE_CFG_LEN 24
#define VPE_OUTPUT_PLANE_CFG_LEN 20
#define VPE_OPERATION_MODE_CFG_LEN 4
#define VPE_NUM_SCALER_TABLES 4
#define VPE_TRANSACTION_SETUP_CONFIG_LEN ( \
(VPE_SCALER_CONFIG_LEN * VPE_NUM_SCALER_TABLES) \
+ VPE_INPUT_PLANE_CFG_LEN \
+ VPE_OUTPUT_PLANE_CFG_LEN \
+ VPE_OPERATION_MODE_CFG_LEN)
/* VPE_TRANSACTION_SETUP_CONFIG_LEN = 1088 */
struct msm_vpe_transaction_setup_cfg {
uint8_t scaler_cfg[VPE_TRANSACTION_SETUP_CONFIG_LEN];
};
struct vpe_subscribe_info {
struct v4l2_fh *vfh;
uint32_t active;
};
enum vpe_state {
VPE_STATE_BOOT,
VPE_STATE_IDLE,
VPE_STATE_ACTIVE,
VPE_STATE_OFF,
};
struct msm_queue_cmd {
struct list_head list_config;
struct list_head list_control;
struct list_head list_frame;
struct list_head list_pict;
struct list_head list_vpe_frame;
struct list_head list_eventdata;
void *command;
atomic_t on_heap;
struct timespec ts;
uint32_t error_code;
uint32_t trans_code;
};
struct msm_device_queue {
struct list_head list;
spinlock_t lock;
wait_queue_head_t wait;
int max;
int len;
const char *name;
};
struct msm_vpe_tasklet_queue_cmd {
struct list_head list;
uint32_t irq_status;
uint8_t cmd_used;
};
struct msm_vpe_buffer_map_info_t {
unsigned long len;
dma_addr_t phy_addr;
struct dma_buf *dbuf;
struct dma_buf_attachment *attachment;
struct sg_table *table;
struct msm_vpe_buffer_info_t buff_info;
};
struct msm_vpe_buffer_map_list_t {
struct msm_vpe_buffer_map_info_t map_info;
struct list_head entry;
};
struct msm_vpe_buff_queue_info_t {
uint32_t used;
uint16_t session_id;
uint16_t stream_id;
struct list_head vb2_buff_head;
struct list_head native_buff_head;
};
struct vpe_device {
struct platform_device *pdev;
struct msm_sd_subdev msm_sd;
struct v4l2_subdev subdev;
struct resource *mem;
struct resource *irq;
void __iomem *base;
struct clk **vpe_clk;
struct regulator *fs_vpe;
struct mutex mutex;
enum vpe_state state;
int domain_num;
struct iommu_domain *domain;
struct device *iommu_ctx_src;
struct device *iommu_ctx_dst;
struct ion_client *client;
struct kref refcount;
/* Reusing proven tasklet from msm isp */
atomic_t irq_cnt;
uint8_t taskletq_idx;
spinlock_t tasklet_lock;
struct list_head tasklet_q;
struct tasklet_struct vpe_tasklet;
struct msm_vpe_tasklet_queue_cmd
tasklet_queue_cmd[MSM_VPE_TASKLETQ_SIZE];
struct vpe_subscribe_info vpe_subscribe_list[MAX_ACTIVE_VPE_INSTANCE];
uint32_t vpe_open_cnt;
struct msm_device_queue eventData_q; /* V4L2 Event Payload Queue */
/*
* Processing Queue: store frame info for frames sent to
* microcontroller
*/
struct msm_device_queue processing_q;
struct msm_vpe_buff_queue_info_t *buff_queue;
uint32_t num_buffq;
struct v4l2_subdev *buf_mgr_subdev;
};
#endif /* __MSM_VPE_H__ */

View file

@ -0,0 +1,8 @@
ccflags-y += -Idrivers/media/platform/msm/ais
ccflags-y += -Idrivers/media/platform/msm/ais/common
ccflags-y += -Idrivers/media/platform/msm/ais/msm_vb2
ccflags-y += -Idrivers/media/platform/msm/ais/camera
ccflags-y += -Idrivers/media/platform/msm/ais/sensor/io
ccflags-y += -Idrivers/media/platform/msm/ais/sensor/cci
obj-$(CONFIG_MSM_AIS) += cci/ io/ csiphy/ csid/ actuator/ eeprom/ ois/ flash/ ir_led/ ir_cut/
obj-$(CONFIG_MSM_AIS_CAMERA_SENSOR) += msm_sensor_init.o msm_sensor_driver.o msm_sensor.o

View file

@ -0,0 +1,5 @@
ccflags-y += -Idrivers/media/platform/msm/ais
ccflags-y += -Idrivers/media/platform/msm/ais/common
ccflags-y += -Idrivers/media/platform/msm/ais/sensor/io
ccflags-y += -Idrivers/media/platform/msm/ais/sensor/cci
obj-$(CONFIG_MSM_AIS) += msm_actuator.o

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,114 @@
/* Copyright (c) 2011-2017, 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_ACTUATOR_H
#define MSM_ACTUATOR_H
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <soc/qcom/ais.h>
#include <media/v4l2-subdev.h>
#include <media/ais/msm_ais.h>
#include "msm_camera_i2c.h"
#include "msm_camera_dt_util.h"
#include "msm_camera_io_util.h"
#define DEFINE_MSM_MUTEX(mutexname) \
static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)
#define MSM_ACTUATOR_MAX_VREGS (10)
#define ACTUATOR_MAX_POLL_COUNT 10
struct msm_actuator_ctrl_t;
enum msm_actuator_state_t {
ACT_ENABLE_STATE,
ACT_OPS_ACTIVE,
ACT_OPS_INACTIVE,
ACT_DISABLE_STATE,
};
struct msm_actuator_func_tbl {
int32_t (*actuator_i2c_write_b_af)(struct msm_actuator_ctrl_t *,
uint8_t,
uint8_t);
int32_t (*actuator_init_step_table)(struct msm_actuator_ctrl_t *,
struct msm_actuator_set_info_t *);
int32_t (*actuator_init_focus)(struct msm_actuator_ctrl_t *,
uint16_t, struct reg_settings_t *);
int32_t (*actuator_set_default_focus)(struct msm_actuator_ctrl_t *,
struct msm_actuator_move_params_t *);
int32_t (*actuator_move_focus)(struct msm_actuator_ctrl_t *,
struct msm_actuator_move_params_t *);
void (*actuator_parse_i2c_params)(struct msm_actuator_ctrl_t *,
int16_t, uint32_t, uint16_t);
void (*actuator_write_focus)(struct msm_actuator_ctrl_t *,
uint16_t,
struct damping_params_t *,
int8_t,
int16_t);
int32_t (*actuator_set_position)(struct msm_actuator_ctrl_t *,
struct msm_actuator_set_position_t *);
int32_t (*actuator_park_lens)(struct msm_actuator_ctrl_t *);
};
struct msm_actuator {
enum actuator_type act_type;
struct msm_actuator_func_tbl func_tbl;
};
struct msm_actuator_vreg {
struct camera_vreg_t *cam_vreg;
void *data[MSM_ACTUATOR_MAX_VREGS];
int num_vreg;
};
struct msm_actuator_ctrl_t {
struct i2c_driver *i2c_driver;
struct platform_driver *pdriver;
struct platform_device *pdev;
struct msm_camera_i2c_client i2c_client;
enum msm_camera_device_type_t act_device_type;
struct msm_sd_subdev msm_sd;
enum af_camera_name cam_name;
struct mutex *actuator_mutex;
struct msm_actuator_func_tbl *func_tbl;
enum msm_camera_i2c_data_type i2c_data_type;
struct v4l2_subdev sdev;
struct v4l2_subdev_ops *act_v4l2_subdev_ops;
int16_t curr_step_pos;
uint16_t curr_region_index;
uint16_t *step_position_table;
struct region_params_t region_params[MAX_ACTUATOR_REGION];
uint16_t reg_tbl_size;
struct msm_actuator_reg_params_t reg_tbl[MAX_ACTUATOR_REG_TBL_SIZE];
uint16_t region_size;
void *user_data;
uint32_t total_steps;
uint16_t pwd_step;
uint16_t initial_code;
struct msm_camera_i2c_reg_array *i2c_reg_tbl;
uint16_t i2c_tbl_index;
enum cci_i2c_master_t cci_master;
uint32_t subdev_id;
enum msm_actuator_state_t actuator_state;
struct msm_actuator_vreg vreg_cfg;
struct park_lens_data_t park_lens;
uint32_t max_code_size;
struct msm_camera_gpio_conf *gconf;
struct msm_pinctrl_info pinctrl_info;
uint8_t cam_pinctrl_status;
};
#endif

View file

@ -0,0 +1,4 @@
ccflags-y += -Idrivers/media/platform/msm/ais
ccflags-y += -Idrivers/media/platform/msm/ais/common
ccflags-y += -Idrivers/media/platform/msm/ais/sensor/io
obj-$(CONFIG_MSM_AIS) += msm_cci.o

View file

@ -0,0 +1,69 @@
/* Copyright (c) 2012-2017, 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_CAM_CCI_HWREG__
#define __MSM_CAM_CCI_HWREG__
#define CCI_HW_VERSION_ADDR 0x00000000
#define CCI_RESET_CMD_ADDR 0x00000004
#define CCI_RESET_CMD_RMSK 0x0f73f3f7
#define CCI_M0_RESET_RMSK 0x3F1
#define CCI_M1_RESET_RMSK 0x3F001
#define CCI_QUEUE_START_ADDR 0x00000008
#define CCI_SET_CID_SYNC_TIMER_ADDR 0x00000010
#define CCI_SET_CID_SYNC_TIMER_OFFSET 0x00000004
#define CCI_I2C_M0_SCL_CTL_ADDR 0x00000100
#define CCI_I2C_M0_SDA_CTL_0_ADDR 0x00000104
#define CCI_I2C_M0_SDA_CTL_1_ADDR 0x00000108
#define CCI_I2C_M0_SDA_CTL_2_ADDR 0x0000010c
#define CCI_I2C_M0_READ_DATA_ADDR 0x00000118
#define CCI_I2C_M0_MISC_CTL_ADDR 0x00000110
#define CCI_I2C_M0_READ_BUF_LEVEL_ADDR 0x0000011C
#define CCI_HALT_REQ_ADDR 0x00000034
#define CCI_M0_HALT_REQ_RMSK 0x1
#define CCI_M1_HALT_REQ_RMSK 0x2
#define CCI_I2C_M1_SCL_CTL_ADDR 0x00000200
#define CCI_I2C_M1_SDA_CTL_0_ADDR 0x00000204
#define CCI_I2C_M1_SDA_CTL_1_ADDR 0x00000208
#define CCI_I2C_M1_SDA_CTL_2_ADDR 0x0000020c
#define CCI_I2C_M1_MISC_CTL_ADDR 0x00000210
#define CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR 0x00000304
#define CCI_I2C_M0_Q0_CUR_CMD_ADDR 0x00000308
#define CCI_I2C_M0_Q0_REPORT_STATUS_ADDR 0x0000030c
#define CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR 0x00000300
#define CCI_I2C_M0_Q0_LOAD_DATA_ADDR 0x00000310
#define CCI_IRQ_MASK_0_ADDR 0x00000c04
#define CCI_IRQ_MASK_0_RMSK 0x7fff7ff7
#define CCI_IRQ_CLEAR_0_ADDR 0x00000c08
#define CCI_IRQ_STATUS_0_ADDR 0x00000c0c
#define CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_HALT_ACK_BMSK 0x4000000
#define CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK_BMSK 0x2000000
#define CCI_IRQ_STATUS_0_RST_DONE_ACK_BMSK 0x1000000
#define CCI_IRQ_STATUS_0_I2C_M1_Q1_REPORT_BMSK 0x100000
#define CCI_IRQ_STATUS_0_I2C_M1_Q0_REPORT_BMSK 0x10000
#define CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK 0x1000
#define CCI_IRQ_STATUS_0_I2C_M0_Q1_REPORT_BMSK 0x100
#define CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT_BMSK 0x10
#define CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK 0x18000EE6
#define CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK 0x60EE6000
#define CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK 0x1
#define CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR 0x00000c00
#define DEBUG_TOP_REG_START 0x0
#define DEBUG_TOP_REG_COUNT 14
#define DEBUG_MASTER_REG_START 0x100
#define DEBUG_MASTER_REG_COUNT 8
#define DEBUG_MASTER_QUEUE_REG_START 0x300
#define DEBUG_MASTER_QUEUE_REG_COUNT 6
#define DEBUG_INTR_REG_START 0xC00
#define DEBUG_INTR_REG_COUNT 7
#endif /* __MSM_CAM_CCI_HWREG__ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,231 @@
/* Copyright (c) 2012-2017, 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_CCI_H
#define MSM_CCI_H
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <media/v4l2-subdev.h>
#include <linux/workqueue.h>
#include <media/ais/msm_ais_sensor.h>
#include <soc/qcom/ais.h>
#include "msm_sd.h"
#include "cam_soc_api.h"
#define NUM_MASTERS 2
#define NUM_QUEUES 2
#define TRUE 1
#define FALSE 0
#define CCI_PINCTRL_STATE_DEFAULT "cci_default"
#define CCI_PINCTRL_STATE_SLEEP "cci_suspend"
#define CCI_NUM_CLK_MAX 16
#define CCI_NUM_CLK_CASES 5
#define CCI_CLK_SRC_NAME "cci_src_clk"
#define MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_10 10
#define MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_11 11
#define BURST_MIN_FREE_SIZE 8
enum cci_i2c_sync {
MSM_SYNC_DISABLE,
MSM_SYNC_ENABLE,
};
enum cci_i2c_queue_t {
QUEUE_0,
QUEUE_1,
QUEUE_INVALID,
};
struct msm_camera_cci_client {
struct v4l2_subdev *cci_subdev;
uint32_t freq;
enum i2c_freq_mode_t i2c_freq_mode;
enum cci_i2c_master_t cci_i2c_master;
uint16_t sid;
uint16_t cid;
uint32_t timeout;
uint16_t retries;
uint16_t id_map;
};
enum msm_cci_cmd_type {
MSM_CCI_INIT,
MSM_CCI_RELEASE,
MSM_CCI_SET_SID,
MSM_CCI_SET_FREQ,
MSM_CCI_SET_SYNC_CID,
MSM_CCI_I2C_READ,
MSM_CCI_I2C_WRITE,
MSM_CCI_I2C_WRITE_SEQ,
MSM_CCI_I2C_WRITE_ASYNC,
MSM_CCI_GPIO_WRITE,
MSM_CCI_I2C_WRITE_SYNC,
MSM_CCI_I2C_WRITE_SYNC_BLOCK,
};
struct msm_camera_cci_wait_sync_cfg {
uint16_t cid;
int16_t csid;
uint16_t line;
uint16_t delay;
};
struct msm_camera_cci_gpio_cfg {
uint16_t gpio_queue;
uint16_t i2c_queue;
};
struct msm_camera_cci_i2c_read_cfg {
uint32_t addr;
enum msm_camera_i2c_reg_addr_type addr_type;
uint8_t *data;
uint16_t num_byte;
};
struct msm_camera_cci_i2c_queue_info {
uint32_t max_queue_size;
uint32_t report_id;
uint32_t irq_en;
uint32_t capture_rep_data;
};
struct msm_camera_cci_ctrl {
int32_t status;
struct msm_camera_cci_client *cci_info;
enum msm_cci_cmd_type cmd;
union {
struct msm_camera_i2c_reg_setting cci_i2c_write_cfg;
struct msm_camera_cci_i2c_read_cfg cci_i2c_read_cfg;
struct msm_camera_cci_wait_sync_cfg cci_wait_sync_cfg;
struct msm_camera_cci_gpio_cfg gpio_cfg;
} cfg;
};
struct msm_camera_cci_master_info {
uint32_t status;
atomic_t q_free[NUM_QUEUES];
uint8_t q_lock[NUM_QUEUES];
uint8_t reset_pending;
struct mutex mutex;
struct completion reset_complete;
struct mutex mutex_q[NUM_QUEUES];
struct completion report_q[NUM_QUEUES];
atomic_t done_pending[NUM_QUEUES];
};
struct msm_cci_clk_params_t {
uint16_t hw_thigh;
uint16_t hw_tlow;
uint16_t hw_tsu_sto;
uint16_t hw_tsu_sta;
uint16_t hw_thd_dat;
uint16_t hw_thd_sta;
uint16_t hw_tbuf;
uint8_t hw_scl_stretch_en;
uint8_t hw_trdhld;
uint8_t hw_tsp;
uint32_t cci_clk_src;
};
enum msm_cci_state_t {
CCI_STATE_ENABLED,
CCI_STATE_DISABLED,
};
struct cci_device {
struct platform_device *pdev;
struct msm_sd_subdev msm_sd;
struct v4l2_subdev subdev;
struct resource *irq;
void __iomem *base;
uint32_t hw_version;
uint8_t ref_count;
enum msm_cci_state_t cci_state;
size_t num_clk;
size_t num_clk_cases;
struct clk **cci_clk;
uint32_t **cci_clk_rates;
struct msm_cam_clk_info *cci_clk_info;
struct msm_camera_cci_i2c_queue_info
cci_i2c_queue_info[NUM_MASTERS][NUM_QUEUES];
struct msm_camera_cci_master_info cci_master_info[NUM_MASTERS];
enum i2c_freq_mode_t i2c_freq_mode[NUM_MASTERS];
struct msm_cci_clk_params_t cci_clk_params[I2C_MAX_MODES];
struct gpio *cci_gpio_tbl;
uint8_t cci_gpio_tbl_size;
struct msm_pinctrl_info cci_pinctrl;
uint8_t cci_pinctrl_status;
uint32_t cycles_per_us;
uint32_t cci_clk_src;
struct camera_vreg_t *cci_vreg;
struct regulator *cci_reg_ptr[MAX_REGULATOR];
int32_t regulator_count;
uint8_t payload_size;
uint8_t support_seq_write;
struct workqueue_struct *write_wq[MASTER_MAX];
struct msm_camera_cci_wait_sync_cfg cci_wait_sync_cfg;
uint8_t valid_sync;
};
enum msm_cci_i2c_cmd_type {
CCI_I2C_SET_PARAM_CMD = 1,
CCI_I2C_WAIT_CMD,
CCI_I2C_WAIT_SYNC_CMD,
CCI_I2C_WAIT_GPIO_EVENT_CMD,
CCI_I2C_TRIG_I2C_EVENT_CMD,
CCI_I2C_LOCK_CMD,
CCI_I2C_UNLOCK_CMD,
CCI_I2C_REPORT_CMD,
CCI_I2C_WRITE_CMD,
CCI_I2C_READ_CMD,
CCI_I2C_WRITE_DISABLE_P_CMD,
CCI_I2C_READ_DISABLE_P_CMD,
CCI_I2C_WRITE_CMD2,
CCI_I2C_WRITE_CMD3,
CCI_I2C_REPEAT_CMD,
CCI_I2C_INVALID_CMD,
};
enum msm_cci_gpio_cmd_type {
CCI_GPIO_SET_PARAM_CMD = 1,
CCI_GPIO_WAIT_CMD,
CCI_GPIO_WAIT_SYNC_CMD,
CCI_GPIO_WAIT_GPIO_IN_EVENT_CMD,
CCI_GPIO_WAIT_I2C_Q_TRIG_EVENT_CMD,
CCI_GPIO_OUT_CMD,
CCI_GPIO_TRIG_EVENT_CMD,
CCI_GPIO_REPORT_CMD,
CCI_GPIO_REPEAT_CMD,
CCI_GPIO_CONTINUE_CMD,
CCI_GPIO_INVALID_CMD,
};
struct cci_write_async {
struct cci_device *cci_dev;
struct msm_camera_cci_ctrl c_ctrl;
enum cci_i2c_queue_t queue;
struct work_struct work;
enum cci_i2c_sync sync_en;
};
struct v4l2_subdev *msm_cci_get_subdev(void);
#define VIDIOC_MSM_CCI_CFG \
_IOWR('V', BASE_VIDIOC_PRIVATE + 23, struct msm_camera_cci_ctrl *)
#endif

View file

@ -0,0 +1,4 @@
ccflags-y += -Idrivers/media/platform/msm/ais
ccflags-y += -Idrivers/media/platform/msm/ais/common
ccflags-y += -Idrivers/media/platform/msm/ais/sensor/io
obj-$(CONFIG_MSM_AIS) += msm_csid.o

View file

@ -0,0 +1,65 @@
/* Copyright (c) 2014-2017, 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_CSID_2_0_HWREG_H
#define MSM_CSID_2_0_HWREG_H
#include <sensor/csid/msm_csid.h>
uint8_t csid_lane_assign_v2_0[PHY_LANE_MAX] = {0, 1, 2, 3, 4};
struct csid_reg_parms_t csid_v2_0 = {
/* MIPI CSID registers */
0x0,
0x4,
0x4,
0x8,
0xc,
0x10,
0x14,
0x18,
0x1C,
0x5c,
0x60,
0x64,
0x68,
0x6c,
0x70,
0x74,
0x78,
0x7C,
0x80,
0x84,
0x88,
0x8C,
0x90,
0x94,
0x9C,
0xA0,
0xA8,
0xAC,
0xB0,
11,
0x7FFF,
0x2,
17,
0x02000011,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0x7f010800,
20,
0xFFFFFFFF,
0xFFFFFFFF,
};
#endif

View file

@ -0,0 +1,64 @@
/* Copyright (c) 2014-2017, 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_CSID_2_2_HWREG_H
#define MSM_CSID_2_2_HWREG_H
#include <sensor/csid/msm_csid.h>
uint8_t csid_lane_assign_v2_2[PHY_LANE_MAX] = {0, 1, 2, 3, 4};
struct csid_reg_parms_t csid_v2_2 = {
/* MIPI CSID registers */
0x0,
0x4,
0x4,
0x8,
0xc,
0x10,
0x14,
0x18,
0x1C,
0x5c,
0x60,
0x64,
0x68,
0x6c,
0x70,
0x74,
0x78,
0x7C,
0x80,
0x84,
0x88,
0x8C,
0x90,
0x94,
0x9C,
0xA0,
0xA8,
0xAC,
0xB0,
11,
0x7FFF,
0x2,
17,
0x02001000,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0x7f010800,
20,
0xFFFFFFFF,
0xFFFFFFFF,
};
#endif

View file

@ -0,0 +1,64 @@
/* Copyright (c) 2014-2017, 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_CSID_3_0_HWREG_H
#define MSM_CSID_3_0_HWREG_H
#include <sensor/csid/msm_csid.h>
uint8_t csid_lane_assign_v3_0[PHY_LANE_MAX] = {0, 1, 2, 3, 4};
struct csid_reg_parms_t csid_v3_0 = {
/* MIPI CSID registers */
0x0,
0x4,
0x8,
0xC,
0x10,
0x14,
0x18,
0x1C,
0x20,
0x60,
0x64,
0x68,
0x6C,
0x70,
0x74,
0x78,
0x7C,
0x80,
0x84,
0x88,
0x8C,
0x90,
0x94,
0x98,
0xA0,
0xA4,
0xAC,
0xB0,
0xB4,
11,
0x7FFF,
0x4,
17,
0x30000000,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0x7f010800,
20,
0xFFFFFFFF,
0xFFFFFFFF,
};
#endif

View file

@ -0,0 +1,64 @@
/* Copyright (c) 2014-2017, 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_CSID_3_1_HWREG_H
#define MSM_CSID_3_1_HWREG_H
#include <sensor/csid/msm_csid.h>
uint8_t csid_lane_assign_v3_1[PHY_LANE_MAX] = {0, 1, 2, 3, 4};
struct csid_reg_parms_t csid_v3_1 = {
/* MIPI CSID registers */
0x0,
0x4,
0x8,
0xC,
0x10,
0x14,
0x18,
0x1C,
0x20,
0x60,
0x64,
0x68,
0x6C,
0x70,
0x74,
0x78,
0x7C,
0x80,
0x84,
0x88,
0x8C,
0x90,
0x94,
0x98,
0xA0,
0xA4,
0xAC,
0xB0,
0xB4,
11,
0x7FFF,
0x4,
17,
0x30010000,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0x7f010800,
20,
0xFFFFFFFF,
0xFFFFFFFF,
};
#endif

View file

@ -0,0 +1,64 @@
/* Copyright (c) 2014-2017, 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_CSID_3_2_HWREG_H
#define MSM_CSID_3_2_HWREG_H
#include <sensor/csid/msm_csid.h>
uint8_t csid_lane_assign_v3_2[PHY_LANE_MAX] = {0, 1, 2, 3, 4};
struct csid_reg_parms_t csid_v3_2 = {
/* MIPI CSID registers */
0x0,
0x4,
0x8,
0xC,
0x10,
0x14,
0x18,
0x1C,
0x20,
0x60,
0x64,
0x68,
0x6C,
0x70,
0x74,
0x78,
0x7C,
0x80,
0x84,
0x88,
0x8C,
0x90,
0x94,
0x98,
0xA0,
0xA4,
0xAC,
0xB0,
0xB4,
11,
0x7FFF,
0x4,
17,
0x30020000,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0x7f010800,
20,
0xFFFFFFFF,
0xFFFFFFFF,
};
#endif

View file

@ -0,0 +1,63 @@
/* Copyright (c) 2015-2017, 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_CSID_3_4_1_HWREG_H
#define MSM_CSID_3_4_1_HWREG_H
#include <sensor/csid/msm_csid.h>
uint8_t csid_lane_assign_v3_4_1[PHY_LANE_MAX] = {0, 1, 2, 3, 4};
struct csid_reg_parms_t csid_v3_4_1 = {
/* MIPI CSID registers */
0x0,
0x4,
0x8,
0xC,
0x10,
0x14,
0x18,
0x1C,
0x20,
0x60,
0x64,
0x68,
0x6C,
0x70,
0x74,
0x78,
0x7C,
0x80,
0x84,
0x88,
0x8C,
0x90,
0x94,
0x98,
0xA0,
0xA4,
0xAC,
0xB0,
0xB4,
11,
0x7FFF,
0x4,
17,
0x30040001,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0x7f010800,
20,
0xFFFFFFFF,
0xFFFFFFFF,
};
#endif

View file

@ -0,0 +1,63 @@
/* Copyright (c) 2015-2017, 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_CSID_3_4_2_HWREG_H
#define MSM_CSID_3_4_2_HWREG_H
#include <sensor/csid/msm_csid.h>
uint8_t csid_lane_assign_v3_4_2[PHY_LANE_MAX] = {0, 4, 1, 2, 3};
struct csid_reg_parms_t csid_v3_4_2 = {
/* MIPI CSID registers */
0x0,
0x4,
0x8,
0xC,
0x10,
0x14,
0x18,
0x1C,
0x20,
0x60,
0x64,
0x68,
0x6C,
0x70,
0x74,
0x78,
0x7C,
0x80,
0x84,
0x88,
0x8C,
0x90,
0x94,
0x98,
0xA0,
0xA4,
0xAC,
0xB0,
0xB4,
11,
0x7FFF,
0x4,
17,
0x30040002,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0x7f010800,
20,
0xFFFFFFFF,
0xFFFFFFFF,
};
#endif

View file

@ -0,0 +1,63 @@
/* Copyright (c) 2015-2017, 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_CSID_3_4_3_HWREG_H
#define MSM_CSID_3_4_3_HWREG_H
#include <sensor/csid/msm_csid.h>
uint8_t csid_lane_assign_v3_4_3[PHY_LANE_MAX] = {0, 4, 1, 2, 3};
struct csid_reg_parms_t csid_v3_4_3 = {
/* MIPI CSID registers */
0x0,
0x4,
0x8,
0xC,
0x10,
0x14,
0x18,
0x1C,
0x20,
0x60,
0x64,
0x68,
0x6C,
0x70,
0x74,
0x78,
0x7C,
0x80,
0x84,
0x88,
0x8C,
0x90,
0x94,
0x98,
0xA0,
0xA4,
0xAC,
0xB0,
0xB4,
11,
0x7FFF,
0x4,
17,
0x30040003,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0x7f010800,
20,
0xFFFFFFFF,
0xFFFFFFFF,
};
#endif

View file

@ -0,0 +1,64 @@
/* Copyright (c) 2015-2017, 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_CSID_3_5_1_HWREG_H
#define MSM_CSID_3_5_1_HWREG_H
#include <sensor/csid/msm_csid.h>
uint8_t csid_lane_assign_v3_5_1[PHY_LANE_MAX] = {0, 4, 1, 2, 3};
struct csid_reg_parms_t csid_v3_5_1 = {
/* MIPI CSID registers */
0x0,
0x4,
0x8,
0x10,
0x14,
0x18,
0x1C,
0x20,
0x24,
0x64,
0x68,
0x6C,
0x70,
0x74,
0x78,
0x7C,
0x80,
0x88,
0x8C,
0x90,
0x94,
0x98,
0x9C,
0xA0,
0xA8,
0xAC,
0xB4,
0xB8,
0xBC,
11,
0x7FFF,
0x4,
17,
0x30050001,
0xC,
0x84,
0xA4,
0x7f010800,
20,
17,
16,
};
#endif

View file

@ -0,0 +1,64 @@
/* Copyright (c) 2015-2017, 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_CSID_3_5_HWREG_H
#define MSM_CSID_3_5_HWREG_H
#include <sensor/csid/msm_csid.h>
uint8_t csid_lane_assign_v3_5[PHY_LANE_MAX] = {0, 4, 1, 2, 3};
struct csid_reg_parms_t csid_v3_5 = {
/* MIPI CSID registers */
0x0,
0x4,
0x8,
0x10,
0x14,
0x18,
0x1C,
0x20,
0x24,
0x64,
0x68,
0x6C,
0x70,
0x74,
0x78,
0x7C,
0x80,
0x88,
0x8C,
0x90,
0x94,
0x98,
0x9C,
0xA0,
0xA8,
0xAC,
0xB4,
0xB8,
0xBC,
11,
0x7FFF,
0x4,
17,
0x30050000,
0xC,
0x84,
0xA4,
0x7f010800,
20,
17,
16,
};
#endif

View file

@ -0,0 +1,63 @@
/* Copyright (c) 2015-2017, 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_CSID_3_6_0_HWREG_H
#define MSM_CSID_3_6_0_HWREG_H
#include <sensor/csid/msm_csid.h>
uint8_t csid_lane_assign_v3_6_0[PHY_LANE_MAX] = {0, 1, 2, 3, 4};
struct csid_reg_parms_t csid_v3_6_0 = {
/* MIPI CSID registers */
0x0,
0x4,
0x8,
0xC,
0x10,
0x14,
0x18,
0x1C,
0x20,
0x60,
0x64,
0x68,
0x6C,
0x70,
0x74,
0x78,
0x7C,
0x80,
0x84,
0x88,
0x8C,
0x90,
0x94,
0x98,
0xA0,
0xA4,
0xAC,
0xB0,
0xB4,
11,
0x7FFF,
0x4,
17,
0x30060000,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0x7f010800,
20,
0xFFFFFFFF,
0xFFFFFFFF,
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,124 @@
/* Copyright (c) 2011-2017, 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_CSID_H
#define MSM_CSID_H
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <media/v4l2-subdev.h>
#include <media/ais/msm_ais_sensor.h>
#include "msm_sd.h"
#include "cam_soc_api.h"
#define CSID_SOF_DEBUG_COUNT 3
enum csiphy_lane_assign {
PHY_LANE_D0,
PHY_LANE_CLK,
PHY_LANE_D1,
PHY_LANE_D2,
PHY_LANE_D3,
PHY_LANE_MAX,
};
struct csid_reg_parms_t {
/* MIPI CSID registers */
uint32_t csid_hw_version_addr;
uint32_t csid_core_ctrl_0_addr;
uint32_t csid_core_ctrl_1_addr;
uint32_t csid_rst_cmd_addr;
uint32_t csid_cid_lut_vc_0_addr;
uint32_t csid_cid_lut_vc_1_addr;
uint32_t csid_cid_lut_vc_2_addr;
uint32_t csid_cid_lut_vc_3_addr;
uint32_t csid_cid_n_cfg_addr;
uint32_t csid_irq_clear_cmd_addr;
uint32_t csid_irq_mask_addr;
uint32_t csid_irq_status_addr;
uint32_t csid_captured_unmapped_long_pkt_hdr_addr;
uint32_t csid_captured_mmaped_long_pkt_hdr_addr;
uint32_t csid_captured_short_pkt_addr;
uint32_t csid_captured_long_pkt_hdr_addr;
uint32_t csid_captured_long_pkt_ftr_addr;
uint32_t csid_pif_misr_dl0_addr;
uint32_t csid_pif_misr_dl1_addr;
uint32_t csid_pif_misr_dl2_addr;
uint32_t csid_pif_misr_dl3_addr;
uint32_t csid_stats_total_pkts_rcvd_addr;
uint32_t csid_stats_ecc_addr;
uint32_t csid_stats_crc_addr;
uint32_t csid_tg_ctrl_addr;
uint32_t csid_tg_vc_cfg_addr;
uint32_t csid_tg_dt_n_cfg_0_addr;
uint32_t csid_tg_dt_n_cfg_1_addr;
uint32_t csid_tg_dt_n_cfg_2_addr;
uint32_t csid_rst_done_irq_bitshift;
uint32_t csid_rst_stb_all;
uint32_t csid_dl_input_sel_shift;
uint32_t csid_phy_sel_shift;
uint32_t csid_version;
uint32_t csid_3p_ctrl_0_addr;
uint32_t csid_3p_pkt_hdr_addr;
uint32_t csid_test_bus_ctrl;
uint32_t csid_irq_mask_val;
uint32_t csid_err_lane_overflow_offset_2p;
uint32_t csid_err_lane_overflow_offset_3p;
uint32_t csid_phy_sel_shift_3p;
};
struct csid_ctrl_t {
struct csid_reg_parms_t csid_reg;
uint8_t *csid_lane_assign;
};
enum msm_csid_state_t {
CSID_POWER_UP,
CSID_POWER_DOWN,
};
struct csid_device {
struct platform_device *pdev;
struct msm_sd_subdev msm_sd;
struct resource *irq;
struct regulator *csi_vdd;
void __iomem *base;
struct mutex mutex;
struct completion reset_complete;
uint32_t hw_version;
uint32_t hw_dts_version;
enum msm_csid_state_t csid_state;
struct csid_ctrl_t *ctrl_reg;
struct regulator *reg_ptr;
size_t num_clk;
struct clk **csid_clk;
struct msm_cam_clk_info *csid_clk_info;
uint32_t csid_clk_index;
uint32_t csid_max_clk;
uint32_t csid_3p_enabled;
struct camera_vreg_t *csid_vreg;
struct regulator *csid_reg_ptr[MAX_REGULATOR];
int32_t regulator_count;
uint8_t is_testmode;
struct msm_camera_csid_testmode_parms testmode_params;
struct msm_camera_csid_params current_csid_params;
uint32_t csid_sof_debug;
uint32_t csid_lane_cnt;
uint32_t csid_sof_debug_count;
void *csiphy_dev;
};
#define VIDIOC_MSM_CSID_RELEASE \
_IOWR('V', BASE_VIDIOC_PRIVATE + 12, struct v4l2_subdev*)
#endif

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