* [PATCH 5/5 v4] V4L/DVB: s5p-fimc: Add camera capture support
From: Sylwester Nawrocki @ 2010-10-08 8:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1286527837-4980-1-git-send-email-s.nawrocki@samsung.com>
Add a video device driver per each FIMC entity to support
the camera capture input mode. Video capture node is registered
only if CCD sensor data is provided through driver's platfrom data
and board setup code.
Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Reviewed-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
drivers/media/video/s5p-fimc/Makefile | 2 +-
drivers/media/video/s5p-fimc/fimc-capture.c | 816 +++++++++++++++++++++++++++
drivers/media/video/s5p-fimc/fimc-core.c | 585 ++++++++++++++------
drivers/media/video/s5p-fimc/fimc-core.h | 205 +++++++-
drivers/media/video/s5p-fimc/fimc-reg.c | 173 ++++++-
include/media/s3c_fimc.h | 60 ++
6 files changed, 1649 insertions(+), 192 deletions(-)
create mode 100644 drivers/media/video/s5p-fimc/fimc-capture.c
create mode 100644 include/media/s3c_fimc.h
diff --git a/drivers/media/video/s5p-fimc/Makefile b/drivers/media/video/s5p-fimc/Makefile
index 0d9d541..7ea1b14 100644
--- a/drivers/media/video/s5p-fimc/Makefile
+++ b/drivers/media/video/s5p-fimc/Makefile
@@ -1,3 +1,3 @@
obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) := s5p-fimc.o
-s5p-fimc-y := fimc-core.o fimc-reg.o
+s5p-fimc-y := fimc-core.o fimc-reg.o fimc-capture.o
diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c
new file mode 100644
index 0000000..b224ca9
--- /dev/null
+++ b/drivers/media/video/s5p-fimc/fimc-capture.c
@@ -0,0 +1,816 @@
+/*
+ * Samsung S5P SoC series camera interface (camera capture) driver
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd
+ * Author: Sylwester Nawrocki, <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/bug.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/i2c.h>
+
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf-core.h>
+#include <media/videobuf-dma-contig.h>
+
+#include "fimc-core.h"
+
+static struct v4l2_subdev *fimc_subdev_register(struct fimc_dev *fimc,
+ struct s3c_fimc_isp_info *isp_info)
+{
+ struct i2c_adapter *i2c_adap;
+ struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
+ struct v4l2_subdev *sd = NULL;
+
+ i2c_adap = i2c_get_adapter(isp_info->i2c_bus_num);
+ if (!i2c_adap)
+ return ERR_PTR(-ENOMEM);
+
+ sd = v4l2_i2c_new_subdev_board(&vid_cap->v4l2_dev, i2c_adap,
+ MODULE_NAME, isp_info->board_info, NULL);
+ if (!sd) {
+ v4l2_err(&vid_cap->v4l2_dev, "failed to acquire subdev\n");
+ return NULL;
+ }
+
+ v4l2_info(&vid_cap->v4l2_dev, "subdevice %s registered successfuly\n",
+ isp_info->board_info->type);
+
+ return sd;
+}
+
+static void fimc_subdev_unregister(struct fimc_dev *fimc)
+{
+ struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
+ struct i2c_client *client;
+
+ if (vid_cap->input_index < 0)
+ return; /* Subdevice already released or not registered. */
+
+ if (vid_cap->sd) {
+ v4l2_device_unregister_subdev(vid_cap->sd);
+ client = v4l2_get_subdevdata(vid_cap->sd);
+ i2c_unregister_device(client);
+ i2c_put_adapter(client->adapter);
+ vid_cap->sd = NULL;
+ }
+
+ vid_cap->input_index = -1;
+}
+
+/**
+ * fimc_subdev_attach - attach v4l2_subdev to camera host interface
+ *
+ * @fimc: FIMC device information
+ * @index: index to the array of available subdevices,
+ * -1 for full array search or non negative value
+ * to select specific subdevice
+ */
+static int fimc_subdev_attach(struct fimc_dev *fimc, int index)
+{
+ struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
+ struct s3c_platform_fimc *pdata = fimc->pdata;
+ struct s3c_fimc_isp_info *isp_info;
+ struct v4l2_subdev *sd;
+ int i;
+
+ for (i = 0; i < FIMC_MAX_CAMIF_CLIENTS; ++i) {
+ isp_info = pdata->isp_info[i];
+
+ if (!isp_info || (index >= 0 && i != index))
+ continue;
+
+ sd = fimc_subdev_register(fimc, isp_info);
+ if (sd) {
+ vid_cap->sd = sd;
+ vid_cap->input_index = i;
+
+ return 0;
+ }
+ }
+
+ vid_cap->input_index = -1;
+ vid_cap->sd = NULL;
+ v4l2_err(&vid_cap->v4l2_dev, "fimc%d: sensor attach failed\n",
+ fimc->id);
+ return -ENODEV;
+}
+
+static int fimc_isp_subdev_init(struct fimc_dev *fimc, int index)
+{
+ struct s3c_fimc_isp_info *isp_info;
+ int ret;
+
+ ret = fimc_subdev_attach(fimc, index);
+ if (ret)
+ return ret;
+
+ isp_info = fimc->pdata->isp_info[fimc->vid_cap.input_index];
+ ret = fimc_hw_set_camera_polarity(fimc, isp_info);
+ if (!ret) {
+ ret = v4l2_subdev_call(fimc->vid_cap.sd, core,
+ s_power, 1);
+ if (!ret)
+ return ret;
+ }
+
+ fimc_subdev_unregister(fimc);
+ err("ISP initialization failed: %d", ret);
+ return ret;
+}
+
+/*
+ * At least one buffer on the pending_buf_q queue is required.
+ * Locking: The caller holds fimc->slock spinlock.
+ */
+int fimc_vid_cap_buf_queue(struct fimc_dev *fimc,
+ struct fimc_vid_buffer *fimc_vb)
+{
+ struct fimc_vid_cap *cap = &fimc->vid_cap;
+ struct fimc_ctx *ctx = cap->ctx;
+ int ret = 0;
+
+ BUG_ON(!fimc || !fimc_vb);
+
+ ret = fimc_prepare_addr(ctx, fimc_vb, &ctx->d_frame,
+ &fimc_vb->paddr);
+ if (ret)
+ return ret;
+
+ if (test_bit(ST_CAPT_STREAM, &fimc->state)) {
+ fimc_pending_queue_add(cap, fimc_vb);
+ } else {
+ /* Setup the buffer directly for processing. */
+ int buf_id = (cap->reqbufs_count == 1) ? -1 : cap->buf_index;
+ fimc_hw_set_output_addr(fimc, &fimc_vb->paddr, buf_id);
+
+ fimc_vb->index = cap->buf_index;
+ active_queue_add(cap, fimc_vb);
+
+ if (++cap->buf_index >= FIMC_MAX_OUT_BUFS)
+ cap->buf_index = 0;
+ }
+ return ret;
+}
+
+static int fimc_stop_capture(struct fimc_dev *fimc)
+{
+ unsigned long flags;
+ struct fimc_vid_cap *cap;
+ int ret;
+
+ cap = &fimc->vid_cap;
+
+ if (!fimc_capture_active(fimc))
+ return 0;
+
+ spin_lock_irqsave(&fimc->slock, flags);
+ set_bit(ST_CAPT_SHUT, &fimc->state);
+ fimc_deactivate_capture(fimc);
+ spin_unlock_irqrestore(&fimc->slock, flags);
+
+ wait_event_timeout(fimc->irq_queue,
+ test_bit(ST_CAPT_SHUT, &fimc->state),
+ FIMC_SHUTDOWN_TIMEOUT);
+
+ ret = v4l2_subdev_call(cap->sd, video, s_stream, 0);
+ if (ret)
+ v4l2_err(&fimc->vid_cap.v4l2_dev, "s_stream(0) failed\n");
+
+ spin_lock_irqsave(&fimc->slock, flags);
+ fimc->state &= ~(1 << ST_CAPT_RUN | 1 << ST_CAPT_PEND |
+ 1 << ST_CAPT_STREAM);
+
+ fimc->vid_cap.active_buf_cnt = 0;
+ spin_unlock_irqrestore(&fimc->slock, flags);
+
+ dbg("state: 0x%lx", fimc->state);
+ return 0;
+}
+
+static int fimc_capture_open(struct file *file)
+{
+ struct fimc_dev *fimc = video_drvdata(file);
+ int ret = 0;
+
+ dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state);
+
+ /* Return if the corresponding video mem2mem node is already opened. */
+ if (fimc_m2m_active(fimc))
+ return -EBUSY;
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ if (++fimc->vid_cap.refcnt == 1) {
+ ret = fimc_isp_subdev_init(fimc, -1);
+ if (ret) {
+ fimc->vid_cap.refcnt--;
+ ret = -EIO;
+ }
+ }
+
+ file->private_data = fimc->vid_cap.ctx;
+
+ mutex_unlock(&fimc->lock);
+ return ret;
+}
+
+static int fimc_capture_close(struct file *file)
+{
+ struct fimc_dev *fimc = video_drvdata(file);
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state);
+
+ if (--fimc->vid_cap.refcnt == 0) {
+ fimc_stop_capture(fimc);
+
+ videobuf_stop(&fimc->vid_cap.vbq);
+ videobuf_mmap_free(&fimc->vid_cap.vbq);
+
+ v4l2_err(&fimc->vid_cap.v4l2_dev, "releasing ISP\n");
+ v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 0);
+ fimc_subdev_unregister(fimc);
+ }
+
+ mutex_unlock(&fimc->lock);
+ return 0;
+}
+
+static unsigned int fimc_capture_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct fimc_ctx *ctx = file->private_data;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct fimc_vid_cap *cap = &fimc->vid_cap;
+ int ret;
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return POLLERR;
+
+ ret = videobuf_poll_stream(file, &cap->vbq, wait);
+ mutex_unlock(&fimc->lock);
+
+ return ret;
+}
+
+static int fimc_capture_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct fimc_ctx *ctx = file->private_data;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct fimc_vid_cap *cap = &fimc->vid_cap;
+ int ret;
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ ret = videobuf_mmap_mapper(&cap->vbq, vma);
+ mutex_unlock(&fimc->lock);
+
+ return ret;
+}
+
+/* video device file operations */
+static const struct v4l2_file_operations fimc_capture_fops = {
+ .owner = THIS_MODULE,
+ .open = fimc_capture_open,
+ .release = fimc_capture_close,
+ .poll = fimc_capture_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = fimc_capture_mmap,
+};
+
+static int fimc_vidioc_querycap_capture(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct fimc_ctx *ctx = file->private_data;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+
+ strncpy(cap->driver, fimc->pdev->name, sizeof(cap->driver) - 1);
+ strncpy(cap->card, fimc->pdev->name, sizeof(cap->card) - 1);
+ cap->bus_info[0] = 0;
+ cap->version = KERNEL_VERSION(1, 0, 0);
+ cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE;
+
+ return 0;
+}
+
+/* Synchronize formats of the camera interface input and attached sensor. */
+static int sync_capture_fmt(struct fimc_ctx *ctx)
+{
+ struct fimc_frame *frame = &ctx->s_frame;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct v4l2_mbus_framefmt *fmt = &fimc->vid_cap.fmt;
+ int ret;
+
+ fmt->width = ctx->d_frame.o_width;
+ fmt->height = ctx->d_frame.o_height;
+
+ ret = v4l2_subdev_call(fimc->vid_cap.sd, video, s_mbus_fmt, fmt);
+ if (ret == -ENOIOCTLCMD) {
+ err("s_mbus_fmt failed");
+ return ret;
+ }
+ dbg("w: %d, h: %d, code= %d", fmt->width, fmt->height, fmt->code);
+
+ frame->fmt = find_mbus_format(fmt, FMT_FLAGS_CAM);
+ if (!frame->fmt) {
+ err("fimc source format not found\n");
+ return -EINVAL;
+ }
+
+ frame->f_width = fmt->width;
+ frame->f_height = fmt->height;
+ frame->width = fmt->width;
+ frame->height = fmt->height;
+ frame->o_width = fmt->width;
+ frame->o_height = fmt->height;
+ frame->offs_h = 0;
+ frame->offs_v = 0;
+
+ return 0;
+}
+
+static int fimc_cap_s_fmt(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct fimc_ctx *ctx = priv;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct fimc_frame *frame;
+ struct v4l2_pix_format *pix;
+ int ret;
+
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ ret = fimc_vidioc_try_fmt(file, priv, f);
+ if (ret)
+ return ret;
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ if (fimc_capture_active(fimc)) {
+ ret = -EBUSY;
+ goto sf_unlock;
+ }
+
+ frame = &ctx->d_frame;
+
+ pix = &f->fmt.pix;
+ frame->fmt = find_format(f, FMT_FLAGS_M2M | FMT_FLAGS_CAM);
+ if (!frame->fmt) {
+ err("fimc target format not found\n");
+ ret = -EINVAL;
+ goto sf_unlock;
+ }
+
+ /* Output DMA frame pixel size and offsets. */
+ frame->f_width = pix->bytesperline * 8 / frame->fmt->depth;
+ frame->f_height = pix->height;
+ frame->width = pix->width;
+ frame->height = pix->height;
+ frame->o_width = pix->width;
+ frame->o_height = pix->height;
+ frame->size = (pix->width * pix->height * frame->fmt->depth) >> 3;
+ frame->offs_h = 0;
+ frame->offs_v = 0;
+
+ ret = sync_capture_fmt(ctx);
+
+ ctx->state |= (FIMC_PARAMS | FIMC_DST_FMT);
+
+sf_unlock:
+ mutex_unlock(&fimc->lock);
+ return ret;
+}
+
+static int fimc_cap_enum_input(struct file *file, void *priv,
+ struct v4l2_input *i)
+{
+ struct fimc_ctx *ctx = priv;
+ struct s3c_platform_fimc *pldata = ctx->fimc_dev->pdata;
+ struct s3c_fimc_isp_info *isp_info;
+
+ if (i->index >= FIMC_MAX_CAMIF_CLIENTS)
+ return -EINVAL;
+
+ isp_info = pldata->isp_info[i->index];
+ if (isp_info == NULL)
+ return -EINVAL;
+
+ i->type = V4L2_INPUT_TYPE_CAMERA;
+ strncpy(i->name, isp_info->board_info->type, 32);
+ return 0;
+}
+
+static int fimc_cap_s_input(struct file *file, void *priv,
+ unsigned int i)
+{
+ struct fimc_ctx *ctx = priv;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct s3c_platform_fimc *pdata = fimc->pdata;
+ int ret;
+
+ if (fimc_capture_active(ctx->fimc_dev))
+ return -EBUSY;
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ if (i >= FIMC_MAX_CAMIF_CLIENTS || !pdata->isp_info[i]) {
+ ret = -EINVAL;
+ goto si_unlock;
+ }
+
+ if (fimc->vid_cap.sd) {
+ ret = v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 0);
+ if (ret)
+ err("s_power failed: %d", ret);
+ }
+
+ /* Release the attached sensor subdevice. */
+ fimc_subdev_unregister(fimc);
+
+ ret = fimc_isp_subdev_init(fimc, i);
+
+si_unlock:
+ mutex_unlock(&fimc->lock);
+ return ret;
+}
+
+static int fimc_cap_g_input(struct file *file, void *priv,
+ unsigned int *i)
+{
+ struct fimc_ctx *ctx = priv;
+ struct fimc_vid_cap *cap = &ctx->fimc_dev->vid_cap;
+
+ *i = cap->input_index;
+ return 0;
+}
+
+static int fimc_cap_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct s3c_fimc_isp_info *isp_info;
+ struct fimc_ctx *ctx = priv;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ int ret = -EBUSY;
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ if (fimc_capture_active(fimc) || !fimc->vid_cap.sd)
+ goto s_unlock;
+
+ if (!(ctx->state & FIMC_DST_FMT)) {
+ v4l2_err(&fimc->vid_cap.v4l2_dev, "Format is not set\n");
+ ret = -EINVAL;
+ goto s_unlock;
+ }
+
+ ret = v4l2_subdev_call(fimc->vid_cap.sd, video, s_stream, 1);
+ if (ret && ret != -ENOIOCTLCMD)
+ goto s_unlock;
+
+ ret = fimc_prepare_config(ctx, ctx->state);
+ if (ret)
+ goto s_unlock;
+
+ isp_info = fimc->pdata->isp_info[fimc->vid_cap.input_index];
+ fimc_hw_set_camera_type(fimc, isp_info);
+ fimc_hw_set_camera_source(fimc, isp_info);
+ fimc_hw_set_camera_offset(fimc, &ctx->s_frame);
+
+ if (ctx->state & FIMC_PARAMS) {
+ ret = fimc_set_scaler_info(ctx);
+ if (ret) {
+ err("Scaler setup error");
+ goto s_unlock;
+ }
+ fimc_hw_set_input_path(ctx);
+ fimc_hw_set_scaler(ctx);
+ fimc_hw_set_target_format(ctx);
+ fimc_hw_set_rotation(ctx);
+ fimc_hw_set_effect(ctx);
+ }
+
+ fimc_hw_set_output_path(ctx);
+ fimc_hw_set_out_dma(ctx);
+
+ INIT_LIST_HEAD(&fimc->vid_cap.pending_buf_q);
+ INIT_LIST_HEAD(&fimc->vid_cap.active_buf_q);
+ fimc->vid_cap.active_buf_cnt = 0;
+ fimc->vid_cap.frame_count = 0;
+
+ set_bit(ST_CAPT_PEND, &fimc->state);
+ ret = videobuf_streamon(&fimc->vid_cap.vbq);
+
+s_unlock:
+ mutex_unlock(&fimc->lock);
+ return ret;
+}
+
+static int fimc_cap_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct fimc_ctx *ctx = priv;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct fimc_vid_cap *cap = &fimc->vid_cap;
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&fimc->slock, flags);
+ if (!fimc_capture_running(fimc) && !fimc_capture_pending(fimc)) {
+ spin_unlock_irqrestore(&fimc->slock, flags);
+ dbg("state: 0x%lx", fimc->state);
+ return -EINVAL;
+ }
+ spin_unlock_irqrestore(&fimc->slock, flags);
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ fimc_stop_capture(fimc);
+ ret = videobuf_streamoff(&cap->vbq);
+ mutex_unlock(&fimc->lock);
+ return ret;
+}
+
+static int fimc_cap_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *reqbufs)
+{
+ struct fimc_ctx *ctx = priv;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct fimc_vid_cap *cap = &fimc->vid_cap;
+ int ret;
+
+ if (fimc_capture_active(ctx->fimc_dev))
+ return -EBUSY;
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ ret = videobuf_reqbufs(&cap->vbq, reqbufs);
+ if (!ret)
+ cap->reqbufs_count = reqbufs->count;
+
+ mutex_unlock(&fimc->lock);
+ return ret;
+}
+
+static int fimc_cap_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct fimc_ctx *ctx = priv;
+ struct fimc_vid_cap *cap = &ctx->fimc_dev->vid_cap;
+
+ if (fimc_capture_active(ctx->fimc_dev))
+ return -EBUSY;
+
+ return videobuf_querybuf(&cap->vbq, buf);
+}
+
+static int fimc_cap_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct fimc_ctx *ctx = priv;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct fimc_vid_cap *cap = &fimc->vid_cap;
+ int ret;
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ ret = videobuf_qbuf(&cap->vbq, buf);
+
+ mutex_unlock(&fimc->lock);
+ return ret;
+}
+
+static int fimc_cap_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct fimc_ctx *ctx = priv;
+ int ret;
+
+ if (mutex_lock_interruptible(&ctx->fimc_dev->lock))
+ return -ERESTARTSYS;
+
+ ret = videobuf_dqbuf(&ctx->fimc_dev->vid_cap.vbq, buf,
+ file->f_flags & O_NONBLOCK);
+
+ mutex_unlock(&ctx->fimc_dev->lock);
+ return ret;
+}
+
+static int fimc_cap_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct fimc_ctx *ctx = priv;
+ int ret = -EINVAL;
+
+ if (mutex_lock_interruptible(&ctx->fimc_dev->lock))
+ return -ERESTARTSYS;
+
+ /* Allow any controls but 90/270 rotation while streaming */
+ if (!fimc_capture_active(ctx->fimc_dev) ||
+ ctrl->id != V4L2_CID_ROTATE ||
+ (ctrl->value != 90 && ctrl->value != 270)) {
+ ret = check_ctrl_val(ctx, ctrl);
+ if (!ret) {
+ ret = fimc_s_ctrl(ctx, ctrl);
+ if (!ret)
+ ctx->state |= FIMC_PARAMS;
+ }
+ }
+
+ mutex_unlock(&ctx->fimc_dev->lock);
+ return ret;
+}
+
+static int fimc_cap_s_crop(struct file *file, void *fh,
+ struct v4l2_crop *cr)
+{
+ struct fimc_frame *f;
+ struct fimc_ctx *ctx = file->private_data;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ int ret = -EINVAL;
+
+ if (fimc_capture_active(fimc))
+ return -EBUSY;
+
+ ret = fimc_try_crop(ctx, cr);
+ if (ret)
+ return ret;
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ if (!(ctx->state & FIMC_DST_FMT)) {
+ v4l2_err(&fimc->vid_cap.v4l2_dev,
+ "Capture color format not set\n");
+ goto sc_unlock;
+ }
+
+ f = &ctx->s_frame;
+ /* Check for the pixel scaling ratio when cropping input image. */
+ ret = fimc_check_scaler_ratio(&cr->c, &ctx->d_frame);
+ if (ret) {
+ v4l2_err(&fimc->vid_cap.v4l2_dev, "Out of the scaler range");
+ } else {
+ ret = 0;
+ f->offs_h = cr->c.left;
+ f->offs_v = cr->c.top;
+ f->width = cr->c.width;
+ f->height = cr->c.height;
+ }
+
+sc_unlock:
+ mutex_unlock(&fimc->lock);
+ return ret;
+}
+
+
+static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = {
+ .vidioc_querycap = fimc_vidioc_querycap_capture,
+
+ .vidioc_enum_fmt_vid_cap = fimc_vidioc_enum_fmt,
+ .vidioc_try_fmt_vid_cap = fimc_vidioc_try_fmt,
+ .vidioc_s_fmt_vid_cap = fimc_cap_s_fmt,
+ .vidioc_g_fmt_vid_cap = fimc_vidioc_g_fmt,
+
+ .vidioc_reqbufs = fimc_cap_reqbufs,
+ .vidioc_querybuf = fimc_cap_querybuf,
+
+ .vidioc_qbuf = fimc_cap_qbuf,
+ .vidioc_dqbuf = fimc_cap_dqbuf,
+
+ .vidioc_streamon = fimc_cap_streamon,
+ .vidioc_streamoff = fimc_cap_streamoff,
+
+ .vidioc_queryctrl = fimc_vidioc_queryctrl,
+ .vidioc_g_ctrl = fimc_vidioc_g_ctrl,
+ .vidioc_s_ctrl = fimc_cap_s_ctrl,
+
+ .vidioc_g_crop = fimc_vidioc_g_crop,
+ .vidioc_s_crop = fimc_cap_s_crop,
+ .vidioc_cropcap = fimc_vidioc_cropcap,
+
+ .vidioc_enum_input = fimc_cap_enum_input,
+ .vidioc_s_input = fimc_cap_s_input,
+ .vidioc_g_input = fimc_cap_g_input,
+};
+
+int fimc_register_capture_device(struct fimc_dev *fimc)
+{
+ struct v4l2_device *v4l2_dev = &fimc->vid_cap.v4l2_dev;
+ struct video_device *vfd;
+ struct fimc_vid_cap *vid_cap;
+ struct fimc_ctx *ctx;
+ struct v4l2_format f;
+ int ret;
+
+ ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ ctx->fimc_dev = fimc;
+ ctx->in_path = FIMC_CAMERA;
+ ctx->out_path = FIMC_DMA;
+ ctx->state = FIMC_CTX_CAP;
+
+ f.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
+ ctx->d_frame.fmt = find_format(&f, FMT_FLAGS_M2M);
+
+ if (!v4l2_dev->name[0])
+ snprintf(v4l2_dev->name, sizeof(v4l2_dev->name),
+ "%s.capture", dev_name(&fimc->pdev->dev));
+
+ ret = v4l2_device_register(NULL, v4l2_dev);
+ if (ret)
+ goto err_info;
+
+ vfd = video_device_alloc();
+ if (!vfd) {
+ v4l2_err(v4l2_dev, "Failed to allocate video device\n");
+ goto err_v4l2_reg;
+ }
+
+ snprintf(vfd->name, sizeof(vfd->name), "%s:cap",
+ dev_name(&fimc->pdev->dev));
+
+ vfd->fops = &fimc_capture_fops;
+ vfd->ioctl_ops = &fimc_capture_ioctl_ops;
+ vfd->minor = -1;
+ vfd->release = video_device_release;
+ video_set_drvdata(vfd, fimc);
+
+ vid_cap = &fimc->vid_cap;
+ vid_cap->vfd = vfd;
+ vid_cap->active_buf_cnt = 0;
+ vid_cap->reqbufs_count = 0;
+ vid_cap->refcnt = 0;
+ /* The default color format for image sensor. */
+ vid_cap->fmt.code = V4L2_MBUS_FMT_YUYV8_2X8;
+
+ INIT_LIST_HEAD(&vid_cap->pending_buf_q);
+ INIT_LIST_HEAD(&vid_cap->active_buf_q);
+ spin_lock_init(&ctx->slock);
+ vid_cap->ctx = ctx;
+
+ videobuf_queue_dma_contig_init(&vid_cap->vbq, &fimc_qops,
+ vid_cap->v4l2_dev.dev, &fimc->irqlock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
+ sizeof(struct fimc_vid_buffer), (void *)ctx);
+
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
+ if (ret) {
+ v4l2_err(v4l2_dev, "Failed to register video device\n");
+ goto err_vd_reg;
+ }
+
+ v4l2_info(v4l2_dev,
+ "FIMC capture driver registered as /dev/video%d\n",
+ vfd->num);
+
+ return 0;
+
+err_vd_reg:
+ video_device_release(vfd);
+err_v4l2_reg:
+ v4l2_device_unregister(v4l2_dev);
+err_info:
+ dev_err(&fimc->pdev->dev, "failed to install\n");
+ return ret;
+}
+
+void fimc_unregister_capture_device(struct fimc_dev *fimc)
+{
+ struct fimc_vid_cap *capture = &fimc->vid_cap;
+
+ if (capture->vfd)
+ video_unregister_device(capture->vfd);
+
+ kfree(capture->ctx);
+}
diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c
index 23cc054..c05777f 100644
--- a/drivers/media/video/s5p-fimc/fimc-core.c
+++ b/drivers/media/video/s5p-fimc/fimc-core.c
@@ -1,7 +1,7 @@
/*
* S5P camera interface (video postprocessor) driver
*
- * Copyright (c) 2010 Samsung Electronics
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd
*
* Sylwester Nawrocki, <s.nawrocki@samsung.com>
*
@@ -38,85 +38,102 @@ static struct fimc_fmt fimc_formats[] = {
.depth = 16,
.color = S5P_FIMC_RGB565,
.buff_cnt = 1,
- .planes_cnt = 1
+ .planes_cnt = 1,
+ .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_BE,
+ .flags = FMT_FLAGS_M2M,
}, {
.name = "BGR666",
.fourcc = V4L2_PIX_FMT_BGR666,
.depth = 32,
.color = S5P_FIMC_RGB666,
.buff_cnt = 1,
- .planes_cnt = 1
+ .planes_cnt = 1,
+ .flags = FMT_FLAGS_M2M,
}, {
.name = "XRGB-8-8-8-8, 24 bpp",
.fourcc = V4L2_PIX_FMT_RGB24,
.depth = 32,
.color = S5P_FIMC_RGB888,
.buff_cnt = 1,
- .planes_cnt = 1
+ .planes_cnt = 1,
+ .flags = FMT_FLAGS_M2M,
}, {
.name = "YUV 4:2:2 packed, YCbYCr",
.fourcc = V4L2_PIX_FMT_YUYV,
.depth = 16,
.color = S5P_FIMC_YCBYCR422,
.buff_cnt = 1,
- .planes_cnt = 1
- }, {
+ .planes_cnt = 1,
+ .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
+ }, {
.name = "YUV 4:2:2 packed, CbYCrY",
.fourcc = V4L2_PIX_FMT_UYVY,
.depth = 16,
.color = S5P_FIMC_CBYCRY422,
.buff_cnt = 1,
- .planes_cnt = 1
+ .planes_cnt = 1,
+ .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8,
+ .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
}, {
.name = "YUV 4:2:2 packed, CrYCbY",
.fourcc = V4L2_PIX_FMT_VYUY,
.depth = 16,
.color = S5P_FIMC_CRYCBY422,
.buff_cnt = 1,
- .planes_cnt = 1
+ .planes_cnt = 1,
+ .mbus_code = V4L2_MBUS_FMT_VYUY8_2X8,
+ .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
}, {
.name = "YUV 4:2:2 packed, YCrYCb",
.fourcc = V4L2_PIX_FMT_YVYU,
.depth = 16,
.color = S5P_FIMC_YCRYCB422,
.buff_cnt = 1,
- .planes_cnt = 1
+ .planes_cnt = 1,
+ .mbus_code = V4L2_MBUS_FMT_YVYU8_2X8,
+ .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
}, {
.name = "YUV 4:2:2 planar, Y/Cb/Cr",
.fourcc = V4L2_PIX_FMT_YUV422P,
.depth = 12,
.color = S5P_FIMC_YCBCR422,
.buff_cnt = 1,
- .planes_cnt = 3
+ .planes_cnt = 3,
+ .flags = FMT_FLAGS_M2M,
}, {
.name = "YUV 4:2:2 planar, Y/CbCr",
.fourcc = V4L2_PIX_FMT_NV16,
.depth = 16,
.color = S5P_FIMC_YCBCR422,
.buff_cnt = 1,
- .planes_cnt = 2
+ .planes_cnt = 2,
+ .flags = FMT_FLAGS_M2M,
}, {
.name = "YUV 4:2:2 planar, Y/CrCb",
.fourcc = V4L2_PIX_FMT_NV61,
.depth = 16,
.color = S5P_FIMC_RGB565,
.buff_cnt = 1,
- .planes_cnt = 2
+ .planes_cnt = 2,
+ .flags = FMT_FLAGS_M2M,
}, {
.name = "YUV 4:2:0 planar, YCbCr",
.fourcc = V4L2_PIX_FMT_YUV420,
.depth = 12,
.color = S5P_FIMC_YCBCR420,
.buff_cnt = 1,
- .planes_cnt = 3
+ .planes_cnt = 3,
+ .flags = FMT_FLAGS_M2M,
}, {
.name = "YUV 4:2:0 planar, Y/CbCr",
.fourcc = V4L2_PIX_FMT_NV12,
.depth = 12,
.color = S5P_FIMC_YCBCR420,
.buff_cnt = 1,
- .planes_cnt = 2
- }
+ .planes_cnt = 2,
+ .flags = FMT_FLAGS_M2M,
+ },
};
static struct v4l2_queryctrl fimc_ctrls[] = {
@@ -156,7 +173,7 @@ static struct v4l2_queryctrl *get_ctrl(int id)
return NULL;
}
-static int fimc_check_scaler_ratio(struct v4l2_rect *r, struct fimc_frame *f)
+int fimc_check_scaler_ratio(struct v4l2_rect *r, struct fimc_frame *f)
{
if (r->width > f->width) {
if (f->width > (r->width * SCALER_MAX_HRATIO))
@@ -199,7 +216,7 @@ static int fimc_get_scaler_factor(u32 src, u32 tar, u32 *ratio, u32 *shift)
return 0;
}
-static int fimc_set_scaler_info(struct fimc_ctx *ctx)
+int fimc_set_scaler_info(struct fimc_ctx *ctx)
{
struct fimc_scaler *sc = &ctx->scaler;
struct fimc_frame *s_frame = &ctx->s_frame;
@@ -259,6 +276,51 @@ static int fimc_set_scaler_info(struct fimc_ctx *ctx)
return 0;
}
+static void fimc_capture_handler(struct fimc_dev *fimc)
+{
+ struct fimc_vid_cap *cap = &fimc->vid_cap;
+ struct fimc_vid_buffer *v_buf = NULL;
+
+ if (!list_empty(&cap->active_buf_q)) {
+ v_buf = active_queue_pop(cap);
+ fimc_buf_finish(fimc, v_buf);
+ }
+
+ if (test_and_clear_bit(ST_CAPT_SHUT, &fimc->state)) {
+ wake_up(&fimc->irq_queue);
+ return;
+ }
+
+ if (!list_empty(&cap->pending_buf_q)) {
+
+ v_buf = pending_queue_pop(cap);
+ fimc_hw_set_output_addr(fimc, &v_buf->paddr, cap->buf_index);
+ v_buf->index = cap->buf_index;
+
+ dbg("hw ptr: %d, sw ptr: %d",
+ fimc_hw_get_frame_index(fimc), cap->buf_index);
+
+ spin_lock(&fimc->irqlock);
+ v_buf->vb.state = VIDEOBUF_ACTIVE;
+ spin_unlock(&fimc->irqlock);
+
+ /* Move the buffer to the capture active queue */
+ active_queue_add(cap, v_buf);
+
+ dbg("next frame: %d, done frame: %d",
+ fimc_hw_get_frame_index(fimc), v_buf->index);
+
+ if (++cap->buf_index >= FIMC_MAX_OUT_BUFS)
+ cap->buf_index = 0;
+
+ } else if (test_and_clear_bit(ST_CAPT_STREAM, &fimc->state) &&
+ cap->active_buf_cnt <= 1) {
+ fimc_deactivate_capture(fimc);
+ }
+
+ dbg("frame: %d, active_buf_cnt= %d",
+ fimc_hw_get_frame_index(fimc), cap->active_buf_cnt);
+}
static irqreturn_t fimc_isr(int irq, void *priv)
{
@@ -285,6 +347,16 @@ static irqreturn_t fimc_isr(int irq, void *priv)
spin_unlock(&fimc->irqlock);
v4l2_m2m_job_finish(fimc->m2m.m2m_dev, ctx->m2m_ctx);
}
+ goto isr_unlock;
+
+ }
+
+ if (test_bit(ST_CAPT_RUN, &fimc->state))
+ fimc_capture_handler(fimc);
+
+ if (test_and_clear_bit(ST_CAPT_PEND, &fimc->state)) {
+ set_bit(ST_CAPT_RUN, &fimc->state);
+ wake_up(&fimc->irq_queue);
}
isr_unlock:
@@ -424,7 +496,7 @@ static void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f)
*
* Return: 0 if dimensions are valid or non zero otherwise.
*/
-static int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags)
+int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags)
{
struct fimc_frame *s_frame, *d_frame;
struct fimc_vid_buffer *buf = NULL;
@@ -513,9 +585,9 @@ static void fimc_dma_run(void *priv)
if (ctx->state & FIMC_PARAMS)
fimc_hw_set_out_dma(ctx);
- ctx->state = 0;
fimc_activate_capture(ctx);
+ ctx->state &= (FIMC_CTX_M2M | FIMC_CTX_CAP);
fimc_hw_activate_input_dma(fimc, true);
dma_unlock:
@@ -598,16 +670,59 @@ static void fimc_buf_queue(struct videobuf_queue *vq,
struct videobuf_buffer *vb)
{
struct fimc_ctx *ctx = vq->priv_data;
- v4l2_m2m_buf_queue(ctx->m2m_ctx, vq, vb);
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct fimc_vid_cap *cap = &fimc->vid_cap;
+ unsigned long flags;
+
+ dbg("ctx: %p, ctx->state: 0x%x", ctx, ctx->state);
+
+ if ((ctx->state & FIMC_CTX_M2M) && ctx->m2m_ctx) {
+ v4l2_m2m_buf_queue(ctx->m2m_ctx, vq, vb);
+ } else if (ctx->state & FIMC_CTX_CAP) {
+ spin_lock_irqsave(&fimc->slock, flags);
+ fimc_vid_cap_buf_queue(fimc, (struct fimc_vid_buffer *)vb);
+
+ dbg("fimc->cap.active_buf_cnt: %d",
+ fimc->vid_cap.active_buf_cnt);
+
+ if (cap->active_buf_cnt >= cap->reqbufs_count ||
+ cap->active_buf_cnt >= FIMC_MAX_OUT_BUFS) {
+ if (!test_and_set_bit(ST_CAPT_STREAM, &fimc->state))
+ fimc_activate_capture(ctx);
+ }
+ spin_unlock_irqrestore(&fimc->slock, flags);
+ }
}
-static struct videobuf_queue_ops fimc_qops = {
+struct videobuf_queue_ops fimc_qops = {
.buf_setup = fimc_buf_setup,
.buf_prepare = fimc_buf_prepare,
.buf_queue = fimc_buf_queue,
.buf_release = fimc_buf_release,
};
+/**
+ * check_stream_type - check if stream type is valid
+ * @ctx: hardware operation context, per device for capture
+ * @type: v4l stream type
+ *
+ * Return: non zero for V4L output stream, 0 - for capture stream,
+ * -EINVAL if stream is invalid for given context
+ */
+static int check_stream_type(struct fimc_ctx *ctx, int type)
+{
+ int is_output = (type == V4L2_BUF_TYPE_VIDEO_OUTPUT);
+
+ if (ctx->state & FIMC_CTX_CAP) {
+ if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ } else {
+ if (!is_output && type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ }
+ return is_output;
+}
+
static int fimc_m2m_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
@@ -624,7 +739,7 @@ static int fimc_m2m_querycap(struct file *file, void *priv,
return 0;
}
-static int fimc_m2m_enum_fmt(struct file *file, void *priv,
+int fimc_vidioc_enum_fmt(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
struct fimc_fmt *fmt;
@@ -635,109 +750,135 @@ static int fimc_m2m_enum_fmt(struct file *file, void *priv,
fmt = &fimc_formats[f->index];
strncpy(f->description, fmt->name, sizeof(f->description) - 1);
f->pixelformat = fmt->fourcc;
+
return 0;
}
-static int fimc_m2m_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
+int fimc_vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
{
struct fimc_ctx *ctx = priv;
+ struct fimc_dev *fimc = ctx->fimc_dev;
struct fimc_frame *frame;
frame = ctx_get_frame(ctx, f->type);
if (IS_ERR(frame))
return PTR_ERR(frame);
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
f->fmt.pix.width = frame->width;
f->fmt.pix.height = frame->height;
f->fmt.pix.field = V4L2_FIELD_NONE;
f->fmt.pix.pixelformat = frame->fmt->fourcc;
+ mutex_unlock(&fimc->lock);
return 0;
}
-static struct fimc_fmt *find_format(struct v4l2_format *f)
+struct fimc_fmt *find_format(struct v4l2_format *f, unsigned int mask)
{
struct fimc_fmt *fmt;
unsigned int i;
for (i = 0; i < ARRAY_SIZE(fimc_formats); ++i) {
fmt = &fimc_formats[i];
- if (fmt->fourcc == f->fmt.pix.pixelformat)
+ if (fmt->fourcc == f->fmt.pix.pixelformat &&
+ (fmt->flags & mask))
break;
}
- if (i == ARRAY_SIZE(fimc_formats))
- return NULL;
- return fmt;
+ return (i == ARRAY_SIZE(fimc_formats)) ? NULL : fmt;
}
-static int fimc_m2m_try_fmt(struct file *file, void *priv,
- struct v4l2_format *f)
+struct fimc_fmt *find_mbus_format(struct v4l2_mbus_framefmt *f,
+ unsigned int mask)
{
struct fimc_fmt *fmt;
- u32 max_width, max_height, mod_x, mod_y;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(fimc_formats); ++i) {
+ fmt = &fimc_formats[i];
+ if (fmt->mbus_code == f->code && (fmt->flags & mask))
+ break;
+ }
+
+ return (i == ARRAY_SIZE(fimc_formats)) ? NULL : fmt;
+}
+
+
+int fimc_vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
struct fimc_ctx *ctx = priv;
struct fimc_dev *fimc = ctx->fimc_dev;
- struct v4l2_pix_format *pix = &f->fmt.pix;
struct samsung_fimc_variant *variant = fimc->variant;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ struct fimc_fmt *fmt;
+ u32 max_width, mod_x, mod_y, mask;
+ int ret = -EINVAL;
+
+ bool is_output = check_stream_type(ctx, f->type);
+ if (is_output < 0)
+ return ret;
- fmt = find_format(f);
+ dbg("w: %d, h: %d, bpl: %d",
+ pix->width, pix->height, pix->bytesperline);
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ mask = is_output ? FMT_FLAGS_M2M : FMT_FLAGS_M2M | FMT_FLAGS_CAM;
+ fmt = find_format(f, mask);
if (!fmt) {
- v4l2_err(&fimc->m2m.v4l2_dev,
- "Fourcc format (0x%X) invalid.\n", pix->pixelformat);
- return -EINVAL;
+ v4l2_err(&fimc->m2m.v4l2_dev, "Fourcc format (0x%X) invalid.\n",
+ pix->pixelformat);
+ goto tf_out;
}
if (pix->field == V4L2_FIELD_ANY)
pix->field = V4L2_FIELD_NONE;
else if (V4L2_FIELD_NONE != pix->field)
- return -EINVAL;
+ goto tf_out;
- if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+ if (is_output) {
max_width = variant->scaler_dis_w;
- max_height = variant->scaler_dis_w;
- mod_x = variant->min_inp_pixsize;
- mod_y = variant->min_inp_pixsize;
- } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- max_width = variant->out_rot_dis_w;
- max_height = variant->out_rot_dis_w;
- mod_x = variant->min_out_pixsize;
- mod_y = variant->min_out_pixsize;
+ mod_x = ffs(variant->min_inp_pixsize) - 1;
} else {
- err("Wrong stream type (%d)", f->type);
- return -EINVAL;
+ max_width = variant->out_rot_dis_w;
+ mod_x = ffs(variant->min_out_pixsize) - 1;
}
- dbg("max_w= %d, max_h= %d", max_width, max_height);
-
- if (pix->height > max_height)
- pix->height = max_height;
- if (pix->width > max_width)
- pix->width = max_width;
-
if (tiled_fmt(fmt)) {
- mod_x = 64; /* 64x32 tile */
- mod_y = 32;
+ mod_x = 6; /* 64 x 32 pixels tile */
+ mod_y = 5;
+ } else {
+ if (fimc->id == 1 && fimc->variant->pix_hoff)
+ mod_y = fimc_fmt_is_rgb(fmt->color) ? 0 : 1;
+ else
+ mod_y = mod_x;
}
- dbg("mod_x= 0x%X, mod_y= 0x%X", mod_x, mod_y);
+ dbg("mod_x: %d, mod_y: %d, max_w: %d", mod_x, mod_y, max_width);
- pix->width = (pix->width == 0) ? mod_x : ALIGN(pix->width, mod_x);
- pix->height = (pix->height == 0) ? mod_y : ALIGN(pix->height, mod_y);
+ v4l_bound_align_image(&pix->width, 16, max_width, mod_x,
+ &pix->height, 8, variant->scaler_dis_w, mod_y, 0);
if (pix->bytesperline == 0 ||
- pix->bytesperline * 8 / fmt->depth > pix->width)
+ (pix->bytesperline * 8 / fmt->depth) > pix->width)
pix->bytesperline = (pix->width * fmt->depth) >> 3;
if (pix->sizeimage == 0)
pix->sizeimage = pix->height * pix->bytesperline;
- dbg("pix->bytesperline= %d, fmt->depth= %d",
- pix->bytesperline, fmt->depth);
+ dbg("w: %d, h: %d, bpl: %d, depth: %d",
+ pix->width, pix->height, pix->bytesperline, fmt->depth);
- return 0;
-}
+ ret = 0;
+tf_out:
+ mutex_unlock(&fimc->lock);
+ return ret;
+}
static int fimc_m2m_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
{
@@ -750,9 +891,7 @@ static int fimc_m2m_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
unsigned long flags;
int ret = 0;
- BUG_ON(!ctx);
-
- ret = fimc_m2m_try_fmt(file, priv, f);
+ ret = fimc_vidioc_try_fmt(file, priv, f);
if (ret)
return ret;
@@ -785,7 +924,7 @@ static int fimc_m2m_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
spin_unlock_irqrestore(&ctx->slock, flags);
pix = &f->fmt.pix;
- frame->fmt = find_format(f);
+ frame->fmt = find_format(f, FMT_FLAGS_M2M);
if (!frame->fmt) {
ret = -EINVAL;
goto sf_out;
@@ -857,21 +996,33 @@ static int fimc_m2m_streamoff(struct file *file, void *priv,
return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
}
-int fimc_m2m_queryctrl(struct file *file, void *priv,
+int fimc_vidioc_queryctrl(struct file *file, void *priv,
struct v4l2_queryctrl *qc)
{
+ struct fimc_ctx *ctx = priv;
struct v4l2_queryctrl *c;
+
c = get_ctrl(qc->id);
- if (!c)
- return -EINVAL;
- *qc = *c;
- return 0;
+ if (c) {
+ *qc = *c;
+ return 0;
+ }
+
+ if (ctx->state & FIMC_CTX_CAP)
+ return v4l2_subdev_call(ctx->fimc_dev->vid_cap.sd,
+ core, queryctrl, qc);
+ return -EINVAL;
}
-int fimc_m2m_g_ctrl(struct file *file, void *priv,
+int fimc_vidioc_g_ctrl(struct file *file, void *priv,
struct v4l2_control *ctrl)
{
struct fimc_ctx *ctx = priv;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ int ret = 0;
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
switch (ctrl->id) {
case V4L2_CID_HFLIP:
@@ -884,15 +1035,22 @@ int fimc_m2m_g_ctrl(struct file *file, void *priv,
ctrl->value = ctx->rotation;
break;
default:
- v4l2_err(&ctx->fimc_dev->m2m.v4l2_dev, "Invalid control\n");
- return -EINVAL;
+ if (ctx->state & FIMC_CTX_CAP) {
+ ret = v4l2_subdev_call(fimc->vid_cap.sd, core,
+ g_ctrl, ctrl);
+ } else {
+ v4l2_err(&fimc->m2m.v4l2_dev,
+ "Invalid control\n");
+ ret = -EINVAL;
+ }
}
dbg("ctrl->value= %d", ctrl->value);
- return 0;
+
+ mutex_unlock(&fimc->lock);
+ return ret;
}
-static int check_ctrl_val(struct fimc_ctx *ctx,
- struct v4l2_control *ctrl)
+int check_ctrl_val(struct fimc_ctx *ctx, struct v4l2_control *ctrl)
{
struct v4l2_queryctrl *c;
c = get_ctrl(ctrl->id);
@@ -909,22 +1067,23 @@ static int check_ctrl_val(struct fimc_ctx *ctx,
return 0;
}
-int fimc_m2m_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
+int fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_control *ctrl)
{
- struct fimc_ctx *ctx = priv;
struct samsung_fimc_variant *variant = ctx->fimc_dev->variant;
+ struct fimc_dev *fimc = ctx->fimc_dev;
unsigned long flags;
- int ret = 0;
- ret = check_ctrl_val(ctx, ctrl);
- if (ret)
- return ret;
+ if (ctx->rotation != 0 &&
+ (ctrl->id == V4L2_CID_HFLIP || ctrl->id == V4L2_CID_VFLIP)) {
+ v4l2_err(&fimc->m2m.v4l2_dev,
+ "Simultaneous flip and rotation is not supported\n");
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&ctx->slock, flags);
switch (ctrl->id) {
case V4L2_CID_HFLIP:
- if (ctx->rotation != 0)
- return 0;
if (ctrl->value)
ctx->flip |= FLIP_X_AXIS;
else
@@ -932,8 +1091,6 @@ int fimc_m2m_s_ctrl(struct file *file, void *priv,
break;
case V4L2_CID_VFLIP:
- if (ctx->rotation != 0)
- return 0;
if (ctrl->value)
ctx->flip |= FLIP_Y_AXIS;
else
@@ -941,77 +1098,99 @@ int fimc_m2m_s_ctrl(struct file *file, void *priv,
break;
case V4L2_CID_ROTATE:
- if (ctrl->value == 90 || ctrl->value == 270) {
- if (ctx->out_path == FIMC_LCDFIFO &&
- !variant->has_inp_rot) {
- return -EINVAL;
- } else if (ctx->in_path == FIMC_DMA &&
- !variant->has_out_rot) {
- return -EINVAL;
- }
+ /* Check for the output rotator availability */
+ if ((ctrl->value == 90 || ctrl->value == 270) &&
+ (ctx->in_path == FIMC_DMA && !variant->has_out_rot)) {
+ spin_unlock_irqrestore(&ctx->slock, flags);
+ return -EINVAL;
+ } else {
+ ctx->rotation = ctrl->value;
}
- ctx->rotation = ctrl->value;
- if (ctrl->value == 180)
- ctx->flip = FLIP_XY_AXIS;
break;
default:
- v4l2_err(&ctx->fimc_dev->m2m.v4l2_dev, "Invalid control\n");
+ spin_unlock_irqrestore(&ctx->slock, flags);
+ if (ctx->state & FIMC_CTX_CAP)
+ return v4l2_subdev_call(fimc->vid_cap.sd, core,
+ s_ctrl, ctrl);
+
+ v4l2_err(&fimc->m2m.v4l2_dev, "Invalid control\n");
return -EINVAL;
}
- spin_lock_irqsave(&ctx->slock, flags);
ctx->state |= FIMC_PARAMS;
spin_unlock_irqrestore(&ctx->slock, flags);
+
return 0;
}
+static int fimc_m2m_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct fimc_ctx *ctx = priv;
+ int ret = 0;
+
+ ret = check_ctrl_val(ctx, ctrl);
+ if (ret)
+ return ret;
-static int fimc_m2m_cropcap(struct file *file, void *fh,
- struct v4l2_cropcap *cr)
+ ret = fimc_s_ctrl(ctx, ctrl);
+ return 0;
+}
+
+int fimc_vidioc_cropcap(struct file *file, void *fh,
+ struct v4l2_cropcap *cr)
{
struct fimc_frame *frame;
struct fimc_ctx *ctx = fh;
+ struct fimc_dev *fimc = ctx->fimc_dev;
frame = ctx_get_frame(ctx, cr->type);
if (IS_ERR(frame))
return PTR_ERR(frame);
- cr->bounds.left = 0;
- cr->bounds.top = 0;
- cr->bounds.width = frame->f_width;
- cr->bounds.height = frame->f_height;
- cr->defrect.left = frame->offs_h;
- cr->defrect.top = frame->offs_v;
- cr->defrect.width = frame->o_width;
- cr->defrect.height = frame->o_height;
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ cr->bounds.left = 0;
+ cr->bounds.top = 0;
+ cr->bounds.width = frame->f_width;
+ cr->bounds.height = frame->f_height;
+ cr->defrect = cr->bounds;
+
+ mutex_unlock(&fimc->lock);
return 0;
}
-static int fimc_m2m_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
+int fimc_vidioc_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
{
struct fimc_frame *frame;
struct fimc_ctx *ctx = file->private_data;
+ struct fimc_dev *fimc = ctx->fimc_dev;
frame = ctx_get_frame(ctx, cr->type);
if (IS_ERR(frame))
return PTR_ERR(frame);
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
cr->c.left = frame->offs_h;
cr->c.top = frame->offs_v;
cr->c.width = frame->width;
cr->c.height = frame->height;
+ mutex_unlock(&fimc->lock);
return 0;
}
-static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr)
+int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr)
{
- struct fimc_ctx *ctx = file->private_data;
struct fimc_dev *fimc = ctx->fimc_dev;
- unsigned long flags;
struct fimc_frame *f;
- u32 min_size;
- int ret = 0;
+ u32 min_size, halign;
+
+ f = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ?
+ &ctx->s_frame : &ctx->d_frame;
if (cr->c.top < 0 || cr->c.left < 0) {
v4l2_err(&fimc->m2m.v4l2_dev,
@@ -1019,66 +1198,98 @@ static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr)
return -EINVAL;
}
- if (cr->c.width <= 0 || cr->c.height <= 0) {
- v4l2_err(&fimc->m2m.v4l2_dev,
- "crop width and height must be greater than 0\n");
- return -EINVAL;
- }
-
f = ctx_get_frame(ctx, cr->type);
if (IS_ERR(f))
return PTR_ERR(f);
- /* Adjust to required pixel boundary. */
- min_size = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ?
- fimc->variant->min_inp_pixsize : fimc->variant->min_out_pixsize;
+ min_size = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ ? fimc->variant->min_inp_pixsize
+ : fimc->variant->min_out_pixsize;
- cr->c.width = round_down(cr->c.width, min_size);
- cr->c.height = round_down(cr->c.height, min_size);
- cr->c.left = round_down(cr->c.left + 1, min_size);
- cr->c.top = round_down(cr->c.top + 1, min_size);
-
- if ((cr->c.left + cr->c.width > f->o_width)
- || (cr->c.top + cr->c.height > f->o_height)) {
- v4l2_err(&fimc->m2m.v4l2_dev, "Error in S_CROP params\n");
- return -EINVAL;
+ if (ctx->state & FIMC_CTX_M2M) {
+ if (fimc->id == 1 && fimc->variant->pix_hoff)
+ halign = fimc_fmt_is_rgb(f->fmt->color) ? 0 : 1;
+ else
+ halign = ffs(min_size) - 1;
+ /* there are more strict aligment requirements at camera interface */
+ } else {
+ min_size = 16;
+ halign = 4;
}
+ v4l_bound_align_image(&cr->c.width, min_size, f->o_width,
+ ffs(min_size) - 1,
+ &cr->c.height, min_size, f->o_height,
+ halign, 64/(ALIGN(f->fmt->depth, 8)));
+
+ /* adjust left/top if cropping rectangle is out of bounds */
+ if (cr->c.left + cr->c.width > f->o_width)
+ cr->c.left = f->o_width - cr->c.width;
+ if (cr->c.top + cr->c.height > f->o_height)
+ cr->c.top = f->o_height - cr->c.height;
+
+ cr->c.left = round_down(cr->c.left, min_size);
+ cr->c.top = round_down(cr->c.top,
+ ctx->state & FIMC_CTX_M2M ? 8 : 16);
+
+ dbg("l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d",
+ cr->c.left, cr->c.top, cr->c.width, cr->c.height,
+ f->f_width, f->f_height);
+
+ return 0;
+}
+
+
+static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr)
+{
+ struct fimc_ctx *ctx = file->private_data;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ unsigned long flags;
+ struct fimc_frame *f;
+ int ret;
+
+ ret = fimc_try_crop(ctx, cr);
+ if (ret)
+ return ret;
+
+ f = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ?
+ &ctx->s_frame : &ctx->d_frame;
+
spin_lock_irqsave(&ctx->slock, flags);
- if ((ctx->state & FIMC_SRC_FMT) && (ctx->state & FIMC_DST_FMT)) {
- /* Check for the pixel scaling ratio when cropping input img. */
+ if (~ctx->state & (FIMC_SRC_FMT | FIMC_DST_FMT)) {
+ /* Check to see if scaling ratio is within supported range */
if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
ret = fimc_check_scaler_ratio(&cr->c, &ctx->d_frame);
- else if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ else
ret = fimc_check_scaler_ratio(&cr->c, &ctx->s_frame);
-
if (ret) {
spin_unlock_irqrestore(&ctx->slock, flags);
- v4l2_err(&fimc->m2m.v4l2_dev, "Out of scaler range");
+ v4l2_err(&fimc->m2m.v4l2_dev, "Out of scaler range");
return -EINVAL;
}
}
ctx->state |= FIMC_PARAMS;
- spin_unlock_irqrestore(&ctx->slock, flags);
f->offs_h = cr->c.left;
f->offs_v = cr->c.top;
- f->width = cr->c.width;
+ f->width = cr->c.width;
f->height = cr->c.height;
+
+ spin_unlock_irqrestore(&ctx->slock, flags);
return 0;
}
static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = {
.vidioc_querycap = fimc_m2m_querycap,
- .vidioc_enum_fmt_vid_cap = fimc_m2m_enum_fmt,
- .vidioc_enum_fmt_vid_out = fimc_m2m_enum_fmt,
+ .vidioc_enum_fmt_vid_cap = fimc_vidioc_enum_fmt,
+ .vidioc_enum_fmt_vid_out = fimc_vidioc_enum_fmt,
- .vidioc_g_fmt_vid_cap = fimc_m2m_g_fmt,
- .vidioc_g_fmt_vid_out = fimc_m2m_g_fmt,
+ .vidioc_g_fmt_vid_cap = fimc_vidioc_g_fmt,
+ .vidioc_g_fmt_vid_out = fimc_vidioc_g_fmt,
- .vidioc_try_fmt_vid_cap = fimc_m2m_try_fmt,
- .vidioc_try_fmt_vid_out = fimc_m2m_try_fmt,
+ .vidioc_try_fmt_vid_cap = fimc_vidioc_try_fmt,
+ .vidioc_try_fmt_vid_out = fimc_vidioc_try_fmt,
.vidioc_s_fmt_vid_cap = fimc_m2m_s_fmt,
.vidioc_s_fmt_vid_out = fimc_m2m_s_fmt,
@@ -1092,13 +1303,13 @@ static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = {
.vidioc_streamon = fimc_m2m_streamon,
.vidioc_streamoff = fimc_m2m_streamoff,
- .vidioc_queryctrl = fimc_m2m_queryctrl,
- .vidioc_g_ctrl = fimc_m2m_g_ctrl,
+ .vidioc_queryctrl = fimc_vidioc_queryctrl,
+ .vidioc_g_ctrl = fimc_vidioc_g_ctrl,
.vidioc_s_ctrl = fimc_m2m_s_ctrl,
- .vidioc_g_crop = fimc_m2m_g_crop,
+ .vidioc_g_crop = fimc_vidioc_g_crop,
.vidioc_s_crop = fimc_m2m_s_crop,
- .vidioc_cropcap = fimc_m2m_cropcap
+ .vidioc_cropcap = fimc_vidioc_cropcap
};
@@ -1120,11 +1331,23 @@ static int fimc_m2m_open(struct file *file)
struct fimc_ctx *ctx = NULL;
int err = 0;
- mutex_lock(&fimc->lock);
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ dbg("pid: %d, state: 0x%lx, refcnt: %d",
+ task_pid_nr(current), fimc->state, fimc->vid_cap.refcnt);
+
+ /*
+ * Return if the corresponding video capture node
+ * is already opened.
+ */
+ if (fimc->vid_cap.refcnt > 0) {
+ mutex_unlock(&fimc->lock);
+ return -EBUSY;
+ }
+
fimc->m2m.refcnt++;
set_bit(ST_OUTDMA_RUN, &fimc->state);
- mutex_unlock(&fimc->lock);
-
ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
if (!ctx)
@@ -1135,8 +1358,8 @@ static int fimc_m2m_open(struct file *file)
/* Default color format */
ctx->s_frame.fmt = &fimc_formats[0];
ctx->d_frame.fmt = &fimc_formats[0];
- /* per user process device context initialization */
- ctx->state = 0;
+ /* Setup the device context for mem2mem mode. */
+ ctx->state = FIMC_CTX_M2M;
ctx->flags = 0;
ctx->in_path = FIMC_DMA;
ctx->out_path = FIMC_DMA;
@@ -1147,6 +1370,8 @@ static int fimc_m2m_open(struct file *file)
err = PTR_ERR(ctx->m2m_ctx);
kfree(ctx);
}
+
+ mutex_unlock(&fimc->lock);
return err;
}
@@ -1155,11 +1380,16 @@ static int fimc_m2m_release(struct file *file)
struct fimc_ctx *ctx = file->private_data;
struct fimc_dev *fimc = ctx->fimc_dev;
+ mutex_lock(&fimc->lock);
+
+ dbg("pid: %d, state: 0x%lx, refcnt= %d",
+ task_pid_nr(current), fimc->state, fimc->m2m.refcnt);
+
v4l2_m2m_ctx_release(ctx->m2m_ctx);
kfree(ctx);
- mutex_lock(&fimc->lock);
if (--fimc->m2m.refcnt <= 0)
clear_bit(ST_OUTDMA_RUN, &fimc->state);
+
mutex_unlock(&fimc->lock);
return 0;
}
@@ -1168,6 +1398,7 @@ static unsigned int fimc_m2m_poll(struct file *file,
struct poll_table_struct *wait)
{
struct fimc_ctx *ctx = file->private_data;
+
return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
}
@@ -1175,6 +1406,7 @@ static unsigned int fimc_m2m_poll(struct file *file,
static int fimc_m2m_mmap(struct file *file, struct vm_area_struct *vma)
{
struct fimc_ctx *ctx = file->private_data;
+
return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
}
@@ -1322,9 +1554,11 @@ static int fimc_probe(struct platform_device *pdev)
fimc->id = pdev->id;
fimc->variant = drv_data->variant[fimc->id];
fimc->pdev = pdev;
+ fimc->pdata = pdev->dev.platform_data;
fimc->state = ST_IDLE;
spin_lock_init(&fimc->irqlock);
+ init_waitqueue_head(&fimc->irq_queue);
spin_lock_init(&fimc->slock);
mutex_init(&fimc->lock);
@@ -1354,6 +1588,7 @@ static int fimc_probe(struct platform_device *pdev)
ret = fimc_clk_get(fimc);
if (ret)
goto err_regs_unmap;
+ clk_set_rate(fimc->clock[0], drv_data->lclk_frequency);
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
@@ -1375,11 +1610,27 @@ static int fimc_probe(struct platform_device *pdev)
if (ret)
goto err_irq;
+ /* At least one camera sensor is required to register capture node */
+ if (fimc->pdata) {
+ int i;
+ for (i = 0; i < FIMC_MAX_CAMIF_CLIENTS; ++i)
+ if (fimc->pdata->isp_info[i])
+ break;
+
+ if (i < FIMC_MAX_CAMIF_CLIENTS) {
+ ret = fimc_register_capture_device(fimc);
+ if (ret)
+ goto err_m2m;
+ }
+ }
+
dev_dbg(&pdev->dev, "%s(): fimc-%d registered successfully\n",
__func__, fimc->id);
return 0;
+err_m2m:
+ fimc_unregister_m2m_device(fimc);
err_irq:
free_irq(fimc->irq, fimc);
err_clk:
@@ -1404,6 +1655,8 @@ static int __devexit fimc_remove(struct platform_device *pdev)
fimc_hw_reset(fimc);
fimc_unregister_m2m_device(fimc);
+ fimc_unregister_capture_device(fimc);
+
fimc_clk_release(fimc);
iounmap(fimc->regs);
release_resource(fimc->regs_res);
@@ -1474,7 +1727,8 @@ static struct samsung_fimc_driverdata fimc_drvdata_s5p = {
[1] = &fimc01_variant_s5p,
[2] = &fimc2_variant_s5p,
},
- .devs_cnt = 3
+ .devs_cnt = 3,
+ .lclk_frequency = 133000000UL,
};
static struct samsung_fimc_driverdata fimc_drvdata_s5pv210 = {
@@ -1483,7 +1737,8 @@ static struct samsung_fimc_driverdata fimc_drvdata_s5pv210 = {
[1] = &fimc01_variant_s5pv210,
[2] = &fimc2_variant_s5pv210,
},
- .devs_cnt = 3
+ .devs_cnt = 3,
+ .lclk_frequency = 166000000UL,
};
static struct platform_device_id fimc_driver_ids[] = {
@@ -1524,6 +1779,6 @@ static void __exit fimc_exit(void)
module_init(fimc_init);
module_exit(fimc_exit);
-MODULE_AUTHOR("Sylwester Nawrocki, s.nawrocki at samsung.com");
-MODULE_DESCRIPTION("S3C/S5P FIMC (video postprocessor) driver");
+MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
+MODULE_DESCRIPTION("S5P FIMC camera host interface/video postprocessor driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h
index 5aeb3ef..ce0a6b8 100644
--- a/drivers/media/video/s5p-fimc/fimc-core.h
+++ b/drivers/media/video/s5p-fimc/fimc-core.h
@@ -11,10 +11,14 @@
#ifndef FIMC_CORE_H_
#define FIMC_CORE_H_
+/*#define DEBUG*/
+
#include <linux/types.h>
#include <media/videobuf-core.h>
#include <media/v4l2-device.h>
#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-mediabus.h>
+#include <media/s3c_fimc.h>
#include <linux/videodev2.h>
#include "regs-fimc.h"
@@ -28,6 +32,8 @@
#define dbg(fmt, args...)
#endif
+/* Time to wait for next frame VSYNC interrupt while stopping operation. */
+#define FIMC_SHUTDOWN_TIMEOUT ((100*HZ)/1000)
#define NUM_FIMC_CLOCKS 2
#define MODULE_NAME "s5p-fimc"
#define FIMC_MAX_DEVS 3
@@ -36,19 +42,41 @@
#define SCALER_MAX_VRATIO 64
#define DMA_MIN_SIZE 8
-enum {
+/* FIMC device state flags */
+enum fimc_dev_flags {
+ /* for m2m node */
ST_IDLE,
ST_OUTDMA_RUN,
ST_M2M_PEND,
+ /* for capture node */
+ ST_CAPT_PEND,
+ ST_CAPT_RUN,
+ ST_CAPT_STREAM,
+ ST_CAPT_SHUT,
};
#define fimc_m2m_active(dev) test_bit(ST_OUTDMA_RUN, &(dev)->state)
#define fimc_m2m_pending(dev) test_bit(ST_M2M_PEND, &(dev)->state)
+#define fimc_capture_running(dev) test_bit(ST_CAPT_RUN, &(dev)->state)
+#define fimc_capture_pending(dev) test_bit(ST_CAPT_PEND, &(dev)->state)
+
+#define fimc_capture_active(dev) \
+ (test_bit(ST_CAPT_RUN, &(dev)->state) || \
+ test_bit(ST_CAPT_PEND, &(dev)->state))
+
+#define fimc_capture_streaming(dev) \
+ test_bit(ST_CAPT_STREAM, &(dev)->state)
+
+#define fimc_buf_finish(dev, vid_buf) do { \
+ spin_lock(&(dev)->irqlock); \
+ (vid_buf)->vb.state = VIDEOBUF_DONE; \
+ spin_unlock(&(dev)->irqlock); \
+ wake_up(&(vid_buf)->vb.done); \
+} while (0)
+
enum fimc_datapath {
- FIMC_ITU_CAM_A,
- FIMC_ITU_CAM_B,
- FIMC_MIPI_CAM,
+ FIMC_CAMERA,
FIMC_DMA,
FIMC_LCDFIFO,
FIMC_WRITEBACK
@@ -123,20 +151,25 @@ enum fimc_color_fmt {
/**
* struct fimc_fmt - the driver's internal color format data
+ * @mbus_code: Media Bus pixel code, -1 if not applicable
* @name: format description
- * @fourcc: the fourcc code for this format
+ * @fourcc: the fourcc code for this format, 0 if not applicable
* @color: the corresponding fimc_color_fmt
- * @depth: number of bits per pixel
+ * @depth: driver's private 'number of bits per pixel'
* @buff_cnt: number of physically non-contiguous data planes
* @planes_cnt: number of physically contiguous data planes
*/
struct fimc_fmt {
+ enum v4l2_mbus_pixelcode mbus_code;
char *name;
u32 fourcc;
u32 color;
- u32 depth;
u16 buff_cnt;
u16 planes_cnt;
+ u16 depth;
+ u16 flags;
+#define FMT_FLAGS_CAM (1 << 0)
+#define FMT_FLAGS_M2M (1 << 1)
};
/**
@@ -220,10 +253,14 @@ struct fimc_addr {
/**
* struct fimc_vid_buffer - the driver's video buffer
- * @vb: v4l videobuf buffer
+ * @vb: v4l videobuf buffer
+ * @paddr: precalculated physical address set
+ * @index: buffer index for the output DMA engine
*/
struct fimc_vid_buffer {
struct videobuf_buffer vb;
+ struct fimc_addr paddr;
+ int index;
};
/**
@@ -274,6 +311,40 @@ struct fimc_m2m_device {
};
/**
+ * struct fimc_vid_cap - camera capture device information
+ * @ctx: hardware context data
+ * @vfd: video device node for camera capture mode
+ * @v4l2_dev: v4l2_device struct to manage subdevs
+ * @sd: pointer to camera sensor subdevice currently in use
+ * @fmt: Media Bus format configured@selected image sensor
+ * @pending_buf_q: the pending buffer queue head
+ * @active_buf_q: the queue head of buffers scheduled in hardware
+ * @vbq: the capture am video buffer queue
+ * @active_buf_cnt: number of video buffers scheduled in hardware
+ * @buf_index: index for managing the output DMA buffers
+ * @frame_count: the frame counter for statistics
+ * @reqbufs_count: the number of buffers requested in REQBUFS ioctl
+ * @input_index: input (camera sensor) index
+ * @refcnt: driver's private reference counter
+ */
+struct fimc_vid_cap {
+ struct fimc_ctx *ctx;
+ struct video_device *vfd;
+ struct v4l2_device v4l2_dev;
+ struct v4l2_subdev *sd;
+ struct v4l2_mbus_framefmt fmt;
+ struct list_head pending_buf_q;
+ struct list_head active_buf_q;
+ struct videobuf_queue vbq;
+ int active_buf_cnt;
+ int buf_index;
+ unsigned int frame_count;
+ unsigned int reqbufs_count;
+ int input_index;
+ int refcnt;
+};
+
+/**
* struct samsung_fimc_variant - camera interface variant information
*
* @pix_hoff: indicate whether horizontal offset is in pixels or in bytes
@@ -308,10 +379,12 @@ struct samsung_fimc_variant {
*
* @variant: the variant information for this driver.
* @dev_cnt: number of fimc sub-devices available in SoC
+ * @lclk_frequency: fimc bus clock frequency
*/
struct samsung_fimc_driverdata {
struct samsung_fimc_variant *variant[FIMC_MAX_DEVS];
- int devs_cnt;
+ unsigned long lclk_frequency;
+ int devs_cnt;
};
struct fimc_ctx;
@@ -322,19 +395,23 @@ struct fimc_ctx;
* @slock: the spinlock protecting this data structure
* @lock: the mutex protecting this data structure
* @pdev: pointer to the FIMC platform device
+ * @pdata: pointer to the device platform data
* @id: FIMC device index (0..2)
* @clock[]: the clocks required for FIMC operation
* @regs: the mapped hardware registers
* @regs_res: the resource claimed for IO registers
* @irq: interrupt number of the FIMC subdevice
* @irqlock: spinlock protecting videobuffer queue
+ * @irq_queue:
* @m2m: memory-to-memory V4L2 device information
- * @state: the FIMC device state flags
+ * @vid_cap: camera capture device information
+ * @state: flags used to synchronize m2m and capture mode operation
*/
struct fimc_dev {
spinlock_t slock;
struct mutex lock;
struct platform_device *pdev;
+ struct s3c_platform_fimc *pdata;
struct samsung_fimc_variant *variant;
int id;
struct clk *clock[NUM_FIMC_CLOCKS];
@@ -342,7 +419,9 @@ struct fimc_dev {
struct resource *regs_res;
int irq;
spinlock_t irqlock;
+ wait_queue_head_t irq_queue;
struct fimc_m2m_device m2m;
+ struct fimc_vid_cap vid_cap;
unsigned long state;
};
@@ -387,6 +466,7 @@ struct fimc_ctx {
struct v4l2_m2m_ctx *m2m_ctx;
};
+extern struct videobuf_queue_ops fimc_qops;
static inline int tiled_fmt(struct fimc_fmt *fmt)
{
@@ -433,7 +513,10 @@ static inline struct fimc_frame *ctx_get_frame(struct fimc_ctx *ctx,
struct fimc_frame *frame;
if (V4L2_BUF_TYPE_VIDEO_OUTPUT == type) {
- frame = &ctx->s_frame;
+ if (ctx->state & FIMC_CTX_M2M)
+ frame = &ctx->s_frame;
+ else
+ return ERR_PTR(-EINVAL);
} else if (V4L2_BUF_TYPE_VIDEO_CAPTURE == type) {
frame = &ctx->d_frame;
} else {
@@ -445,6 +528,13 @@ static inline struct fimc_frame *ctx_get_frame(struct fimc_ctx *ctx,
return frame;
}
+static inline u32 fimc_hw_get_frame_index(struct fimc_dev *dev)
+{
+ u32 reg = readl(dev->regs + S5P_CISTATUS);
+ return (reg & S5P_CISTATUS_FRAMECNT_MASK) >>
+ S5P_CISTATUS_FRAMECNT_SHIFT;
+}
+
/* -----------------------------------------------------*/
/* fimc-reg.c */
void fimc_hw_reset(struct fimc_dev *fimc);
@@ -462,6 +552,52 @@ void fimc_hw_set_output_path(struct fimc_ctx *ctx);
void fimc_hw_set_input_addr(struct fimc_dev *fimc, struct fimc_addr *paddr);
void fimc_hw_set_output_addr(struct fimc_dev *fimc, struct fimc_addr *paddr,
int index);
+int fimc_hw_set_camera_source(struct fimc_dev *fimc,
+ struct s3c_fimc_isp_info *cam);
+int fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f);
+int fimc_hw_set_camera_polarity(struct fimc_dev *fimc,
+ struct s3c_fimc_isp_info *cam);
+int fimc_hw_set_camera_type(struct fimc_dev *fimc,
+ struct s3c_fimc_isp_info *cam);
+
+/* -----------------------------------------------------*/
+/* fimc-core.c */
+int fimc_vidioc_enum_fmt(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f);
+int fimc_vidioc_g_fmt(struct file *file, void *priv,
+ struct v4l2_format *f);
+int fimc_vidioc_try_fmt(struct file *file, void *priv,
+ struct v4l2_format *f);
+int fimc_vidioc_g_crop(struct file *file, void *fh,
+ struct v4l2_crop *cr);
+int fimc_vidioc_cropcap(struct file *file, void *fh,
+ struct v4l2_cropcap *cr);
+int fimc_vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc);
+int fimc_vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl);
+
+int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr);
+int check_ctrl_val(struct fimc_ctx *ctx, struct v4l2_control *ctrl);
+int fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_control *ctrl);
+
+struct fimc_fmt *find_format(struct v4l2_format *f, unsigned int mask);
+struct fimc_fmt *find_mbus_format(struct v4l2_mbus_framefmt *f,
+ unsigned int mask);
+
+int fimc_check_scaler_ratio(struct v4l2_rect *r, struct fimc_frame *f);
+int fimc_set_scaler_info(struct fimc_ctx *ctx);
+int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags);
+int fimc_prepare_addr(struct fimc_ctx *ctx, struct fimc_vid_buffer *buf,
+ struct fimc_frame *frame, struct fimc_addr *paddr);
+
+/* -----------------------------------------------------*/
+/* fimc-capture.c */
+int fimc_register_capture_device(struct fimc_dev *fimc);
+void fimc_unregister_capture_device(struct fimc_dev *fimc);
+int fimc_sensor_sd_init(struct fimc_dev *fimc, int index);
+int fimc_vid_cap_buf_queue(struct fimc_dev *fimc,
+ struct fimc_vid_buffer *fimc_vb);
/* Locking: the caller holds fimc->slock */
static inline void fimc_activate_capture(struct fimc_ctx *ctx)
@@ -478,4 +614,51 @@ static inline void fimc_deactivate_capture(struct fimc_dev *fimc)
fimc_hw_en_lastirq(fimc, false);
}
+/*
+ * Add video buffer to the active buffers queue.
+ * The caller holds irqlock spinlock.
+ */
+static inline void active_queue_add(struct fimc_vid_cap *vid_cap,
+ struct fimc_vid_buffer *buf)
+{
+ buf->vb.state = VIDEOBUF_ACTIVE;
+ list_add_tail(&buf->vb.queue, &vid_cap->active_buf_q);
+ vid_cap->active_buf_cnt++;
+}
+
+/*
+ * Pop a video buffer from the capture active buffers queue
+ * Locking: Need to be called with dev->slock held.
+ */
+static inline struct fimc_vid_buffer *
+active_queue_pop(struct fimc_vid_cap *vid_cap)
+{
+ struct fimc_vid_buffer *buf;
+ buf = list_entry(vid_cap->active_buf_q.next,
+ struct fimc_vid_buffer, vb.queue);
+ list_del(&buf->vb.queue);
+ vid_cap->active_buf_cnt--;
+ return buf;
+}
+
+/* Add video buffer to the capture pending buffers queue */
+static inline void fimc_pending_queue_add(struct fimc_vid_cap *vid_cap,
+ struct fimc_vid_buffer *buf)
+{
+ buf->vb.state = VIDEOBUF_QUEUED;
+ list_add_tail(&buf->vb.queue, &vid_cap->pending_buf_q);
+}
+
+/* Add video buffer to the capture pending buffers queue */
+static inline struct fimc_vid_buffer *
+pending_queue_pop(struct fimc_vid_cap *vid_cap)
+{
+ struct fimc_vid_buffer *buf;
+ buf = list_entry(vid_cap->pending_buf_q.next,
+ struct fimc_vid_buffer, vb.queue);
+ list_del(&buf->vb.queue);
+ return buf;
+}
+
+
#endif /* FIMC_CORE_H_ */
diff --git a/drivers/media/video/s5p-fimc/fimc-reg.c b/drivers/media/video/s5p-fimc/fimc-reg.c
index 95adc84..511631a 100644
--- a/drivers/media/video/s5p-fimc/fimc-reg.c
+++ b/drivers/media/video/s5p-fimc/fimc-reg.c
@@ -13,6 +13,7 @@
#include <linux/io.h>
#include <linux/delay.h>
#include <mach/map.h>
+#include <media/s3c_fimc.h>
#include "fimc-core.h"
@@ -176,6 +177,15 @@ static void fimc_hw_set_out_dma_size(struct fimc_ctx *ctx)
cfg = S5P_ORIG_SIZE_HOR(frame->f_width);
cfg |= S5P_ORIG_SIZE_VER(frame->f_height);
writel(cfg, dev->regs + S5P_ORGOSIZE);
+
+ /* Select color space conversion equation (HD/SD size).*/
+ cfg = readl(dev->regs + S5P_CIGCTRL);
+ if (frame->f_width >= 1280) /* HD */
+ cfg |= S5P_CIGCTRL_CSC_ITU601_709;
+ else /* SD */
+ cfg &= ~S5P_CIGCTRL_CSC_ITU601_709;
+ writel(cfg, dev->regs + S5P_CIGCTRL);
+
}
void fimc_hw_set_out_dma(struct fimc_ctx *ctx)
@@ -231,19 +241,12 @@ static void fimc_hw_en_autoload(struct fimc_dev *dev, int enable)
void fimc_hw_en_lastirq(struct fimc_dev *dev, int enable)
{
- unsigned long flags;
- u32 cfg;
-
- spin_lock_irqsave(&dev->slock, flags);
-
- cfg = readl(dev->regs + S5P_CIOCTRL);
+ u32 cfg = readl(dev->regs + S5P_CIOCTRL);
if (enable)
cfg |= S5P_CIOCTRL_LASTIRQ_ENABLE;
else
cfg &= ~S5P_CIOCTRL_LASTIRQ_ENABLE;
writel(cfg, dev->regs + S5P_CIOCTRL);
-
- spin_unlock_irqrestore(&dev->slock, flags);
}
static void fimc_hw_set_prescaler(struct fimc_ctx *ctx)
@@ -325,14 +328,18 @@ void fimc_hw_set_scaler(struct fimc_ctx *ctx)
void fimc_hw_en_capture(struct fimc_ctx *ctx)
{
struct fimc_dev *dev = ctx->fimc_dev;
- u32 cfg;
- cfg = readl(dev->regs + S5P_CIIMGCPT);
- /* One shot mode for output DMA or freerun for FIFO. */
- if (ctx->out_path == FIMC_DMA)
- cfg |= S5P_CIIMGCPT_CPT_FREN_ENABLE;
- else
- cfg &= ~S5P_CIIMGCPT_CPT_FREN_ENABLE;
+ u32 cfg = readl(dev->regs + S5P_CIIMGCPT);
+
+ if (ctx->out_path == FIMC_DMA) {
+ /* one shot mode */
+ cfg |= S5P_CIIMGCPT_CPT_FREN_ENABLE | S5P_CIIMGCPT_IMGCPTEN;
+ } else {
+ /* Continous frame capture mode (freerun). */
+ cfg &= ~(S5P_CIIMGCPT_CPT_FREN_ENABLE |
+ S5P_CIIMGCPT_CPT_FRMOD_CNT);
+ cfg |= S5P_CIIMGCPT_IMGCPTEN;
+ }
if (ctx->scaler.enabled)
cfg |= S5P_CIIMGCPT_IMGCPTEN_SC;
@@ -523,3 +530,139 @@ void fimc_hw_set_output_addr(struct fimc_dev *dev,
i, paddr->y, paddr->cb, paddr->cr);
} while (index == -1 && ++i < FIMC_MAX_OUT_BUFS);
}
+
+int fimc_hw_set_camera_polarity(struct fimc_dev *fimc,
+ struct s3c_fimc_isp_info *cam)
+{
+ u32 cfg = readl(fimc->regs + S5P_CIGCTRL);
+
+ cfg &= ~(S5P_CIGCTRL_INVPOLPCLK | S5P_CIGCTRL_INVPOLVSYNC |
+ S5P_CIGCTRL_INVPOLHREF | S5P_CIGCTRL_INVPOLHSYNC);
+
+ if (cam->flags & FIMC_CLK_INV_PCLK)
+ cfg |= S5P_CIGCTRL_INVPOLPCLK;
+
+ if (cam->flags & FIMC_CLK_INV_VSYNC)
+ cfg |= S5P_CIGCTRL_INVPOLVSYNC;
+
+ if (cam->flags & FIMC_CLK_INV_HREF)
+ cfg |= S5P_CIGCTRL_INVPOLHREF;
+
+ if (cam->flags & FIMC_CLK_INV_HSYNC)
+ cfg |= S5P_CIGCTRL_INVPOLHSYNC;
+
+ writel(cfg, fimc->regs + S5P_CIGCTRL);
+
+ return 0;
+}
+
+int fimc_hw_set_camera_source(struct fimc_dev *fimc,
+ struct s3c_fimc_isp_info *cam)
+{
+ struct fimc_frame *f = &fimc->vid_cap.ctx->s_frame;
+ u32 cfg = 0;
+
+ if (cam->bus_type == FIMC_ITU_601 || cam->bus_type == FIMC_ITU_656) {
+
+ switch (fimc->vid_cap.fmt.code) {
+ case V4L2_MBUS_FMT_YUYV8_2X8:
+ cfg = S5P_CISRCFMT_ORDER422_YCBYCR;
+ break;
+ case V4L2_MBUS_FMT_YVYU8_2X8:
+ cfg = S5P_CISRCFMT_ORDER422_YCRYCB;
+ break;
+ case V4L2_MBUS_FMT_VYUY8_2X8:
+ cfg = S5P_CISRCFMT_ORDER422_CRYCBY;
+ break;
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ cfg = S5P_CISRCFMT_ORDER422_CBYCRY;
+ break;
+ default:
+ err("camera image format not supported: %d",
+ fimc->vid_cap.fmt.code);
+ return -EINVAL;
+ }
+
+ if (cam->bus_type == FIMC_ITU_601) {
+ if (cam->bus_width == 8) {
+ cfg |= S5P_CISRCFMT_ITU601_8BIT;
+ } else if (cam->bus_width == 16) {
+ cfg |= S5P_CISRCFMT_ITU601_16BIT;
+ } else {
+ err("invalid bus width: %d", cam->bus_width);
+ return -EINVAL;
+ }
+ } /* else defaults to ITU-R BT.656 8-bit */
+ }
+
+ cfg |= S5P_CISRCFMT_HSIZE(f->o_width) | S5P_CISRCFMT_VSIZE(f->o_height);
+ writel(cfg, fimc->regs + S5P_CISRCFMT);
+ return 0;
+}
+
+
+int fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f)
+{
+ u32 hoff2, voff2;
+
+ u32 cfg = readl(fimc->regs + S5P_CIWDOFST);
+
+ cfg &= ~(S5P_CIWDOFST_HOROFF_MASK | S5P_CIWDOFST_VEROFF_MASK);
+ cfg |= S5P_CIWDOFST_OFF_EN |
+ S5P_CIWDOFST_HOROFF(f->offs_h) |
+ S5P_CIWDOFST_VEROFF(f->offs_v);
+
+ writel(cfg, fimc->regs + S5P_CIWDOFST);
+
+ /* See CIWDOFSTn register description in the datasheet for details. */
+ hoff2 = f->o_width - f->width - f->offs_h;
+ voff2 = f->o_height - f->height - f->offs_v;
+ cfg = S5P_CIWDOFST2_HOROFF(hoff2) | S5P_CIWDOFST2_VEROFF(voff2);
+
+ writel(cfg, fimc->regs + S5P_CIWDOFST2);
+ return 0;
+}
+
+int fimc_hw_set_camera_type(struct fimc_dev *fimc,
+ struct s3c_fimc_isp_info *cam)
+{
+ u32 cfg, tmp;
+ struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
+
+ cfg = readl(fimc->regs + S5P_CIGCTRL);
+
+ /* Select ITU B interface, disable Writeback path and test pattern. */
+ cfg &= ~(S5P_CIGCTRL_TESTPAT_MASK | S5P_CIGCTRL_SELCAM_ITU_A |
+ S5P_CIGCTRL_SELCAM_MIPI | S5P_CIGCTRL_CAMIF_SELWB |
+ S5P_CIGCTRL_SELCAM_MIPI_A);
+
+ if (cam->bus_type == FIMC_MIPI_CSI2) {
+ cfg |= S5P_CIGCTRL_SELCAM_MIPI;
+
+ if (cam->mux_id == 0)
+ cfg |= S5P_CIGCTRL_SELCAM_MIPI_A;
+
+ /* TODO: add remaining supported formats. */
+ if (vid_cap->fmt.code == V4L2_MBUS_FMT_VYUY8_2X8) {
+ tmp = S5P_CSIIMGFMT_YCBCR422_8BIT;
+ } else {
+ err("camera image format not supported: %d",
+ vid_cap->fmt.code);
+ return -EINVAL;
+ }
+ writel(tmp | (0x1 << 8), fimc->regs + S5P_CSIIMGFMT);
+
+ } else if (cam->bus_type == FIMC_ITU_601 ||
+ cam->bus_type == FIMC_ITU_656) {
+ if (cam->mux_id == 0) /* ITU-A, ITU-B: 0, 1 */
+ cfg |= S5P_CIGCTRL_SELCAM_ITU_A;
+ } else if (cam->bus_type == FIMC_LCD_WB) {
+ cfg |= S5P_CIGCTRL_CAMIF_SELWB;
+ } else {
+ err("invalid camera bus type selected\n");
+ return -EINVAL;
+ }
+ writel(cfg, fimc->regs + S5P_CIGCTRL);
+
+ return 0;
+}
diff --git a/include/media/s3c_fimc.h b/include/media/s3c_fimc.h
new file mode 100644
index 0000000..ca1b673
--- /dev/null
+++ b/include/media/s3c_fimc.h
@@ -0,0 +1,60 @@
+/*
+ * Samsung S5P SoC camera interface driver header
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd
+ * Author: Sylwester Nawrocki, <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef S3C_FIMC_H_
+#define S3C_FIMC_H_
+
+enum cam_bus_type {
+ FIMC_ITU_601 = 1,
+ FIMC_ITU_656,
+ FIMC_MIPI_CSI2,
+ FIMC_LCD_WB, /* FIFO link from LCD mixer */
+};
+
+#define FIMC_CLK_INV_PCLK (1 << 0)
+#define FIMC_CLK_INV_VSYNC (1 << 1)
+#define FIMC_CLK_INV_HREF (1 << 2)
+#define FIMC_CLK_INV_HSYNC (1 << 3)
+
+struct i2c_board_info;
+
+/**
+ * struct s3c_fimc_isp_info - image sensor information required for host
+ * interace configuration.
+ *
+ * @board_info: pointer to I2C subdevice's board info
+ * @bus_type: determines bus type, MIPI, ITU-R BT.601 etc.
+ * @i2c_bus_num: i2c control bus id the sensor is attached to
+ * @mux_id: FIMC camera interface multiplexer index (separate for MIPI and ITU)
+ * @bus_width: camera data bus width in bits
+ * @flags: flags defining bus signals polarity inversion (High by default)
+ */
+struct s3c_fimc_isp_info {
+ struct i2c_board_info *board_info;
+ enum cam_bus_type bus_type;
+ u16 i2c_bus_num;
+ u16 mux_id;
+ u16 bus_width;
+ u16 flags;
+};
+
+
+#define FIMC_MAX_CAMIF_CLIENTS 2
+
+/**
+ * struct s3c_platform_fimc - camera host interface platform data
+ *
+ * @isp_info: properties of camera sensor required for host interface setup
+ */
+struct s3c_platform_fimc {
+ struct s3c_fimc_isp_info *isp_info[FIMC_MAX_CAMIF_CLIENTS];
+};
+#endif /* S3C_FIMC_H_ */
--
1.7.3.1
^ permalink raw reply related
* [PATCH 5/5 v4] V4L/DVB: s5p-fimc: Add camera capture support
From: Sylwester Nawrocki @ 2010-10-08 8:50 UTC (permalink / raw)
To: linux-media, linux-arm-kernel, linux-samsung-soc
Cc: m.szyprowski, kyungmin.park, s.nawrocki
In-Reply-To: <1286527837-4980-1-git-send-email-s.nawrocki@samsung.com>
Add a video device driver per each FIMC entity to support
the camera capture input mode. Video capture node is registered
only if CCD sensor data is provided through driver's platfrom data
and board setup code.
Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Reviewed-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
drivers/media/video/s5p-fimc/Makefile | 2 +-
drivers/media/video/s5p-fimc/fimc-capture.c | 816 +++++++++++++++++++++++++++
drivers/media/video/s5p-fimc/fimc-core.c | 585 ++++++++++++++------
drivers/media/video/s5p-fimc/fimc-core.h | 205 +++++++-
drivers/media/video/s5p-fimc/fimc-reg.c | 173 ++++++-
include/media/s3c_fimc.h | 60 ++
6 files changed, 1649 insertions(+), 192 deletions(-)
create mode 100644 drivers/media/video/s5p-fimc/fimc-capture.c
create mode 100644 include/media/s3c_fimc.h
diff --git a/drivers/media/video/s5p-fimc/Makefile b/drivers/media/video/s5p-fimc/Makefile
index 0d9d541..7ea1b14 100644
--- a/drivers/media/video/s5p-fimc/Makefile
+++ b/drivers/media/video/s5p-fimc/Makefile
@@ -1,3 +1,3 @@
obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) := s5p-fimc.o
-s5p-fimc-y := fimc-core.o fimc-reg.o
+s5p-fimc-y := fimc-core.o fimc-reg.o fimc-capture.o
diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c
new file mode 100644
index 0000000..b224ca9
--- /dev/null
+++ b/drivers/media/video/s5p-fimc/fimc-capture.c
@@ -0,0 +1,816 @@
+/*
+ * Samsung S5P SoC series camera interface (camera capture) driver
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd
+ * Author: Sylwester Nawrocki, <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/bug.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/i2c.h>
+
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf-core.h>
+#include <media/videobuf-dma-contig.h>
+
+#include "fimc-core.h"
+
+static struct v4l2_subdev *fimc_subdev_register(struct fimc_dev *fimc,
+ struct s3c_fimc_isp_info *isp_info)
+{
+ struct i2c_adapter *i2c_adap;
+ struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
+ struct v4l2_subdev *sd = NULL;
+
+ i2c_adap = i2c_get_adapter(isp_info->i2c_bus_num);
+ if (!i2c_adap)
+ return ERR_PTR(-ENOMEM);
+
+ sd = v4l2_i2c_new_subdev_board(&vid_cap->v4l2_dev, i2c_adap,
+ MODULE_NAME, isp_info->board_info, NULL);
+ if (!sd) {
+ v4l2_err(&vid_cap->v4l2_dev, "failed to acquire subdev\n");
+ return NULL;
+ }
+
+ v4l2_info(&vid_cap->v4l2_dev, "subdevice %s registered successfuly\n",
+ isp_info->board_info->type);
+
+ return sd;
+}
+
+static void fimc_subdev_unregister(struct fimc_dev *fimc)
+{
+ struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
+ struct i2c_client *client;
+
+ if (vid_cap->input_index < 0)
+ return; /* Subdevice already released or not registered. */
+
+ if (vid_cap->sd) {
+ v4l2_device_unregister_subdev(vid_cap->sd);
+ client = v4l2_get_subdevdata(vid_cap->sd);
+ i2c_unregister_device(client);
+ i2c_put_adapter(client->adapter);
+ vid_cap->sd = NULL;
+ }
+
+ vid_cap->input_index = -1;
+}
+
+/**
+ * fimc_subdev_attach - attach v4l2_subdev to camera host interface
+ *
+ * @fimc: FIMC device information
+ * @index: index to the array of available subdevices,
+ * -1 for full array search or non negative value
+ * to select specific subdevice
+ */
+static int fimc_subdev_attach(struct fimc_dev *fimc, int index)
+{
+ struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
+ struct s3c_platform_fimc *pdata = fimc->pdata;
+ struct s3c_fimc_isp_info *isp_info;
+ struct v4l2_subdev *sd;
+ int i;
+
+ for (i = 0; i < FIMC_MAX_CAMIF_CLIENTS; ++i) {
+ isp_info = pdata->isp_info[i];
+
+ if (!isp_info || (index >= 0 && i != index))
+ continue;
+
+ sd = fimc_subdev_register(fimc, isp_info);
+ if (sd) {
+ vid_cap->sd = sd;
+ vid_cap->input_index = i;
+
+ return 0;
+ }
+ }
+
+ vid_cap->input_index = -1;
+ vid_cap->sd = NULL;
+ v4l2_err(&vid_cap->v4l2_dev, "fimc%d: sensor attach failed\n",
+ fimc->id);
+ return -ENODEV;
+}
+
+static int fimc_isp_subdev_init(struct fimc_dev *fimc, int index)
+{
+ struct s3c_fimc_isp_info *isp_info;
+ int ret;
+
+ ret = fimc_subdev_attach(fimc, index);
+ if (ret)
+ return ret;
+
+ isp_info = fimc->pdata->isp_info[fimc->vid_cap.input_index];
+ ret = fimc_hw_set_camera_polarity(fimc, isp_info);
+ if (!ret) {
+ ret = v4l2_subdev_call(fimc->vid_cap.sd, core,
+ s_power, 1);
+ if (!ret)
+ return ret;
+ }
+
+ fimc_subdev_unregister(fimc);
+ err("ISP initialization failed: %d", ret);
+ return ret;
+}
+
+/*
+ * At least one buffer on the pending_buf_q queue is required.
+ * Locking: The caller holds fimc->slock spinlock.
+ */
+int fimc_vid_cap_buf_queue(struct fimc_dev *fimc,
+ struct fimc_vid_buffer *fimc_vb)
+{
+ struct fimc_vid_cap *cap = &fimc->vid_cap;
+ struct fimc_ctx *ctx = cap->ctx;
+ int ret = 0;
+
+ BUG_ON(!fimc || !fimc_vb);
+
+ ret = fimc_prepare_addr(ctx, fimc_vb, &ctx->d_frame,
+ &fimc_vb->paddr);
+ if (ret)
+ return ret;
+
+ if (test_bit(ST_CAPT_STREAM, &fimc->state)) {
+ fimc_pending_queue_add(cap, fimc_vb);
+ } else {
+ /* Setup the buffer directly for processing. */
+ int buf_id = (cap->reqbufs_count == 1) ? -1 : cap->buf_index;
+ fimc_hw_set_output_addr(fimc, &fimc_vb->paddr, buf_id);
+
+ fimc_vb->index = cap->buf_index;
+ active_queue_add(cap, fimc_vb);
+
+ if (++cap->buf_index >= FIMC_MAX_OUT_BUFS)
+ cap->buf_index = 0;
+ }
+ return ret;
+}
+
+static int fimc_stop_capture(struct fimc_dev *fimc)
+{
+ unsigned long flags;
+ struct fimc_vid_cap *cap;
+ int ret;
+
+ cap = &fimc->vid_cap;
+
+ if (!fimc_capture_active(fimc))
+ return 0;
+
+ spin_lock_irqsave(&fimc->slock, flags);
+ set_bit(ST_CAPT_SHUT, &fimc->state);
+ fimc_deactivate_capture(fimc);
+ spin_unlock_irqrestore(&fimc->slock, flags);
+
+ wait_event_timeout(fimc->irq_queue,
+ test_bit(ST_CAPT_SHUT, &fimc->state),
+ FIMC_SHUTDOWN_TIMEOUT);
+
+ ret = v4l2_subdev_call(cap->sd, video, s_stream, 0);
+ if (ret)
+ v4l2_err(&fimc->vid_cap.v4l2_dev, "s_stream(0) failed\n");
+
+ spin_lock_irqsave(&fimc->slock, flags);
+ fimc->state &= ~(1 << ST_CAPT_RUN | 1 << ST_CAPT_PEND |
+ 1 << ST_CAPT_STREAM);
+
+ fimc->vid_cap.active_buf_cnt = 0;
+ spin_unlock_irqrestore(&fimc->slock, flags);
+
+ dbg("state: 0x%lx", fimc->state);
+ return 0;
+}
+
+static int fimc_capture_open(struct file *file)
+{
+ struct fimc_dev *fimc = video_drvdata(file);
+ int ret = 0;
+
+ dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state);
+
+ /* Return if the corresponding video mem2mem node is already opened. */
+ if (fimc_m2m_active(fimc))
+ return -EBUSY;
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ if (++fimc->vid_cap.refcnt == 1) {
+ ret = fimc_isp_subdev_init(fimc, -1);
+ if (ret) {
+ fimc->vid_cap.refcnt--;
+ ret = -EIO;
+ }
+ }
+
+ file->private_data = fimc->vid_cap.ctx;
+
+ mutex_unlock(&fimc->lock);
+ return ret;
+}
+
+static int fimc_capture_close(struct file *file)
+{
+ struct fimc_dev *fimc = video_drvdata(file);
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state);
+
+ if (--fimc->vid_cap.refcnt == 0) {
+ fimc_stop_capture(fimc);
+
+ videobuf_stop(&fimc->vid_cap.vbq);
+ videobuf_mmap_free(&fimc->vid_cap.vbq);
+
+ v4l2_err(&fimc->vid_cap.v4l2_dev, "releasing ISP\n");
+ v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 0);
+ fimc_subdev_unregister(fimc);
+ }
+
+ mutex_unlock(&fimc->lock);
+ return 0;
+}
+
+static unsigned int fimc_capture_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct fimc_ctx *ctx = file->private_data;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct fimc_vid_cap *cap = &fimc->vid_cap;
+ int ret;
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return POLLERR;
+
+ ret = videobuf_poll_stream(file, &cap->vbq, wait);
+ mutex_unlock(&fimc->lock);
+
+ return ret;
+}
+
+static int fimc_capture_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct fimc_ctx *ctx = file->private_data;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct fimc_vid_cap *cap = &fimc->vid_cap;
+ int ret;
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ ret = videobuf_mmap_mapper(&cap->vbq, vma);
+ mutex_unlock(&fimc->lock);
+
+ return ret;
+}
+
+/* video device file operations */
+static const struct v4l2_file_operations fimc_capture_fops = {
+ .owner = THIS_MODULE,
+ .open = fimc_capture_open,
+ .release = fimc_capture_close,
+ .poll = fimc_capture_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = fimc_capture_mmap,
+};
+
+static int fimc_vidioc_querycap_capture(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct fimc_ctx *ctx = file->private_data;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+
+ strncpy(cap->driver, fimc->pdev->name, sizeof(cap->driver) - 1);
+ strncpy(cap->card, fimc->pdev->name, sizeof(cap->card) - 1);
+ cap->bus_info[0] = 0;
+ cap->version = KERNEL_VERSION(1, 0, 0);
+ cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE;
+
+ return 0;
+}
+
+/* Synchronize formats of the camera interface input and attached sensor. */
+static int sync_capture_fmt(struct fimc_ctx *ctx)
+{
+ struct fimc_frame *frame = &ctx->s_frame;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct v4l2_mbus_framefmt *fmt = &fimc->vid_cap.fmt;
+ int ret;
+
+ fmt->width = ctx->d_frame.o_width;
+ fmt->height = ctx->d_frame.o_height;
+
+ ret = v4l2_subdev_call(fimc->vid_cap.sd, video, s_mbus_fmt, fmt);
+ if (ret == -ENOIOCTLCMD) {
+ err("s_mbus_fmt failed");
+ return ret;
+ }
+ dbg("w: %d, h: %d, code= %d", fmt->width, fmt->height, fmt->code);
+
+ frame->fmt = find_mbus_format(fmt, FMT_FLAGS_CAM);
+ if (!frame->fmt) {
+ err("fimc source format not found\n");
+ return -EINVAL;
+ }
+
+ frame->f_width = fmt->width;
+ frame->f_height = fmt->height;
+ frame->width = fmt->width;
+ frame->height = fmt->height;
+ frame->o_width = fmt->width;
+ frame->o_height = fmt->height;
+ frame->offs_h = 0;
+ frame->offs_v = 0;
+
+ return 0;
+}
+
+static int fimc_cap_s_fmt(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct fimc_ctx *ctx = priv;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct fimc_frame *frame;
+ struct v4l2_pix_format *pix;
+ int ret;
+
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ ret = fimc_vidioc_try_fmt(file, priv, f);
+ if (ret)
+ return ret;
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ if (fimc_capture_active(fimc)) {
+ ret = -EBUSY;
+ goto sf_unlock;
+ }
+
+ frame = &ctx->d_frame;
+
+ pix = &f->fmt.pix;
+ frame->fmt = find_format(f, FMT_FLAGS_M2M | FMT_FLAGS_CAM);
+ if (!frame->fmt) {
+ err("fimc target format not found\n");
+ ret = -EINVAL;
+ goto sf_unlock;
+ }
+
+ /* Output DMA frame pixel size and offsets. */
+ frame->f_width = pix->bytesperline * 8 / frame->fmt->depth;
+ frame->f_height = pix->height;
+ frame->width = pix->width;
+ frame->height = pix->height;
+ frame->o_width = pix->width;
+ frame->o_height = pix->height;
+ frame->size = (pix->width * pix->height * frame->fmt->depth) >> 3;
+ frame->offs_h = 0;
+ frame->offs_v = 0;
+
+ ret = sync_capture_fmt(ctx);
+
+ ctx->state |= (FIMC_PARAMS | FIMC_DST_FMT);
+
+sf_unlock:
+ mutex_unlock(&fimc->lock);
+ return ret;
+}
+
+static int fimc_cap_enum_input(struct file *file, void *priv,
+ struct v4l2_input *i)
+{
+ struct fimc_ctx *ctx = priv;
+ struct s3c_platform_fimc *pldata = ctx->fimc_dev->pdata;
+ struct s3c_fimc_isp_info *isp_info;
+
+ if (i->index >= FIMC_MAX_CAMIF_CLIENTS)
+ return -EINVAL;
+
+ isp_info = pldata->isp_info[i->index];
+ if (isp_info == NULL)
+ return -EINVAL;
+
+ i->type = V4L2_INPUT_TYPE_CAMERA;
+ strncpy(i->name, isp_info->board_info->type, 32);
+ return 0;
+}
+
+static int fimc_cap_s_input(struct file *file, void *priv,
+ unsigned int i)
+{
+ struct fimc_ctx *ctx = priv;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct s3c_platform_fimc *pdata = fimc->pdata;
+ int ret;
+
+ if (fimc_capture_active(ctx->fimc_dev))
+ return -EBUSY;
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ if (i >= FIMC_MAX_CAMIF_CLIENTS || !pdata->isp_info[i]) {
+ ret = -EINVAL;
+ goto si_unlock;
+ }
+
+ if (fimc->vid_cap.sd) {
+ ret = v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 0);
+ if (ret)
+ err("s_power failed: %d", ret);
+ }
+
+ /* Release the attached sensor subdevice. */
+ fimc_subdev_unregister(fimc);
+
+ ret = fimc_isp_subdev_init(fimc, i);
+
+si_unlock:
+ mutex_unlock(&fimc->lock);
+ return ret;
+}
+
+static int fimc_cap_g_input(struct file *file, void *priv,
+ unsigned int *i)
+{
+ struct fimc_ctx *ctx = priv;
+ struct fimc_vid_cap *cap = &ctx->fimc_dev->vid_cap;
+
+ *i = cap->input_index;
+ return 0;
+}
+
+static int fimc_cap_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct s3c_fimc_isp_info *isp_info;
+ struct fimc_ctx *ctx = priv;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ int ret = -EBUSY;
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ if (fimc_capture_active(fimc) || !fimc->vid_cap.sd)
+ goto s_unlock;
+
+ if (!(ctx->state & FIMC_DST_FMT)) {
+ v4l2_err(&fimc->vid_cap.v4l2_dev, "Format is not set\n");
+ ret = -EINVAL;
+ goto s_unlock;
+ }
+
+ ret = v4l2_subdev_call(fimc->vid_cap.sd, video, s_stream, 1);
+ if (ret && ret != -ENOIOCTLCMD)
+ goto s_unlock;
+
+ ret = fimc_prepare_config(ctx, ctx->state);
+ if (ret)
+ goto s_unlock;
+
+ isp_info = fimc->pdata->isp_info[fimc->vid_cap.input_index];
+ fimc_hw_set_camera_type(fimc, isp_info);
+ fimc_hw_set_camera_source(fimc, isp_info);
+ fimc_hw_set_camera_offset(fimc, &ctx->s_frame);
+
+ if (ctx->state & FIMC_PARAMS) {
+ ret = fimc_set_scaler_info(ctx);
+ if (ret) {
+ err("Scaler setup error");
+ goto s_unlock;
+ }
+ fimc_hw_set_input_path(ctx);
+ fimc_hw_set_scaler(ctx);
+ fimc_hw_set_target_format(ctx);
+ fimc_hw_set_rotation(ctx);
+ fimc_hw_set_effect(ctx);
+ }
+
+ fimc_hw_set_output_path(ctx);
+ fimc_hw_set_out_dma(ctx);
+
+ INIT_LIST_HEAD(&fimc->vid_cap.pending_buf_q);
+ INIT_LIST_HEAD(&fimc->vid_cap.active_buf_q);
+ fimc->vid_cap.active_buf_cnt = 0;
+ fimc->vid_cap.frame_count = 0;
+
+ set_bit(ST_CAPT_PEND, &fimc->state);
+ ret = videobuf_streamon(&fimc->vid_cap.vbq);
+
+s_unlock:
+ mutex_unlock(&fimc->lock);
+ return ret;
+}
+
+static int fimc_cap_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct fimc_ctx *ctx = priv;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct fimc_vid_cap *cap = &fimc->vid_cap;
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&fimc->slock, flags);
+ if (!fimc_capture_running(fimc) && !fimc_capture_pending(fimc)) {
+ spin_unlock_irqrestore(&fimc->slock, flags);
+ dbg("state: 0x%lx", fimc->state);
+ return -EINVAL;
+ }
+ spin_unlock_irqrestore(&fimc->slock, flags);
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ fimc_stop_capture(fimc);
+ ret = videobuf_streamoff(&cap->vbq);
+ mutex_unlock(&fimc->lock);
+ return ret;
+}
+
+static int fimc_cap_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *reqbufs)
+{
+ struct fimc_ctx *ctx = priv;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct fimc_vid_cap *cap = &fimc->vid_cap;
+ int ret;
+
+ if (fimc_capture_active(ctx->fimc_dev))
+ return -EBUSY;
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ ret = videobuf_reqbufs(&cap->vbq, reqbufs);
+ if (!ret)
+ cap->reqbufs_count = reqbufs->count;
+
+ mutex_unlock(&fimc->lock);
+ return ret;
+}
+
+static int fimc_cap_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct fimc_ctx *ctx = priv;
+ struct fimc_vid_cap *cap = &ctx->fimc_dev->vid_cap;
+
+ if (fimc_capture_active(ctx->fimc_dev))
+ return -EBUSY;
+
+ return videobuf_querybuf(&cap->vbq, buf);
+}
+
+static int fimc_cap_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct fimc_ctx *ctx = priv;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct fimc_vid_cap *cap = &fimc->vid_cap;
+ int ret;
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ ret = videobuf_qbuf(&cap->vbq, buf);
+
+ mutex_unlock(&fimc->lock);
+ return ret;
+}
+
+static int fimc_cap_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct fimc_ctx *ctx = priv;
+ int ret;
+
+ if (mutex_lock_interruptible(&ctx->fimc_dev->lock))
+ return -ERESTARTSYS;
+
+ ret = videobuf_dqbuf(&ctx->fimc_dev->vid_cap.vbq, buf,
+ file->f_flags & O_NONBLOCK);
+
+ mutex_unlock(&ctx->fimc_dev->lock);
+ return ret;
+}
+
+static int fimc_cap_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct fimc_ctx *ctx = priv;
+ int ret = -EINVAL;
+
+ if (mutex_lock_interruptible(&ctx->fimc_dev->lock))
+ return -ERESTARTSYS;
+
+ /* Allow any controls but 90/270 rotation while streaming */
+ if (!fimc_capture_active(ctx->fimc_dev) ||
+ ctrl->id != V4L2_CID_ROTATE ||
+ (ctrl->value != 90 && ctrl->value != 270)) {
+ ret = check_ctrl_val(ctx, ctrl);
+ if (!ret) {
+ ret = fimc_s_ctrl(ctx, ctrl);
+ if (!ret)
+ ctx->state |= FIMC_PARAMS;
+ }
+ }
+
+ mutex_unlock(&ctx->fimc_dev->lock);
+ return ret;
+}
+
+static int fimc_cap_s_crop(struct file *file, void *fh,
+ struct v4l2_crop *cr)
+{
+ struct fimc_frame *f;
+ struct fimc_ctx *ctx = file->private_data;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ int ret = -EINVAL;
+
+ if (fimc_capture_active(fimc))
+ return -EBUSY;
+
+ ret = fimc_try_crop(ctx, cr);
+ if (ret)
+ return ret;
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ if (!(ctx->state & FIMC_DST_FMT)) {
+ v4l2_err(&fimc->vid_cap.v4l2_dev,
+ "Capture color format not set\n");
+ goto sc_unlock;
+ }
+
+ f = &ctx->s_frame;
+ /* Check for the pixel scaling ratio when cropping input image. */
+ ret = fimc_check_scaler_ratio(&cr->c, &ctx->d_frame);
+ if (ret) {
+ v4l2_err(&fimc->vid_cap.v4l2_dev, "Out of the scaler range");
+ } else {
+ ret = 0;
+ f->offs_h = cr->c.left;
+ f->offs_v = cr->c.top;
+ f->width = cr->c.width;
+ f->height = cr->c.height;
+ }
+
+sc_unlock:
+ mutex_unlock(&fimc->lock);
+ return ret;
+}
+
+
+static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = {
+ .vidioc_querycap = fimc_vidioc_querycap_capture,
+
+ .vidioc_enum_fmt_vid_cap = fimc_vidioc_enum_fmt,
+ .vidioc_try_fmt_vid_cap = fimc_vidioc_try_fmt,
+ .vidioc_s_fmt_vid_cap = fimc_cap_s_fmt,
+ .vidioc_g_fmt_vid_cap = fimc_vidioc_g_fmt,
+
+ .vidioc_reqbufs = fimc_cap_reqbufs,
+ .vidioc_querybuf = fimc_cap_querybuf,
+
+ .vidioc_qbuf = fimc_cap_qbuf,
+ .vidioc_dqbuf = fimc_cap_dqbuf,
+
+ .vidioc_streamon = fimc_cap_streamon,
+ .vidioc_streamoff = fimc_cap_streamoff,
+
+ .vidioc_queryctrl = fimc_vidioc_queryctrl,
+ .vidioc_g_ctrl = fimc_vidioc_g_ctrl,
+ .vidioc_s_ctrl = fimc_cap_s_ctrl,
+
+ .vidioc_g_crop = fimc_vidioc_g_crop,
+ .vidioc_s_crop = fimc_cap_s_crop,
+ .vidioc_cropcap = fimc_vidioc_cropcap,
+
+ .vidioc_enum_input = fimc_cap_enum_input,
+ .vidioc_s_input = fimc_cap_s_input,
+ .vidioc_g_input = fimc_cap_g_input,
+};
+
+int fimc_register_capture_device(struct fimc_dev *fimc)
+{
+ struct v4l2_device *v4l2_dev = &fimc->vid_cap.v4l2_dev;
+ struct video_device *vfd;
+ struct fimc_vid_cap *vid_cap;
+ struct fimc_ctx *ctx;
+ struct v4l2_format f;
+ int ret;
+
+ ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ ctx->fimc_dev = fimc;
+ ctx->in_path = FIMC_CAMERA;
+ ctx->out_path = FIMC_DMA;
+ ctx->state = FIMC_CTX_CAP;
+
+ f.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
+ ctx->d_frame.fmt = find_format(&f, FMT_FLAGS_M2M);
+
+ if (!v4l2_dev->name[0])
+ snprintf(v4l2_dev->name, sizeof(v4l2_dev->name),
+ "%s.capture", dev_name(&fimc->pdev->dev));
+
+ ret = v4l2_device_register(NULL, v4l2_dev);
+ if (ret)
+ goto err_info;
+
+ vfd = video_device_alloc();
+ if (!vfd) {
+ v4l2_err(v4l2_dev, "Failed to allocate video device\n");
+ goto err_v4l2_reg;
+ }
+
+ snprintf(vfd->name, sizeof(vfd->name), "%s:cap",
+ dev_name(&fimc->pdev->dev));
+
+ vfd->fops = &fimc_capture_fops;
+ vfd->ioctl_ops = &fimc_capture_ioctl_ops;
+ vfd->minor = -1;
+ vfd->release = video_device_release;
+ video_set_drvdata(vfd, fimc);
+
+ vid_cap = &fimc->vid_cap;
+ vid_cap->vfd = vfd;
+ vid_cap->active_buf_cnt = 0;
+ vid_cap->reqbufs_count = 0;
+ vid_cap->refcnt = 0;
+ /* The default color format for image sensor. */
+ vid_cap->fmt.code = V4L2_MBUS_FMT_YUYV8_2X8;
+
+ INIT_LIST_HEAD(&vid_cap->pending_buf_q);
+ INIT_LIST_HEAD(&vid_cap->active_buf_q);
+ spin_lock_init(&ctx->slock);
+ vid_cap->ctx = ctx;
+
+ videobuf_queue_dma_contig_init(&vid_cap->vbq, &fimc_qops,
+ vid_cap->v4l2_dev.dev, &fimc->irqlock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
+ sizeof(struct fimc_vid_buffer), (void *)ctx);
+
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
+ if (ret) {
+ v4l2_err(v4l2_dev, "Failed to register video device\n");
+ goto err_vd_reg;
+ }
+
+ v4l2_info(v4l2_dev,
+ "FIMC capture driver registered as /dev/video%d\n",
+ vfd->num);
+
+ return 0;
+
+err_vd_reg:
+ video_device_release(vfd);
+err_v4l2_reg:
+ v4l2_device_unregister(v4l2_dev);
+err_info:
+ dev_err(&fimc->pdev->dev, "failed to install\n");
+ return ret;
+}
+
+void fimc_unregister_capture_device(struct fimc_dev *fimc)
+{
+ struct fimc_vid_cap *capture = &fimc->vid_cap;
+
+ if (capture->vfd)
+ video_unregister_device(capture->vfd);
+
+ kfree(capture->ctx);
+}
diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c
index 23cc054..c05777f 100644
--- a/drivers/media/video/s5p-fimc/fimc-core.c
+++ b/drivers/media/video/s5p-fimc/fimc-core.c
@@ -1,7 +1,7 @@
/*
* S5P camera interface (video postprocessor) driver
*
- * Copyright (c) 2010 Samsung Electronics
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd
*
* Sylwester Nawrocki, <s.nawrocki@samsung.com>
*
@@ -38,85 +38,102 @@ static struct fimc_fmt fimc_formats[] = {
.depth = 16,
.color = S5P_FIMC_RGB565,
.buff_cnt = 1,
- .planes_cnt = 1
+ .planes_cnt = 1,
+ .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_BE,
+ .flags = FMT_FLAGS_M2M,
}, {
.name = "BGR666",
.fourcc = V4L2_PIX_FMT_BGR666,
.depth = 32,
.color = S5P_FIMC_RGB666,
.buff_cnt = 1,
- .planes_cnt = 1
+ .planes_cnt = 1,
+ .flags = FMT_FLAGS_M2M,
}, {
.name = "XRGB-8-8-8-8, 24 bpp",
.fourcc = V4L2_PIX_FMT_RGB24,
.depth = 32,
.color = S5P_FIMC_RGB888,
.buff_cnt = 1,
- .planes_cnt = 1
+ .planes_cnt = 1,
+ .flags = FMT_FLAGS_M2M,
}, {
.name = "YUV 4:2:2 packed, YCbYCr",
.fourcc = V4L2_PIX_FMT_YUYV,
.depth = 16,
.color = S5P_FIMC_YCBYCR422,
.buff_cnt = 1,
- .planes_cnt = 1
- }, {
+ .planes_cnt = 1,
+ .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
+ }, {
.name = "YUV 4:2:2 packed, CbYCrY",
.fourcc = V4L2_PIX_FMT_UYVY,
.depth = 16,
.color = S5P_FIMC_CBYCRY422,
.buff_cnt = 1,
- .planes_cnt = 1
+ .planes_cnt = 1,
+ .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8,
+ .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
}, {
.name = "YUV 4:2:2 packed, CrYCbY",
.fourcc = V4L2_PIX_FMT_VYUY,
.depth = 16,
.color = S5P_FIMC_CRYCBY422,
.buff_cnt = 1,
- .planes_cnt = 1
+ .planes_cnt = 1,
+ .mbus_code = V4L2_MBUS_FMT_VYUY8_2X8,
+ .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
}, {
.name = "YUV 4:2:2 packed, YCrYCb",
.fourcc = V4L2_PIX_FMT_YVYU,
.depth = 16,
.color = S5P_FIMC_YCRYCB422,
.buff_cnt = 1,
- .planes_cnt = 1
+ .planes_cnt = 1,
+ .mbus_code = V4L2_MBUS_FMT_YVYU8_2X8,
+ .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
}, {
.name = "YUV 4:2:2 planar, Y/Cb/Cr",
.fourcc = V4L2_PIX_FMT_YUV422P,
.depth = 12,
.color = S5P_FIMC_YCBCR422,
.buff_cnt = 1,
- .planes_cnt = 3
+ .planes_cnt = 3,
+ .flags = FMT_FLAGS_M2M,
}, {
.name = "YUV 4:2:2 planar, Y/CbCr",
.fourcc = V4L2_PIX_FMT_NV16,
.depth = 16,
.color = S5P_FIMC_YCBCR422,
.buff_cnt = 1,
- .planes_cnt = 2
+ .planes_cnt = 2,
+ .flags = FMT_FLAGS_M2M,
}, {
.name = "YUV 4:2:2 planar, Y/CrCb",
.fourcc = V4L2_PIX_FMT_NV61,
.depth = 16,
.color = S5P_FIMC_RGB565,
.buff_cnt = 1,
- .planes_cnt = 2
+ .planes_cnt = 2,
+ .flags = FMT_FLAGS_M2M,
}, {
.name = "YUV 4:2:0 planar, YCbCr",
.fourcc = V4L2_PIX_FMT_YUV420,
.depth = 12,
.color = S5P_FIMC_YCBCR420,
.buff_cnt = 1,
- .planes_cnt = 3
+ .planes_cnt = 3,
+ .flags = FMT_FLAGS_M2M,
}, {
.name = "YUV 4:2:0 planar, Y/CbCr",
.fourcc = V4L2_PIX_FMT_NV12,
.depth = 12,
.color = S5P_FIMC_YCBCR420,
.buff_cnt = 1,
- .planes_cnt = 2
- }
+ .planes_cnt = 2,
+ .flags = FMT_FLAGS_M2M,
+ },
};
static struct v4l2_queryctrl fimc_ctrls[] = {
@@ -156,7 +173,7 @@ static struct v4l2_queryctrl *get_ctrl(int id)
return NULL;
}
-static int fimc_check_scaler_ratio(struct v4l2_rect *r, struct fimc_frame *f)
+int fimc_check_scaler_ratio(struct v4l2_rect *r, struct fimc_frame *f)
{
if (r->width > f->width) {
if (f->width > (r->width * SCALER_MAX_HRATIO))
@@ -199,7 +216,7 @@ static int fimc_get_scaler_factor(u32 src, u32 tar, u32 *ratio, u32 *shift)
return 0;
}
-static int fimc_set_scaler_info(struct fimc_ctx *ctx)
+int fimc_set_scaler_info(struct fimc_ctx *ctx)
{
struct fimc_scaler *sc = &ctx->scaler;
struct fimc_frame *s_frame = &ctx->s_frame;
@@ -259,6 +276,51 @@ static int fimc_set_scaler_info(struct fimc_ctx *ctx)
return 0;
}
+static void fimc_capture_handler(struct fimc_dev *fimc)
+{
+ struct fimc_vid_cap *cap = &fimc->vid_cap;
+ struct fimc_vid_buffer *v_buf = NULL;
+
+ if (!list_empty(&cap->active_buf_q)) {
+ v_buf = active_queue_pop(cap);
+ fimc_buf_finish(fimc, v_buf);
+ }
+
+ if (test_and_clear_bit(ST_CAPT_SHUT, &fimc->state)) {
+ wake_up(&fimc->irq_queue);
+ return;
+ }
+
+ if (!list_empty(&cap->pending_buf_q)) {
+
+ v_buf = pending_queue_pop(cap);
+ fimc_hw_set_output_addr(fimc, &v_buf->paddr, cap->buf_index);
+ v_buf->index = cap->buf_index;
+
+ dbg("hw ptr: %d, sw ptr: %d",
+ fimc_hw_get_frame_index(fimc), cap->buf_index);
+
+ spin_lock(&fimc->irqlock);
+ v_buf->vb.state = VIDEOBUF_ACTIVE;
+ spin_unlock(&fimc->irqlock);
+
+ /* Move the buffer to the capture active queue */
+ active_queue_add(cap, v_buf);
+
+ dbg("next frame: %d, done frame: %d",
+ fimc_hw_get_frame_index(fimc), v_buf->index);
+
+ if (++cap->buf_index >= FIMC_MAX_OUT_BUFS)
+ cap->buf_index = 0;
+
+ } else if (test_and_clear_bit(ST_CAPT_STREAM, &fimc->state) &&
+ cap->active_buf_cnt <= 1) {
+ fimc_deactivate_capture(fimc);
+ }
+
+ dbg("frame: %d, active_buf_cnt= %d",
+ fimc_hw_get_frame_index(fimc), cap->active_buf_cnt);
+}
static irqreturn_t fimc_isr(int irq, void *priv)
{
@@ -285,6 +347,16 @@ static irqreturn_t fimc_isr(int irq, void *priv)
spin_unlock(&fimc->irqlock);
v4l2_m2m_job_finish(fimc->m2m.m2m_dev, ctx->m2m_ctx);
}
+ goto isr_unlock;
+
+ }
+
+ if (test_bit(ST_CAPT_RUN, &fimc->state))
+ fimc_capture_handler(fimc);
+
+ if (test_and_clear_bit(ST_CAPT_PEND, &fimc->state)) {
+ set_bit(ST_CAPT_RUN, &fimc->state);
+ wake_up(&fimc->irq_queue);
}
isr_unlock:
@@ -424,7 +496,7 @@ static void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f)
*
* Return: 0 if dimensions are valid or non zero otherwise.
*/
-static int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags)
+int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags)
{
struct fimc_frame *s_frame, *d_frame;
struct fimc_vid_buffer *buf = NULL;
@@ -513,9 +585,9 @@ static void fimc_dma_run(void *priv)
if (ctx->state & FIMC_PARAMS)
fimc_hw_set_out_dma(ctx);
- ctx->state = 0;
fimc_activate_capture(ctx);
+ ctx->state &= (FIMC_CTX_M2M | FIMC_CTX_CAP);
fimc_hw_activate_input_dma(fimc, true);
dma_unlock:
@@ -598,16 +670,59 @@ static void fimc_buf_queue(struct videobuf_queue *vq,
struct videobuf_buffer *vb)
{
struct fimc_ctx *ctx = vq->priv_data;
- v4l2_m2m_buf_queue(ctx->m2m_ctx, vq, vb);
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct fimc_vid_cap *cap = &fimc->vid_cap;
+ unsigned long flags;
+
+ dbg("ctx: %p, ctx->state: 0x%x", ctx, ctx->state);
+
+ if ((ctx->state & FIMC_CTX_M2M) && ctx->m2m_ctx) {
+ v4l2_m2m_buf_queue(ctx->m2m_ctx, vq, vb);
+ } else if (ctx->state & FIMC_CTX_CAP) {
+ spin_lock_irqsave(&fimc->slock, flags);
+ fimc_vid_cap_buf_queue(fimc, (struct fimc_vid_buffer *)vb);
+
+ dbg("fimc->cap.active_buf_cnt: %d",
+ fimc->vid_cap.active_buf_cnt);
+
+ if (cap->active_buf_cnt >= cap->reqbufs_count ||
+ cap->active_buf_cnt >= FIMC_MAX_OUT_BUFS) {
+ if (!test_and_set_bit(ST_CAPT_STREAM, &fimc->state))
+ fimc_activate_capture(ctx);
+ }
+ spin_unlock_irqrestore(&fimc->slock, flags);
+ }
}
-static struct videobuf_queue_ops fimc_qops = {
+struct videobuf_queue_ops fimc_qops = {
.buf_setup = fimc_buf_setup,
.buf_prepare = fimc_buf_prepare,
.buf_queue = fimc_buf_queue,
.buf_release = fimc_buf_release,
};
+/**
+ * check_stream_type - check if stream type is valid
+ * @ctx: hardware operation context, per device for capture
+ * @type: v4l stream type
+ *
+ * Return: non zero for V4L output stream, 0 - for capture stream,
+ * -EINVAL if stream is invalid for given context
+ */
+static int check_stream_type(struct fimc_ctx *ctx, int type)
+{
+ int is_output = (type == V4L2_BUF_TYPE_VIDEO_OUTPUT);
+
+ if (ctx->state & FIMC_CTX_CAP) {
+ if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ } else {
+ if (!is_output && type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ }
+ return is_output;
+}
+
static int fimc_m2m_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
@@ -624,7 +739,7 @@ static int fimc_m2m_querycap(struct file *file, void *priv,
return 0;
}
-static int fimc_m2m_enum_fmt(struct file *file, void *priv,
+int fimc_vidioc_enum_fmt(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
struct fimc_fmt *fmt;
@@ -635,109 +750,135 @@ static int fimc_m2m_enum_fmt(struct file *file, void *priv,
fmt = &fimc_formats[f->index];
strncpy(f->description, fmt->name, sizeof(f->description) - 1);
f->pixelformat = fmt->fourcc;
+
return 0;
}
-static int fimc_m2m_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
+int fimc_vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
{
struct fimc_ctx *ctx = priv;
+ struct fimc_dev *fimc = ctx->fimc_dev;
struct fimc_frame *frame;
frame = ctx_get_frame(ctx, f->type);
if (IS_ERR(frame))
return PTR_ERR(frame);
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
f->fmt.pix.width = frame->width;
f->fmt.pix.height = frame->height;
f->fmt.pix.field = V4L2_FIELD_NONE;
f->fmt.pix.pixelformat = frame->fmt->fourcc;
+ mutex_unlock(&fimc->lock);
return 0;
}
-static struct fimc_fmt *find_format(struct v4l2_format *f)
+struct fimc_fmt *find_format(struct v4l2_format *f, unsigned int mask)
{
struct fimc_fmt *fmt;
unsigned int i;
for (i = 0; i < ARRAY_SIZE(fimc_formats); ++i) {
fmt = &fimc_formats[i];
- if (fmt->fourcc == f->fmt.pix.pixelformat)
+ if (fmt->fourcc == f->fmt.pix.pixelformat &&
+ (fmt->flags & mask))
break;
}
- if (i == ARRAY_SIZE(fimc_formats))
- return NULL;
- return fmt;
+ return (i == ARRAY_SIZE(fimc_formats)) ? NULL : fmt;
}
-static int fimc_m2m_try_fmt(struct file *file, void *priv,
- struct v4l2_format *f)
+struct fimc_fmt *find_mbus_format(struct v4l2_mbus_framefmt *f,
+ unsigned int mask)
{
struct fimc_fmt *fmt;
- u32 max_width, max_height, mod_x, mod_y;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(fimc_formats); ++i) {
+ fmt = &fimc_formats[i];
+ if (fmt->mbus_code == f->code && (fmt->flags & mask))
+ break;
+ }
+
+ return (i == ARRAY_SIZE(fimc_formats)) ? NULL : fmt;
+}
+
+
+int fimc_vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
struct fimc_ctx *ctx = priv;
struct fimc_dev *fimc = ctx->fimc_dev;
- struct v4l2_pix_format *pix = &f->fmt.pix;
struct samsung_fimc_variant *variant = fimc->variant;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ struct fimc_fmt *fmt;
+ u32 max_width, mod_x, mod_y, mask;
+ int ret = -EINVAL;
+
+ bool is_output = check_stream_type(ctx, f->type);
+ if (is_output < 0)
+ return ret;
- fmt = find_format(f);
+ dbg("w: %d, h: %d, bpl: %d",
+ pix->width, pix->height, pix->bytesperline);
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ mask = is_output ? FMT_FLAGS_M2M : FMT_FLAGS_M2M | FMT_FLAGS_CAM;
+ fmt = find_format(f, mask);
if (!fmt) {
- v4l2_err(&fimc->m2m.v4l2_dev,
- "Fourcc format (0x%X) invalid.\n", pix->pixelformat);
- return -EINVAL;
+ v4l2_err(&fimc->m2m.v4l2_dev, "Fourcc format (0x%X) invalid.\n",
+ pix->pixelformat);
+ goto tf_out;
}
if (pix->field == V4L2_FIELD_ANY)
pix->field = V4L2_FIELD_NONE;
else if (V4L2_FIELD_NONE != pix->field)
- return -EINVAL;
+ goto tf_out;
- if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+ if (is_output) {
max_width = variant->scaler_dis_w;
- max_height = variant->scaler_dis_w;
- mod_x = variant->min_inp_pixsize;
- mod_y = variant->min_inp_pixsize;
- } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- max_width = variant->out_rot_dis_w;
- max_height = variant->out_rot_dis_w;
- mod_x = variant->min_out_pixsize;
- mod_y = variant->min_out_pixsize;
+ mod_x = ffs(variant->min_inp_pixsize) - 1;
} else {
- err("Wrong stream type (%d)", f->type);
- return -EINVAL;
+ max_width = variant->out_rot_dis_w;
+ mod_x = ffs(variant->min_out_pixsize) - 1;
}
- dbg("max_w= %d, max_h= %d", max_width, max_height);
-
- if (pix->height > max_height)
- pix->height = max_height;
- if (pix->width > max_width)
- pix->width = max_width;
-
if (tiled_fmt(fmt)) {
- mod_x = 64; /* 64x32 tile */
- mod_y = 32;
+ mod_x = 6; /* 64 x 32 pixels tile */
+ mod_y = 5;
+ } else {
+ if (fimc->id == 1 && fimc->variant->pix_hoff)
+ mod_y = fimc_fmt_is_rgb(fmt->color) ? 0 : 1;
+ else
+ mod_y = mod_x;
}
- dbg("mod_x= 0x%X, mod_y= 0x%X", mod_x, mod_y);
+ dbg("mod_x: %d, mod_y: %d, max_w: %d", mod_x, mod_y, max_width);
- pix->width = (pix->width == 0) ? mod_x : ALIGN(pix->width, mod_x);
- pix->height = (pix->height == 0) ? mod_y : ALIGN(pix->height, mod_y);
+ v4l_bound_align_image(&pix->width, 16, max_width, mod_x,
+ &pix->height, 8, variant->scaler_dis_w, mod_y, 0);
if (pix->bytesperline == 0 ||
- pix->bytesperline * 8 / fmt->depth > pix->width)
+ (pix->bytesperline * 8 / fmt->depth) > pix->width)
pix->bytesperline = (pix->width * fmt->depth) >> 3;
if (pix->sizeimage == 0)
pix->sizeimage = pix->height * pix->bytesperline;
- dbg("pix->bytesperline= %d, fmt->depth= %d",
- pix->bytesperline, fmt->depth);
+ dbg("w: %d, h: %d, bpl: %d, depth: %d",
+ pix->width, pix->height, pix->bytesperline, fmt->depth);
- return 0;
-}
+ ret = 0;
+tf_out:
+ mutex_unlock(&fimc->lock);
+ return ret;
+}
static int fimc_m2m_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
{
@@ -750,9 +891,7 @@ static int fimc_m2m_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
unsigned long flags;
int ret = 0;
- BUG_ON(!ctx);
-
- ret = fimc_m2m_try_fmt(file, priv, f);
+ ret = fimc_vidioc_try_fmt(file, priv, f);
if (ret)
return ret;
@@ -785,7 +924,7 @@ static int fimc_m2m_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
spin_unlock_irqrestore(&ctx->slock, flags);
pix = &f->fmt.pix;
- frame->fmt = find_format(f);
+ frame->fmt = find_format(f, FMT_FLAGS_M2M);
if (!frame->fmt) {
ret = -EINVAL;
goto sf_out;
@@ -857,21 +996,33 @@ static int fimc_m2m_streamoff(struct file *file, void *priv,
return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
}
-int fimc_m2m_queryctrl(struct file *file, void *priv,
+int fimc_vidioc_queryctrl(struct file *file, void *priv,
struct v4l2_queryctrl *qc)
{
+ struct fimc_ctx *ctx = priv;
struct v4l2_queryctrl *c;
+
c = get_ctrl(qc->id);
- if (!c)
- return -EINVAL;
- *qc = *c;
- return 0;
+ if (c) {
+ *qc = *c;
+ return 0;
+ }
+
+ if (ctx->state & FIMC_CTX_CAP)
+ return v4l2_subdev_call(ctx->fimc_dev->vid_cap.sd,
+ core, queryctrl, qc);
+ return -EINVAL;
}
-int fimc_m2m_g_ctrl(struct file *file, void *priv,
+int fimc_vidioc_g_ctrl(struct file *file, void *priv,
struct v4l2_control *ctrl)
{
struct fimc_ctx *ctx = priv;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ int ret = 0;
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
switch (ctrl->id) {
case V4L2_CID_HFLIP:
@@ -884,15 +1035,22 @@ int fimc_m2m_g_ctrl(struct file *file, void *priv,
ctrl->value = ctx->rotation;
break;
default:
- v4l2_err(&ctx->fimc_dev->m2m.v4l2_dev, "Invalid control\n");
- return -EINVAL;
+ if (ctx->state & FIMC_CTX_CAP) {
+ ret = v4l2_subdev_call(fimc->vid_cap.sd, core,
+ g_ctrl, ctrl);
+ } else {
+ v4l2_err(&fimc->m2m.v4l2_dev,
+ "Invalid control\n");
+ ret = -EINVAL;
+ }
}
dbg("ctrl->value= %d", ctrl->value);
- return 0;
+
+ mutex_unlock(&fimc->lock);
+ return ret;
}
-static int check_ctrl_val(struct fimc_ctx *ctx,
- struct v4l2_control *ctrl)
+int check_ctrl_val(struct fimc_ctx *ctx, struct v4l2_control *ctrl)
{
struct v4l2_queryctrl *c;
c = get_ctrl(ctrl->id);
@@ -909,22 +1067,23 @@ static int check_ctrl_val(struct fimc_ctx *ctx,
return 0;
}
-int fimc_m2m_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
+int fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_control *ctrl)
{
- struct fimc_ctx *ctx = priv;
struct samsung_fimc_variant *variant = ctx->fimc_dev->variant;
+ struct fimc_dev *fimc = ctx->fimc_dev;
unsigned long flags;
- int ret = 0;
- ret = check_ctrl_val(ctx, ctrl);
- if (ret)
- return ret;
+ if (ctx->rotation != 0 &&
+ (ctrl->id == V4L2_CID_HFLIP || ctrl->id == V4L2_CID_VFLIP)) {
+ v4l2_err(&fimc->m2m.v4l2_dev,
+ "Simultaneous flip and rotation is not supported\n");
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&ctx->slock, flags);
switch (ctrl->id) {
case V4L2_CID_HFLIP:
- if (ctx->rotation != 0)
- return 0;
if (ctrl->value)
ctx->flip |= FLIP_X_AXIS;
else
@@ -932,8 +1091,6 @@ int fimc_m2m_s_ctrl(struct file *file, void *priv,
break;
case V4L2_CID_VFLIP:
- if (ctx->rotation != 0)
- return 0;
if (ctrl->value)
ctx->flip |= FLIP_Y_AXIS;
else
@@ -941,77 +1098,99 @@ int fimc_m2m_s_ctrl(struct file *file, void *priv,
break;
case V4L2_CID_ROTATE:
- if (ctrl->value == 90 || ctrl->value == 270) {
- if (ctx->out_path == FIMC_LCDFIFO &&
- !variant->has_inp_rot) {
- return -EINVAL;
- } else if (ctx->in_path == FIMC_DMA &&
- !variant->has_out_rot) {
- return -EINVAL;
- }
+ /* Check for the output rotator availability */
+ if ((ctrl->value == 90 || ctrl->value == 270) &&
+ (ctx->in_path == FIMC_DMA && !variant->has_out_rot)) {
+ spin_unlock_irqrestore(&ctx->slock, flags);
+ return -EINVAL;
+ } else {
+ ctx->rotation = ctrl->value;
}
- ctx->rotation = ctrl->value;
- if (ctrl->value == 180)
- ctx->flip = FLIP_XY_AXIS;
break;
default:
- v4l2_err(&ctx->fimc_dev->m2m.v4l2_dev, "Invalid control\n");
+ spin_unlock_irqrestore(&ctx->slock, flags);
+ if (ctx->state & FIMC_CTX_CAP)
+ return v4l2_subdev_call(fimc->vid_cap.sd, core,
+ s_ctrl, ctrl);
+
+ v4l2_err(&fimc->m2m.v4l2_dev, "Invalid control\n");
return -EINVAL;
}
- spin_lock_irqsave(&ctx->slock, flags);
ctx->state |= FIMC_PARAMS;
spin_unlock_irqrestore(&ctx->slock, flags);
+
return 0;
}
+static int fimc_m2m_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct fimc_ctx *ctx = priv;
+ int ret = 0;
+
+ ret = check_ctrl_val(ctx, ctrl);
+ if (ret)
+ return ret;
-static int fimc_m2m_cropcap(struct file *file, void *fh,
- struct v4l2_cropcap *cr)
+ ret = fimc_s_ctrl(ctx, ctrl);
+ return 0;
+}
+
+int fimc_vidioc_cropcap(struct file *file, void *fh,
+ struct v4l2_cropcap *cr)
{
struct fimc_frame *frame;
struct fimc_ctx *ctx = fh;
+ struct fimc_dev *fimc = ctx->fimc_dev;
frame = ctx_get_frame(ctx, cr->type);
if (IS_ERR(frame))
return PTR_ERR(frame);
- cr->bounds.left = 0;
- cr->bounds.top = 0;
- cr->bounds.width = frame->f_width;
- cr->bounds.height = frame->f_height;
- cr->defrect.left = frame->offs_h;
- cr->defrect.top = frame->offs_v;
- cr->defrect.width = frame->o_width;
- cr->defrect.height = frame->o_height;
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ cr->bounds.left = 0;
+ cr->bounds.top = 0;
+ cr->bounds.width = frame->f_width;
+ cr->bounds.height = frame->f_height;
+ cr->defrect = cr->bounds;
+
+ mutex_unlock(&fimc->lock);
return 0;
}
-static int fimc_m2m_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
+int fimc_vidioc_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
{
struct fimc_frame *frame;
struct fimc_ctx *ctx = file->private_data;
+ struct fimc_dev *fimc = ctx->fimc_dev;
frame = ctx_get_frame(ctx, cr->type);
if (IS_ERR(frame))
return PTR_ERR(frame);
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
cr->c.left = frame->offs_h;
cr->c.top = frame->offs_v;
cr->c.width = frame->width;
cr->c.height = frame->height;
+ mutex_unlock(&fimc->lock);
return 0;
}
-static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr)
+int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr)
{
- struct fimc_ctx *ctx = file->private_data;
struct fimc_dev *fimc = ctx->fimc_dev;
- unsigned long flags;
struct fimc_frame *f;
- u32 min_size;
- int ret = 0;
+ u32 min_size, halign;
+
+ f = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ?
+ &ctx->s_frame : &ctx->d_frame;
if (cr->c.top < 0 || cr->c.left < 0) {
v4l2_err(&fimc->m2m.v4l2_dev,
@@ -1019,66 +1198,98 @@ static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr)
return -EINVAL;
}
- if (cr->c.width <= 0 || cr->c.height <= 0) {
- v4l2_err(&fimc->m2m.v4l2_dev,
- "crop width and height must be greater than 0\n");
- return -EINVAL;
- }
-
f = ctx_get_frame(ctx, cr->type);
if (IS_ERR(f))
return PTR_ERR(f);
- /* Adjust to required pixel boundary. */
- min_size = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ?
- fimc->variant->min_inp_pixsize : fimc->variant->min_out_pixsize;
+ min_size = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ ? fimc->variant->min_inp_pixsize
+ : fimc->variant->min_out_pixsize;
- cr->c.width = round_down(cr->c.width, min_size);
- cr->c.height = round_down(cr->c.height, min_size);
- cr->c.left = round_down(cr->c.left + 1, min_size);
- cr->c.top = round_down(cr->c.top + 1, min_size);
-
- if ((cr->c.left + cr->c.width > f->o_width)
- || (cr->c.top + cr->c.height > f->o_height)) {
- v4l2_err(&fimc->m2m.v4l2_dev, "Error in S_CROP params\n");
- return -EINVAL;
+ if (ctx->state & FIMC_CTX_M2M) {
+ if (fimc->id == 1 && fimc->variant->pix_hoff)
+ halign = fimc_fmt_is_rgb(f->fmt->color) ? 0 : 1;
+ else
+ halign = ffs(min_size) - 1;
+ /* there are more strict aligment requirements at camera interface */
+ } else {
+ min_size = 16;
+ halign = 4;
}
+ v4l_bound_align_image(&cr->c.width, min_size, f->o_width,
+ ffs(min_size) - 1,
+ &cr->c.height, min_size, f->o_height,
+ halign, 64/(ALIGN(f->fmt->depth, 8)));
+
+ /* adjust left/top if cropping rectangle is out of bounds */
+ if (cr->c.left + cr->c.width > f->o_width)
+ cr->c.left = f->o_width - cr->c.width;
+ if (cr->c.top + cr->c.height > f->o_height)
+ cr->c.top = f->o_height - cr->c.height;
+
+ cr->c.left = round_down(cr->c.left, min_size);
+ cr->c.top = round_down(cr->c.top,
+ ctx->state & FIMC_CTX_M2M ? 8 : 16);
+
+ dbg("l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d",
+ cr->c.left, cr->c.top, cr->c.width, cr->c.height,
+ f->f_width, f->f_height);
+
+ return 0;
+}
+
+
+static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr)
+{
+ struct fimc_ctx *ctx = file->private_data;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ unsigned long flags;
+ struct fimc_frame *f;
+ int ret;
+
+ ret = fimc_try_crop(ctx, cr);
+ if (ret)
+ return ret;
+
+ f = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ?
+ &ctx->s_frame : &ctx->d_frame;
+
spin_lock_irqsave(&ctx->slock, flags);
- if ((ctx->state & FIMC_SRC_FMT) && (ctx->state & FIMC_DST_FMT)) {
- /* Check for the pixel scaling ratio when cropping input img. */
+ if (~ctx->state & (FIMC_SRC_FMT | FIMC_DST_FMT)) {
+ /* Check to see if scaling ratio is within supported range */
if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
ret = fimc_check_scaler_ratio(&cr->c, &ctx->d_frame);
- else if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ else
ret = fimc_check_scaler_ratio(&cr->c, &ctx->s_frame);
-
if (ret) {
spin_unlock_irqrestore(&ctx->slock, flags);
- v4l2_err(&fimc->m2m.v4l2_dev, "Out of scaler range");
+ v4l2_err(&fimc->m2m.v4l2_dev, "Out of scaler range");
return -EINVAL;
}
}
ctx->state |= FIMC_PARAMS;
- spin_unlock_irqrestore(&ctx->slock, flags);
f->offs_h = cr->c.left;
f->offs_v = cr->c.top;
- f->width = cr->c.width;
+ f->width = cr->c.width;
f->height = cr->c.height;
+
+ spin_unlock_irqrestore(&ctx->slock, flags);
return 0;
}
static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = {
.vidioc_querycap = fimc_m2m_querycap,
- .vidioc_enum_fmt_vid_cap = fimc_m2m_enum_fmt,
- .vidioc_enum_fmt_vid_out = fimc_m2m_enum_fmt,
+ .vidioc_enum_fmt_vid_cap = fimc_vidioc_enum_fmt,
+ .vidioc_enum_fmt_vid_out = fimc_vidioc_enum_fmt,
- .vidioc_g_fmt_vid_cap = fimc_m2m_g_fmt,
- .vidioc_g_fmt_vid_out = fimc_m2m_g_fmt,
+ .vidioc_g_fmt_vid_cap = fimc_vidioc_g_fmt,
+ .vidioc_g_fmt_vid_out = fimc_vidioc_g_fmt,
- .vidioc_try_fmt_vid_cap = fimc_m2m_try_fmt,
- .vidioc_try_fmt_vid_out = fimc_m2m_try_fmt,
+ .vidioc_try_fmt_vid_cap = fimc_vidioc_try_fmt,
+ .vidioc_try_fmt_vid_out = fimc_vidioc_try_fmt,
.vidioc_s_fmt_vid_cap = fimc_m2m_s_fmt,
.vidioc_s_fmt_vid_out = fimc_m2m_s_fmt,
@@ -1092,13 +1303,13 @@ static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = {
.vidioc_streamon = fimc_m2m_streamon,
.vidioc_streamoff = fimc_m2m_streamoff,
- .vidioc_queryctrl = fimc_m2m_queryctrl,
- .vidioc_g_ctrl = fimc_m2m_g_ctrl,
+ .vidioc_queryctrl = fimc_vidioc_queryctrl,
+ .vidioc_g_ctrl = fimc_vidioc_g_ctrl,
.vidioc_s_ctrl = fimc_m2m_s_ctrl,
- .vidioc_g_crop = fimc_m2m_g_crop,
+ .vidioc_g_crop = fimc_vidioc_g_crop,
.vidioc_s_crop = fimc_m2m_s_crop,
- .vidioc_cropcap = fimc_m2m_cropcap
+ .vidioc_cropcap = fimc_vidioc_cropcap
};
@@ -1120,11 +1331,23 @@ static int fimc_m2m_open(struct file *file)
struct fimc_ctx *ctx = NULL;
int err = 0;
- mutex_lock(&fimc->lock);
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ dbg("pid: %d, state: 0x%lx, refcnt: %d",
+ task_pid_nr(current), fimc->state, fimc->vid_cap.refcnt);
+
+ /*
+ * Return if the corresponding video capture node
+ * is already opened.
+ */
+ if (fimc->vid_cap.refcnt > 0) {
+ mutex_unlock(&fimc->lock);
+ return -EBUSY;
+ }
+
fimc->m2m.refcnt++;
set_bit(ST_OUTDMA_RUN, &fimc->state);
- mutex_unlock(&fimc->lock);
-
ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
if (!ctx)
@@ -1135,8 +1358,8 @@ static int fimc_m2m_open(struct file *file)
/* Default color format */
ctx->s_frame.fmt = &fimc_formats[0];
ctx->d_frame.fmt = &fimc_formats[0];
- /* per user process device context initialization */
- ctx->state = 0;
+ /* Setup the device context for mem2mem mode. */
+ ctx->state = FIMC_CTX_M2M;
ctx->flags = 0;
ctx->in_path = FIMC_DMA;
ctx->out_path = FIMC_DMA;
@@ -1147,6 +1370,8 @@ static int fimc_m2m_open(struct file *file)
err = PTR_ERR(ctx->m2m_ctx);
kfree(ctx);
}
+
+ mutex_unlock(&fimc->lock);
return err;
}
@@ -1155,11 +1380,16 @@ static int fimc_m2m_release(struct file *file)
struct fimc_ctx *ctx = file->private_data;
struct fimc_dev *fimc = ctx->fimc_dev;
+ mutex_lock(&fimc->lock);
+
+ dbg("pid: %d, state: 0x%lx, refcnt= %d",
+ task_pid_nr(current), fimc->state, fimc->m2m.refcnt);
+
v4l2_m2m_ctx_release(ctx->m2m_ctx);
kfree(ctx);
- mutex_lock(&fimc->lock);
if (--fimc->m2m.refcnt <= 0)
clear_bit(ST_OUTDMA_RUN, &fimc->state);
+
mutex_unlock(&fimc->lock);
return 0;
}
@@ -1168,6 +1398,7 @@ static unsigned int fimc_m2m_poll(struct file *file,
struct poll_table_struct *wait)
{
struct fimc_ctx *ctx = file->private_data;
+
return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
}
@@ -1175,6 +1406,7 @@ static unsigned int fimc_m2m_poll(struct file *file,
static int fimc_m2m_mmap(struct file *file, struct vm_area_struct *vma)
{
struct fimc_ctx *ctx = file->private_data;
+
return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
}
@@ -1322,9 +1554,11 @@ static int fimc_probe(struct platform_device *pdev)
fimc->id = pdev->id;
fimc->variant = drv_data->variant[fimc->id];
fimc->pdev = pdev;
+ fimc->pdata = pdev->dev.platform_data;
fimc->state = ST_IDLE;
spin_lock_init(&fimc->irqlock);
+ init_waitqueue_head(&fimc->irq_queue);
spin_lock_init(&fimc->slock);
mutex_init(&fimc->lock);
@@ -1354,6 +1588,7 @@ static int fimc_probe(struct platform_device *pdev)
ret = fimc_clk_get(fimc);
if (ret)
goto err_regs_unmap;
+ clk_set_rate(fimc->clock[0], drv_data->lclk_frequency);
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
@@ -1375,11 +1610,27 @@ static int fimc_probe(struct platform_device *pdev)
if (ret)
goto err_irq;
+ /* At least one camera sensor is required to register capture node */
+ if (fimc->pdata) {
+ int i;
+ for (i = 0; i < FIMC_MAX_CAMIF_CLIENTS; ++i)
+ if (fimc->pdata->isp_info[i])
+ break;
+
+ if (i < FIMC_MAX_CAMIF_CLIENTS) {
+ ret = fimc_register_capture_device(fimc);
+ if (ret)
+ goto err_m2m;
+ }
+ }
+
dev_dbg(&pdev->dev, "%s(): fimc-%d registered successfully\n",
__func__, fimc->id);
return 0;
+err_m2m:
+ fimc_unregister_m2m_device(fimc);
err_irq:
free_irq(fimc->irq, fimc);
err_clk:
@@ -1404,6 +1655,8 @@ static int __devexit fimc_remove(struct platform_device *pdev)
fimc_hw_reset(fimc);
fimc_unregister_m2m_device(fimc);
+ fimc_unregister_capture_device(fimc);
+
fimc_clk_release(fimc);
iounmap(fimc->regs);
release_resource(fimc->regs_res);
@@ -1474,7 +1727,8 @@ static struct samsung_fimc_driverdata fimc_drvdata_s5p = {
[1] = &fimc01_variant_s5p,
[2] = &fimc2_variant_s5p,
},
- .devs_cnt = 3
+ .devs_cnt = 3,
+ .lclk_frequency = 133000000UL,
};
static struct samsung_fimc_driverdata fimc_drvdata_s5pv210 = {
@@ -1483,7 +1737,8 @@ static struct samsung_fimc_driverdata fimc_drvdata_s5pv210 = {
[1] = &fimc01_variant_s5pv210,
[2] = &fimc2_variant_s5pv210,
},
- .devs_cnt = 3
+ .devs_cnt = 3,
+ .lclk_frequency = 166000000UL,
};
static struct platform_device_id fimc_driver_ids[] = {
@@ -1524,6 +1779,6 @@ static void __exit fimc_exit(void)
module_init(fimc_init);
module_exit(fimc_exit);
-MODULE_AUTHOR("Sylwester Nawrocki, s.nawrocki@samsung.com");
-MODULE_DESCRIPTION("S3C/S5P FIMC (video postprocessor) driver");
+MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
+MODULE_DESCRIPTION("S5P FIMC camera host interface/video postprocessor driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h
index 5aeb3ef..ce0a6b8 100644
--- a/drivers/media/video/s5p-fimc/fimc-core.h
+++ b/drivers/media/video/s5p-fimc/fimc-core.h
@@ -11,10 +11,14 @@
#ifndef FIMC_CORE_H_
#define FIMC_CORE_H_
+/*#define DEBUG*/
+
#include <linux/types.h>
#include <media/videobuf-core.h>
#include <media/v4l2-device.h>
#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-mediabus.h>
+#include <media/s3c_fimc.h>
#include <linux/videodev2.h>
#include "regs-fimc.h"
@@ -28,6 +32,8 @@
#define dbg(fmt, args...)
#endif
+/* Time to wait for next frame VSYNC interrupt while stopping operation. */
+#define FIMC_SHUTDOWN_TIMEOUT ((100*HZ)/1000)
#define NUM_FIMC_CLOCKS 2
#define MODULE_NAME "s5p-fimc"
#define FIMC_MAX_DEVS 3
@@ -36,19 +42,41 @@
#define SCALER_MAX_VRATIO 64
#define DMA_MIN_SIZE 8
-enum {
+/* FIMC device state flags */
+enum fimc_dev_flags {
+ /* for m2m node */
ST_IDLE,
ST_OUTDMA_RUN,
ST_M2M_PEND,
+ /* for capture node */
+ ST_CAPT_PEND,
+ ST_CAPT_RUN,
+ ST_CAPT_STREAM,
+ ST_CAPT_SHUT,
};
#define fimc_m2m_active(dev) test_bit(ST_OUTDMA_RUN, &(dev)->state)
#define fimc_m2m_pending(dev) test_bit(ST_M2M_PEND, &(dev)->state)
+#define fimc_capture_running(dev) test_bit(ST_CAPT_RUN, &(dev)->state)
+#define fimc_capture_pending(dev) test_bit(ST_CAPT_PEND, &(dev)->state)
+
+#define fimc_capture_active(dev) \
+ (test_bit(ST_CAPT_RUN, &(dev)->state) || \
+ test_bit(ST_CAPT_PEND, &(dev)->state))
+
+#define fimc_capture_streaming(dev) \
+ test_bit(ST_CAPT_STREAM, &(dev)->state)
+
+#define fimc_buf_finish(dev, vid_buf) do { \
+ spin_lock(&(dev)->irqlock); \
+ (vid_buf)->vb.state = VIDEOBUF_DONE; \
+ spin_unlock(&(dev)->irqlock); \
+ wake_up(&(vid_buf)->vb.done); \
+} while (0)
+
enum fimc_datapath {
- FIMC_ITU_CAM_A,
- FIMC_ITU_CAM_B,
- FIMC_MIPI_CAM,
+ FIMC_CAMERA,
FIMC_DMA,
FIMC_LCDFIFO,
FIMC_WRITEBACK
@@ -123,20 +151,25 @@ enum fimc_color_fmt {
/**
* struct fimc_fmt - the driver's internal color format data
+ * @mbus_code: Media Bus pixel code, -1 if not applicable
* @name: format description
- * @fourcc: the fourcc code for this format
+ * @fourcc: the fourcc code for this format, 0 if not applicable
* @color: the corresponding fimc_color_fmt
- * @depth: number of bits per pixel
+ * @depth: driver's private 'number of bits per pixel'
* @buff_cnt: number of physically non-contiguous data planes
* @planes_cnt: number of physically contiguous data planes
*/
struct fimc_fmt {
+ enum v4l2_mbus_pixelcode mbus_code;
char *name;
u32 fourcc;
u32 color;
- u32 depth;
u16 buff_cnt;
u16 planes_cnt;
+ u16 depth;
+ u16 flags;
+#define FMT_FLAGS_CAM (1 << 0)
+#define FMT_FLAGS_M2M (1 << 1)
};
/**
@@ -220,10 +253,14 @@ struct fimc_addr {
/**
* struct fimc_vid_buffer - the driver's video buffer
- * @vb: v4l videobuf buffer
+ * @vb: v4l videobuf buffer
+ * @paddr: precalculated physical address set
+ * @index: buffer index for the output DMA engine
*/
struct fimc_vid_buffer {
struct videobuf_buffer vb;
+ struct fimc_addr paddr;
+ int index;
};
/**
@@ -274,6 +311,40 @@ struct fimc_m2m_device {
};
/**
+ * struct fimc_vid_cap - camera capture device information
+ * @ctx: hardware context data
+ * @vfd: video device node for camera capture mode
+ * @v4l2_dev: v4l2_device struct to manage subdevs
+ * @sd: pointer to camera sensor subdevice currently in use
+ * @fmt: Media Bus format configured at selected image sensor
+ * @pending_buf_q: the pending buffer queue head
+ * @active_buf_q: the queue head of buffers scheduled in hardware
+ * @vbq: the capture am video buffer queue
+ * @active_buf_cnt: number of video buffers scheduled in hardware
+ * @buf_index: index for managing the output DMA buffers
+ * @frame_count: the frame counter for statistics
+ * @reqbufs_count: the number of buffers requested in REQBUFS ioctl
+ * @input_index: input (camera sensor) index
+ * @refcnt: driver's private reference counter
+ */
+struct fimc_vid_cap {
+ struct fimc_ctx *ctx;
+ struct video_device *vfd;
+ struct v4l2_device v4l2_dev;
+ struct v4l2_subdev *sd;
+ struct v4l2_mbus_framefmt fmt;
+ struct list_head pending_buf_q;
+ struct list_head active_buf_q;
+ struct videobuf_queue vbq;
+ int active_buf_cnt;
+ int buf_index;
+ unsigned int frame_count;
+ unsigned int reqbufs_count;
+ int input_index;
+ int refcnt;
+};
+
+/**
* struct samsung_fimc_variant - camera interface variant information
*
* @pix_hoff: indicate whether horizontal offset is in pixels or in bytes
@@ -308,10 +379,12 @@ struct samsung_fimc_variant {
*
* @variant: the variant information for this driver.
* @dev_cnt: number of fimc sub-devices available in SoC
+ * @lclk_frequency: fimc bus clock frequency
*/
struct samsung_fimc_driverdata {
struct samsung_fimc_variant *variant[FIMC_MAX_DEVS];
- int devs_cnt;
+ unsigned long lclk_frequency;
+ int devs_cnt;
};
struct fimc_ctx;
@@ -322,19 +395,23 @@ struct fimc_ctx;
* @slock: the spinlock protecting this data structure
* @lock: the mutex protecting this data structure
* @pdev: pointer to the FIMC platform device
+ * @pdata: pointer to the device platform data
* @id: FIMC device index (0..2)
* @clock[]: the clocks required for FIMC operation
* @regs: the mapped hardware registers
* @regs_res: the resource claimed for IO registers
* @irq: interrupt number of the FIMC subdevice
* @irqlock: spinlock protecting videobuffer queue
+ * @irq_queue:
* @m2m: memory-to-memory V4L2 device information
- * @state: the FIMC device state flags
+ * @vid_cap: camera capture device information
+ * @state: flags used to synchronize m2m and capture mode operation
*/
struct fimc_dev {
spinlock_t slock;
struct mutex lock;
struct platform_device *pdev;
+ struct s3c_platform_fimc *pdata;
struct samsung_fimc_variant *variant;
int id;
struct clk *clock[NUM_FIMC_CLOCKS];
@@ -342,7 +419,9 @@ struct fimc_dev {
struct resource *regs_res;
int irq;
spinlock_t irqlock;
+ wait_queue_head_t irq_queue;
struct fimc_m2m_device m2m;
+ struct fimc_vid_cap vid_cap;
unsigned long state;
};
@@ -387,6 +466,7 @@ struct fimc_ctx {
struct v4l2_m2m_ctx *m2m_ctx;
};
+extern struct videobuf_queue_ops fimc_qops;
static inline int tiled_fmt(struct fimc_fmt *fmt)
{
@@ -433,7 +513,10 @@ static inline struct fimc_frame *ctx_get_frame(struct fimc_ctx *ctx,
struct fimc_frame *frame;
if (V4L2_BUF_TYPE_VIDEO_OUTPUT == type) {
- frame = &ctx->s_frame;
+ if (ctx->state & FIMC_CTX_M2M)
+ frame = &ctx->s_frame;
+ else
+ return ERR_PTR(-EINVAL);
} else if (V4L2_BUF_TYPE_VIDEO_CAPTURE == type) {
frame = &ctx->d_frame;
} else {
@@ -445,6 +528,13 @@ static inline struct fimc_frame *ctx_get_frame(struct fimc_ctx *ctx,
return frame;
}
+static inline u32 fimc_hw_get_frame_index(struct fimc_dev *dev)
+{
+ u32 reg = readl(dev->regs + S5P_CISTATUS);
+ return (reg & S5P_CISTATUS_FRAMECNT_MASK) >>
+ S5P_CISTATUS_FRAMECNT_SHIFT;
+}
+
/* -----------------------------------------------------*/
/* fimc-reg.c */
void fimc_hw_reset(struct fimc_dev *fimc);
@@ -462,6 +552,52 @@ void fimc_hw_set_output_path(struct fimc_ctx *ctx);
void fimc_hw_set_input_addr(struct fimc_dev *fimc, struct fimc_addr *paddr);
void fimc_hw_set_output_addr(struct fimc_dev *fimc, struct fimc_addr *paddr,
int index);
+int fimc_hw_set_camera_source(struct fimc_dev *fimc,
+ struct s3c_fimc_isp_info *cam);
+int fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f);
+int fimc_hw_set_camera_polarity(struct fimc_dev *fimc,
+ struct s3c_fimc_isp_info *cam);
+int fimc_hw_set_camera_type(struct fimc_dev *fimc,
+ struct s3c_fimc_isp_info *cam);
+
+/* -----------------------------------------------------*/
+/* fimc-core.c */
+int fimc_vidioc_enum_fmt(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f);
+int fimc_vidioc_g_fmt(struct file *file, void *priv,
+ struct v4l2_format *f);
+int fimc_vidioc_try_fmt(struct file *file, void *priv,
+ struct v4l2_format *f);
+int fimc_vidioc_g_crop(struct file *file, void *fh,
+ struct v4l2_crop *cr);
+int fimc_vidioc_cropcap(struct file *file, void *fh,
+ struct v4l2_cropcap *cr);
+int fimc_vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc);
+int fimc_vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl);
+
+int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr);
+int check_ctrl_val(struct fimc_ctx *ctx, struct v4l2_control *ctrl);
+int fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_control *ctrl);
+
+struct fimc_fmt *find_format(struct v4l2_format *f, unsigned int mask);
+struct fimc_fmt *find_mbus_format(struct v4l2_mbus_framefmt *f,
+ unsigned int mask);
+
+int fimc_check_scaler_ratio(struct v4l2_rect *r, struct fimc_frame *f);
+int fimc_set_scaler_info(struct fimc_ctx *ctx);
+int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags);
+int fimc_prepare_addr(struct fimc_ctx *ctx, struct fimc_vid_buffer *buf,
+ struct fimc_frame *frame, struct fimc_addr *paddr);
+
+/* -----------------------------------------------------*/
+/* fimc-capture.c */
+int fimc_register_capture_device(struct fimc_dev *fimc);
+void fimc_unregister_capture_device(struct fimc_dev *fimc);
+int fimc_sensor_sd_init(struct fimc_dev *fimc, int index);
+int fimc_vid_cap_buf_queue(struct fimc_dev *fimc,
+ struct fimc_vid_buffer *fimc_vb);
/* Locking: the caller holds fimc->slock */
static inline void fimc_activate_capture(struct fimc_ctx *ctx)
@@ -478,4 +614,51 @@ static inline void fimc_deactivate_capture(struct fimc_dev *fimc)
fimc_hw_en_lastirq(fimc, false);
}
+/*
+ * Add video buffer to the active buffers queue.
+ * The caller holds irqlock spinlock.
+ */
+static inline void active_queue_add(struct fimc_vid_cap *vid_cap,
+ struct fimc_vid_buffer *buf)
+{
+ buf->vb.state = VIDEOBUF_ACTIVE;
+ list_add_tail(&buf->vb.queue, &vid_cap->active_buf_q);
+ vid_cap->active_buf_cnt++;
+}
+
+/*
+ * Pop a video buffer from the capture active buffers queue
+ * Locking: Need to be called with dev->slock held.
+ */
+static inline struct fimc_vid_buffer *
+active_queue_pop(struct fimc_vid_cap *vid_cap)
+{
+ struct fimc_vid_buffer *buf;
+ buf = list_entry(vid_cap->active_buf_q.next,
+ struct fimc_vid_buffer, vb.queue);
+ list_del(&buf->vb.queue);
+ vid_cap->active_buf_cnt--;
+ return buf;
+}
+
+/* Add video buffer to the capture pending buffers queue */
+static inline void fimc_pending_queue_add(struct fimc_vid_cap *vid_cap,
+ struct fimc_vid_buffer *buf)
+{
+ buf->vb.state = VIDEOBUF_QUEUED;
+ list_add_tail(&buf->vb.queue, &vid_cap->pending_buf_q);
+}
+
+/* Add video buffer to the capture pending buffers queue */
+static inline struct fimc_vid_buffer *
+pending_queue_pop(struct fimc_vid_cap *vid_cap)
+{
+ struct fimc_vid_buffer *buf;
+ buf = list_entry(vid_cap->pending_buf_q.next,
+ struct fimc_vid_buffer, vb.queue);
+ list_del(&buf->vb.queue);
+ return buf;
+}
+
+
#endif /* FIMC_CORE_H_ */
diff --git a/drivers/media/video/s5p-fimc/fimc-reg.c b/drivers/media/video/s5p-fimc/fimc-reg.c
index 95adc84..511631a 100644
--- a/drivers/media/video/s5p-fimc/fimc-reg.c
+++ b/drivers/media/video/s5p-fimc/fimc-reg.c
@@ -13,6 +13,7 @@
#include <linux/io.h>
#include <linux/delay.h>
#include <mach/map.h>
+#include <media/s3c_fimc.h>
#include "fimc-core.h"
@@ -176,6 +177,15 @@ static void fimc_hw_set_out_dma_size(struct fimc_ctx *ctx)
cfg = S5P_ORIG_SIZE_HOR(frame->f_width);
cfg |= S5P_ORIG_SIZE_VER(frame->f_height);
writel(cfg, dev->regs + S5P_ORGOSIZE);
+
+ /* Select color space conversion equation (HD/SD size).*/
+ cfg = readl(dev->regs + S5P_CIGCTRL);
+ if (frame->f_width >= 1280) /* HD */
+ cfg |= S5P_CIGCTRL_CSC_ITU601_709;
+ else /* SD */
+ cfg &= ~S5P_CIGCTRL_CSC_ITU601_709;
+ writel(cfg, dev->regs + S5P_CIGCTRL);
+
}
void fimc_hw_set_out_dma(struct fimc_ctx *ctx)
@@ -231,19 +241,12 @@ static void fimc_hw_en_autoload(struct fimc_dev *dev, int enable)
void fimc_hw_en_lastirq(struct fimc_dev *dev, int enable)
{
- unsigned long flags;
- u32 cfg;
-
- spin_lock_irqsave(&dev->slock, flags);
-
- cfg = readl(dev->regs + S5P_CIOCTRL);
+ u32 cfg = readl(dev->regs + S5P_CIOCTRL);
if (enable)
cfg |= S5P_CIOCTRL_LASTIRQ_ENABLE;
else
cfg &= ~S5P_CIOCTRL_LASTIRQ_ENABLE;
writel(cfg, dev->regs + S5P_CIOCTRL);
-
- spin_unlock_irqrestore(&dev->slock, flags);
}
static void fimc_hw_set_prescaler(struct fimc_ctx *ctx)
@@ -325,14 +328,18 @@ void fimc_hw_set_scaler(struct fimc_ctx *ctx)
void fimc_hw_en_capture(struct fimc_ctx *ctx)
{
struct fimc_dev *dev = ctx->fimc_dev;
- u32 cfg;
- cfg = readl(dev->regs + S5P_CIIMGCPT);
- /* One shot mode for output DMA or freerun for FIFO. */
- if (ctx->out_path == FIMC_DMA)
- cfg |= S5P_CIIMGCPT_CPT_FREN_ENABLE;
- else
- cfg &= ~S5P_CIIMGCPT_CPT_FREN_ENABLE;
+ u32 cfg = readl(dev->regs + S5P_CIIMGCPT);
+
+ if (ctx->out_path == FIMC_DMA) {
+ /* one shot mode */
+ cfg |= S5P_CIIMGCPT_CPT_FREN_ENABLE | S5P_CIIMGCPT_IMGCPTEN;
+ } else {
+ /* Continous frame capture mode (freerun). */
+ cfg &= ~(S5P_CIIMGCPT_CPT_FREN_ENABLE |
+ S5P_CIIMGCPT_CPT_FRMOD_CNT);
+ cfg |= S5P_CIIMGCPT_IMGCPTEN;
+ }
if (ctx->scaler.enabled)
cfg |= S5P_CIIMGCPT_IMGCPTEN_SC;
@@ -523,3 +530,139 @@ void fimc_hw_set_output_addr(struct fimc_dev *dev,
i, paddr->y, paddr->cb, paddr->cr);
} while (index == -1 && ++i < FIMC_MAX_OUT_BUFS);
}
+
+int fimc_hw_set_camera_polarity(struct fimc_dev *fimc,
+ struct s3c_fimc_isp_info *cam)
+{
+ u32 cfg = readl(fimc->regs + S5P_CIGCTRL);
+
+ cfg &= ~(S5P_CIGCTRL_INVPOLPCLK | S5P_CIGCTRL_INVPOLVSYNC |
+ S5P_CIGCTRL_INVPOLHREF | S5P_CIGCTRL_INVPOLHSYNC);
+
+ if (cam->flags & FIMC_CLK_INV_PCLK)
+ cfg |= S5P_CIGCTRL_INVPOLPCLK;
+
+ if (cam->flags & FIMC_CLK_INV_VSYNC)
+ cfg |= S5P_CIGCTRL_INVPOLVSYNC;
+
+ if (cam->flags & FIMC_CLK_INV_HREF)
+ cfg |= S5P_CIGCTRL_INVPOLHREF;
+
+ if (cam->flags & FIMC_CLK_INV_HSYNC)
+ cfg |= S5P_CIGCTRL_INVPOLHSYNC;
+
+ writel(cfg, fimc->regs + S5P_CIGCTRL);
+
+ return 0;
+}
+
+int fimc_hw_set_camera_source(struct fimc_dev *fimc,
+ struct s3c_fimc_isp_info *cam)
+{
+ struct fimc_frame *f = &fimc->vid_cap.ctx->s_frame;
+ u32 cfg = 0;
+
+ if (cam->bus_type == FIMC_ITU_601 || cam->bus_type == FIMC_ITU_656) {
+
+ switch (fimc->vid_cap.fmt.code) {
+ case V4L2_MBUS_FMT_YUYV8_2X8:
+ cfg = S5P_CISRCFMT_ORDER422_YCBYCR;
+ break;
+ case V4L2_MBUS_FMT_YVYU8_2X8:
+ cfg = S5P_CISRCFMT_ORDER422_YCRYCB;
+ break;
+ case V4L2_MBUS_FMT_VYUY8_2X8:
+ cfg = S5P_CISRCFMT_ORDER422_CRYCBY;
+ break;
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ cfg = S5P_CISRCFMT_ORDER422_CBYCRY;
+ break;
+ default:
+ err("camera image format not supported: %d",
+ fimc->vid_cap.fmt.code);
+ return -EINVAL;
+ }
+
+ if (cam->bus_type == FIMC_ITU_601) {
+ if (cam->bus_width == 8) {
+ cfg |= S5P_CISRCFMT_ITU601_8BIT;
+ } else if (cam->bus_width == 16) {
+ cfg |= S5P_CISRCFMT_ITU601_16BIT;
+ } else {
+ err("invalid bus width: %d", cam->bus_width);
+ return -EINVAL;
+ }
+ } /* else defaults to ITU-R BT.656 8-bit */
+ }
+
+ cfg |= S5P_CISRCFMT_HSIZE(f->o_width) | S5P_CISRCFMT_VSIZE(f->o_height);
+ writel(cfg, fimc->regs + S5P_CISRCFMT);
+ return 0;
+}
+
+
+int fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f)
+{
+ u32 hoff2, voff2;
+
+ u32 cfg = readl(fimc->regs + S5P_CIWDOFST);
+
+ cfg &= ~(S5P_CIWDOFST_HOROFF_MASK | S5P_CIWDOFST_VEROFF_MASK);
+ cfg |= S5P_CIWDOFST_OFF_EN |
+ S5P_CIWDOFST_HOROFF(f->offs_h) |
+ S5P_CIWDOFST_VEROFF(f->offs_v);
+
+ writel(cfg, fimc->regs + S5P_CIWDOFST);
+
+ /* See CIWDOFSTn register description in the datasheet for details. */
+ hoff2 = f->o_width - f->width - f->offs_h;
+ voff2 = f->o_height - f->height - f->offs_v;
+ cfg = S5P_CIWDOFST2_HOROFF(hoff2) | S5P_CIWDOFST2_VEROFF(voff2);
+
+ writel(cfg, fimc->regs + S5P_CIWDOFST2);
+ return 0;
+}
+
+int fimc_hw_set_camera_type(struct fimc_dev *fimc,
+ struct s3c_fimc_isp_info *cam)
+{
+ u32 cfg, tmp;
+ struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
+
+ cfg = readl(fimc->regs + S5P_CIGCTRL);
+
+ /* Select ITU B interface, disable Writeback path and test pattern. */
+ cfg &= ~(S5P_CIGCTRL_TESTPAT_MASK | S5P_CIGCTRL_SELCAM_ITU_A |
+ S5P_CIGCTRL_SELCAM_MIPI | S5P_CIGCTRL_CAMIF_SELWB |
+ S5P_CIGCTRL_SELCAM_MIPI_A);
+
+ if (cam->bus_type == FIMC_MIPI_CSI2) {
+ cfg |= S5P_CIGCTRL_SELCAM_MIPI;
+
+ if (cam->mux_id == 0)
+ cfg |= S5P_CIGCTRL_SELCAM_MIPI_A;
+
+ /* TODO: add remaining supported formats. */
+ if (vid_cap->fmt.code == V4L2_MBUS_FMT_VYUY8_2X8) {
+ tmp = S5P_CSIIMGFMT_YCBCR422_8BIT;
+ } else {
+ err("camera image format not supported: %d",
+ vid_cap->fmt.code);
+ return -EINVAL;
+ }
+ writel(tmp | (0x1 << 8), fimc->regs + S5P_CSIIMGFMT);
+
+ } else if (cam->bus_type == FIMC_ITU_601 ||
+ cam->bus_type == FIMC_ITU_656) {
+ if (cam->mux_id == 0) /* ITU-A, ITU-B: 0, 1 */
+ cfg |= S5P_CIGCTRL_SELCAM_ITU_A;
+ } else if (cam->bus_type == FIMC_LCD_WB) {
+ cfg |= S5P_CIGCTRL_CAMIF_SELWB;
+ } else {
+ err("invalid camera bus type selected\n");
+ return -EINVAL;
+ }
+ writel(cfg, fimc->regs + S5P_CIGCTRL);
+
+ return 0;
+}
diff --git a/include/media/s3c_fimc.h b/include/media/s3c_fimc.h
new file mode 100644
index 0000000..ca1b673
--- /dev/null
+++ b/include/media/s3c_fimc.h
@@ -0,0 +1,60 @@
+/*
+ * Samsung S5P SoC camera interface driver header
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd
+ * Author: Sylwester Nawrocki, <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef S3C_FIMC_H_
+#define S3C_FIMC_H_
+
+enum cam_bus_type {
+ FIMC_ITU_601 = 1,
+ FIMC_ITU_656,
+ FIMC_MIPI_CSI2,
+ FIMC_LCD_WB, /* FIFO link from LCD mixer */
+};
+
+#define FIMC_CLK_INV_PCLK (1 << 0)
+#define FIMC_CLK_INV_VSYNC (1 << 1)
+#define FIMC_CLK_INV_HREF (1 << 2)
+#define FIMC_CLK_INV_HSYNC (1 << 3)
+
+struct i2c_board_info;
+
+/**
+ * struct s3c_fimc_isp_info - image sensor information required for host
+ * interace configuration.
+ *
+ * @board_info: pointer to I2C subdevice's board info
+ * @bus_type: determines bus type, MIPI, ITU-R BT.601 etc.
+ * @i2c_bus_num: i2c control bus id the sensor is attached to
+ * @mux_id: FIMC camera interface multiplexer index (separate for MIPI and ITU)
+ * @bus_width: camera data bus width in bits
+ * @flags: flags defining bus signals polarity inversion (High by default)
+ */
+struct s3c_fimc_isp_info {
+ struct i2c_board_info *board_info;
+ enum cam_bus_type bus_type;
+ u16 i2c_bus_num;
+ u16 mux_id;
+ u16 bus_width;
+ u16 flags;
+};
+
+
+#define FIMC_MAX_CAMIF_CLIENTS 2
+
+/**
+ * struct s3c_platform_fimc - camera host interface platform data
+ *
+ * @isp_info: properties of camera sensor required for host interface setup
+ */
+struct s3c_platform_fimc {
+ struct s3c_fimc_isp_info *isp_info[FIMC_MAX_CAMIF_CLIENTS];
+};
+#endif /* S3C_FIMC_H_ */
--
1.7.3.1
^ permalink raw reply related
* [PATCH 4/5 v4] V4L/DVB: s5p-fimc: Do not lock both buffer queues in s_fmt
From: Sylwester Nawrocki @ 2010-10-08 8:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1286527837-4980-1-git-send-email-s.nawrocki@samsung.com>
It is not necessary to lock both capture and output buffer queue while
setting format for single queue.
Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
drivers/media/video/s5p-fimc/fimc-core.c | 69 +++++++++++++----------------
1 files changed, 31 insertions(+), 38 deletions(-)
diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c
index 27379a6..23cc054 100644
--- a/drivers/media/video/s5p-fimc/fimc-core.c
+++ b/drivers/media/video/s5p-fimc/fimc-core.c
@@ -742,8 +742,9 @@ static int fimc_m2m_try_fmt(struct file *file, void *priv,
static int fimc_m2m_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
{
struct fimc_ctx *ctx = priv;
- struct v4l2_device *v4l2_dev = &ctx->fimc_dev->m2m.v4l2_dev;
- struct videobuf_queue *src_vq, *dst_vq;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct v4l2_device *v4l2_dev = &fimc->m2m.v4l2_dev;
+ struct videobuf_queue *vq;
struct fimc_frame *frame;
struct v4l2_pix_format *pix;
unsigned long flags;
@@ -755,69 +756,61 @@ static int fimc_m2m_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
if (ret)
return ret;
- mutex_lock(&ctx->fimc_dev->lock);
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
- src_vq = v4l2_m2m_get_src_vq(ctx->m2m_ctx);
- dst_vq = v4l2_m2m_get_dst_vq(ctx->m2m_ctx);
+ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+ mutex_lock(&vq->vb_lock);
- mutex_lock(&src_vq->vb_lock);
- mutex_lock(&dst_vq->vb_lock);
+ if (videobuf_queue_is_busy(vq)) {
+ v4l2_err(v4l2_dev, "%s: queue (%d) busy\n", __func__, f->type);
+ ret = -EBUSY;
+ goto sf_out;
+ }
+ spin_lock_irqsave(&ctx->slock, flags);
if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
- if (videobuf_queue_is_busy(src_vq)) {
- v4l2_err(v4l2_dev, "%s queue busy\n", __func__);
- ret = -EBUSY;
- goto s_fmt_out;
- }
frame = &ctx->s_frame;
- spin_lock_irqsave(&ctx->slock, flags);
ctx->state |= FIMC_SRC_FMT;
- spin_unlock_irqrestore(&ctx->slock, flags);
-
} else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- if (videobuf_queue_is_busy(dst_vq)) {
- v4l2_err(v4l2_dev, "%s queue busy\n", __func__);
- ret = -EBUSY;
- goto s_fmt_out;
- }
frame = &ctx->d_frame;
- spin_lock_irqsave(&ctx->slock, flags);
ctx->state |= FIMC_DST_FMT;
- spin_unlock_irqrestore(&ctx->slock, flags);
} else {
+ spin_unlock_irqrestore(&ctx->slock, flags);
v4l2_err(&ctx->fimc_dev->m2m.v4l2_dev,
"Wrong buffer/video queue type (%d)\n", f->type);
ret = -EINVAL;
- goto s_fmt_out;
+ goto sf_out;
}
+ spin_unlock_irqrestore(&ctx->slock, flags);
pix = &f->fmt.pix;
frame->fmt = find_format(f);
if (!frame->fmt) {
ret = -EINVAL;
- goto s_fmt_out;
+ goto sf_out;
}
- frame->f_width = pix->bytesperline * 8 / frame->fmt->depth;
- frame->f_height = pix->sizeimage/pix->bytesperline;
- frame->width = pix->width;
- frame->height = pix->height;
- frame->o_width = pix->width;
+ frame->f_width = pix->bytesperline * 8 / frame->fmt->depth;
+ frame->f_height = pix->height;
+ frame->width = pix->width;
+ frame->height = pix->height;
+ frame->o_width = pix->width;
frame->o_height = pix->height;
- frame->offs_h = 0;
- frame->offs_v = 0;
- frame->size = (pix->width * pix->height * frame->fmt->depth) >> 3;
- src_vq->field = dst_vq->field = pix->field;
+ frame->offs_h = 0;
+ frame->offs_v = 0;
+ frame->size = (pix->width * pix->height * frame->fmt->depth) >> 3;
+ vq->field = pix->field;
+
spin_lock_irqsave(&ctx->slock, flags);
ctx->state |= FIMC_PARAMS;
spin_unlock_irqrestore(&ctx->slock, flags);
- dbg("f_width= %d, f_height= %d", frame->f_width, frame->f_height);
+ dbg("f_w: %d, f_h: %d", frame->f_width, frame->f_height);
-s_fmt_out:
- mutex_unlock(&dst_vq->vb_lock);
- mutex_unlock(&src_vq->vb_lock);
- mutex_unlock(&ctx->fimc_dev->lock);
+sf_out:
+ mutex_unlock(&vq->vb_lock);
+ mutex_unlock(&fimc->lock);
return ret;
}
--
1.7.3.1
^ permalink raw reply related
* [PATCH 4/5 v4] V4L/DVB: s5p-fimc: Do not lock both buffer queues in s_fmt
From: Sylwester Nawrocki @ 2010-10-08 8:50 UTC (permalink / raw)
To: linux-media, linux-arm-kernel, linux-samsung-soc
Cc: m.szyprowski, kyungmin.park, s.nawrocki
In-Reply-To: <1286527837-4980-1-git-send-email-s.nawrocki@samsung.com>
It is not necessary to lock both capture and output buffer queue while
setting format for single queue.
Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
drivers/media/video/s5p-fimc/fimc-core.c | 69 +++++++++++++----------------
1 files changed, 31 insertions(+), 38 deletions(-)
diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c
index 27379a6..23cc054 100644
--- a/drivers/media/video/s5p-fimc/fimc-core.c
+++ b/drivers/media/video/s5p-fimc/fimc-core.c
@@ -742,8 +742,9 @@ static int fimc_m2m_try_fmt(struct file *file, void *priv,
static int fimc_m2m_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
{
struct fimc_ctx *ctx = priv;
- struct v4l2_device *v4l2_dev = &ctx->fimc_dev->m2m.v4l2_dev;
- struct videobuf_queue *src_vq, *dst_vq;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct v4l2_device *v4l2_dev = &fimc->m2m.v4l2_dev;
+ struct videobuf_queue *vq;
struct fimc_frame *frame;
struct v4l2_pix_format *pix;
unsigned long flags;
@@ -755,69 +756,61 @@ static int fimc_m2m_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
if (ret)
return ret;
- mutex_lock(&ctx->fimc_dev->lock);
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
- src_vq = v4l2_m2m_get_src_vq(ctx->m2m_ctx);
- dst_vq = v4l2_m2m_get_dst_vq(ctx->m2m_ctx);
+ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+ mutex_lock(&vq->vb_lock);
- mutex_lock(&src_vq->vb_lock);
- mutex_lock(&dst_vq->vb_lock);
+ if (videobuf_queue_is_busy(vq)) {
+ v4l2_err(v4l2_dev, "%s: queue (%d) busy\n", __func__, f->type);
+ ret = -EBUSY;
+ goto sf_out;
+ }
+ spin_lock_irqsave(&ctx->slock, flags);
if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
- if (videobuf_queue_is_busy(src_vq)) {
- v4l2_err(v4l2_dev, "%s queue busy\n", __func__);
- ret = -EBUSY;
- goto s_fmt_out;
- }
frame = &ctx->s_frame;
- spin_lock_irqsave(&ctx->slock, flags);
ctx->state |= FIMC_SRC_FMT;
- spin_unlock_irqrestore(&ctx->slock, flags);
-
} else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- if (videobuf_queue_is_busy(dst_vq)) {
- v4l2_err(v4l2_dev, "%s queue busy\n", __func__);
- ret = -EBUSY;
- goto s_fmt_out;
- }
frame = &ctx->d_frame;
- spin_lock_irqsave(&ctx->slock, flags);
ctx->state |= FIMC_DST_FMT;
- spin_unlock_irqrestore(&ctx->slock, flags);
} else {
+ spin_unlock_irqrestore(&ctx->slock, flags);
v4l2_err(&ctx->fimc_dev->m2m.v4l2_dev,
"Wrong buffer/video queue type (%d)\n", f->type);
ret = -EINVAL;
- goto s_fmt_out;
+ goto sf_out;
}
+ spin_unlock_irqrestore(&ctx->slock, flags);
pix = &f->fmt.pix;
frame->fmt = find_format(f);
if (!frame->fmt) {
ret = -EINVAL;
- goto s_fmt_out;
+ goto sf_out;
}
- frame->f_width = pix->bytesperline * 8 / frame->fmt->depth;
- frame->f_height = pix->sizeimage/pix->bytesperline;
- frame->width = pix->width;
- frame->height = pix->height;
- frame->o_width = pix->width;
+ frame->f_width = pix->bytesperline * 8 / frame->fmt->depth;
+ frame->f_height = pix->height;
+ frame->width = pix->width;
+ frame->height = pix->height;
+ frame->o_width = pix->width;
frame->o_height = pix->height;
- frame->offs_h = 0;
- frame->offs_v = 0;
- frame->size = (pix->width * pix->height * frame->fmt->depth) >> 3;
- src_vq->field = dst_vq->field = pix->field;
+ frame->offs_h = 0;
+ frame->offs_v = 0;
+ frame->size = (pix->width * pix->height * frame->fmt->depth) >> 3;
+ vq->field = pix->field;
+
spin_lock_irqsave(&ctx->slock, flags);
ctx->state |= FIMC_PARAMS;
spin_unlock_irqrestore(&ctx->slock, flags);
- dbg("f_width= %d, f_height= %d", frame->f_width, frame->f_height);
+ dbg("f_w: %d, f_h: %d", frame->f_width, frame->f_height);
-s_fmt_out:
- mutex_unlock(&dst_vq->vb_lock);
- mutex_unlock(&src_vq->vb_lock);
- mutex_unlock(&ctx->fimc_dev->lock);
+sf_out:
+ mutex_unlock(&vq->vb_lock);
+ mutex_unlock(&fimc->lock);
return ret;
}
--
1.7.3.1
^ permalink raw reply related
* [PATCH 3/5 v4] V4L/DVB: s5p-fimc: Fix 90/270 deg rotation errors
From: Sylwester Nawrocki @ 2010-10-08 8:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1286527837-4980-1-git-send-email-s.nawrocki@samsung.com>
Due to errorneous swapping of image dimensions the rotation
control was not handled properly in subsequent calls.
Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
drivers/media/video/s5p-fimc/fimc-core.c | 15 ++---
drivers/media/video/s5p-fimc/fimc-reg.c | 101 +++++++++++++++---------------
2 files changed, 57 insertions(+), 59 deletions(-)
diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c
index fccab13..27379a6 100644
--- a/drivers/media/video/s5p-fimc/fimc-core.c
+++ b/drivers/media/video/s5p-fimc/fimc-core.c
@@ -207,8 +207,13 @@ static int fimc_set_scaler_info(struct fimc_ctx *ctx)
int tx, ty, sx, sy;
int ret;
- tx = d_frame->width;
- ty = d_frame->height;
+ if (ctx->rotation == 90 || ctx->rotation == 270) {
+ ty = d_frame->width;
+ tx = d_frame->height;
+ } else {
+ tx = d_frame->width;
+ ty = d_frame->height;
+ }
if (tx <= 0 || ty <= 0) {
v4l2_err(&ctx->fimc_dev->m2m.v4l2_dev,
"invalid target size: %d x %d", tx, ty);
@@ -429,12 +434,6 @@ static int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags)
d_frame = &ctx->d_frame;
if (flags & FIMC_PARAMS) {
- if ((ctx->out_path == FIMC_DMA) &&
- (ctx->rotation == 90 || ctx->rotation == 270)) {
- swap(d_frame->f_width, d_frame->f_height);
- swap(d_frame->width, d_frame->height);
- }
-
/* Prepare the DMA offset ratios for scaler. */
fimc_prepare_dma_offset(ctx, &ctx->s_frame);
fimc_prepare_dma_offset(ctx, &ctx->d_frame);
diff --git a/drivers/media/video/s5p-fimc/fimc-reg.c b/drivers/media/video/s5p-fimc/fimc-reg.c
index 94e98d4..95adc84 100644
--- a/drivers/media/video/s5p-fimc/fimc-reg.c
+++ b/drivers/media/video/s5p-fimc/fimc-reg.c
@@ -34,44 +34,6 @@ void fimc_hw_reset(struct fimc_dev *dev)
cfg = readl(dev->regs + S5P_CIGCTRL);
cfg &= ~S5P_CIGCTRL_SWRST;
writel(cfg, dev->regs + S5P_CIGCTRL);
-
-}
-
-void fimc_hw_set_rotation(struct fimc_ctx *ctx)
-{
- u32 cfg, flip;
- struct fimc_dev *dev = ctx->fimc_dev;
-
- cfg = readl(dev->regs + S5P_CITRGFMT);
- cfg &= ~(S5P_CITRGFMT_INROT90 | S5P_CITRGFMT_OUTROT90);
-
- flip = readl(dev->regs + S5P_MSCTRL);
- flip &= ~S5P_MSCTRL_FLIP_MASK;
-
- /*
- * The input and output rotator cannot work simultaneously.
- * Use the output rotator in output DMA mode or the input rotator
- * in direct fifo output mode.
- */
- if (ctx->rotation == 90 || ctx->rotation == 270) {
- if (ctx->out_path == FIMC_LCDFIFO) {
- cfg |= S5P_CITRGFMT_INROT90;
- if (ctx->rotation == 270)
- flip |= S5P_MSCTRL_FLIP_180;
- } else {
- cfg |= S5P_CITRGFMT_OUTROT90;
- if (ctx->rotation == 270)
- cfg |= S5P_CITRGFMT_FLIP_180;
- }
- } else if (ctx->rotation == 180) {
- if (ctx->out_path == FIMC_LCDFIFO)
- flip |= S5P_MSCTRL_FLIP_180;
- else
- cfg |= S5P_CITRGFMT_FLIP_180;
- }
- if (ctx->rotation == 180 || ctx->rotation == 270)
- writel(flip, dev->regs + S5P_MSCTRL);
- writel(cfg, dev->regs + S5P_CITRGFMT);
}
static u32 fimc_hw_get_in_flip(u32 ctx_flip)
@@ -114,6 +76,46 @@ static u32 fimc_hw_get_target_flip(u32 ctx_flip)
return flip;
}
+void fimc_hw_set_rotation(struct fimc_ctx *ctx)
+{
+ u32 cfg, flip;
+ struct fimc_dev *dev = ctx->fimc_dev;
+
+ cfg = readl(dev->regs + S5P_CITRGFMT);
+ cfg &= ~(S5P_CITRGFMT_INROT90 | S5P_CITRGFMT_OUTROT90 |
+ S5P_CITRGFMT_FLIP_180);
+
+ flip = readl(dev->regs + S5P_MSCTRL);
+ flip &= ~S5P_MSCTRL_FLIP_MASK;
+
+ /*
+ * The input and output rotator cannot work simultaneously.
+ * Use the output rotator in output DMA mode or the input rotator
+ * in direct fifo output mode.
+ */
+ if (ctx->rotation == 90 || ctx->rotation == 270) {
+ if (ctx->out_path == FIMC_LCDFIFO) {
+ cfg |= S5P_CITRGFMT_INROT90;
+ if (ctx->rotation == 270)
+ flip |= S5P_MSCTRL_FLIP_180;
+ } else {
+ cfg |= S5P_CITRGFMT_OUTROT90;
+ if (ctx->rotation == 270)
+ cfg |= S5P_CITRGFMT_FLIP_180;
+ }
+ } else if (ctx->rotation == 180) {
+ if (ctx->out_path == FIMC_LCDFIFO)
+ flip |= S5P_MSCTRL_FLIP_180;
+ else
+ cfg |= S5P_CITRGFMT_FLIP_180;
+ }
+ if (ctx->rotation == 180 || ctx->rotation == 270)
+ writel(flip, dev->regs + S5P_MSCTRL);
+
+ cfg |= fimc_hw_get_target_flip(ctx->flip);
+ writel(cfg, dev->regs + S5P_CITRGFMT);
+}
+
void fimc_hw_set_target_format(struct fimc_ctx *ctx)
{
u32 cfg;
@@ -149,13 +151,15 @@ void fimc_hw_set_target_format(struct fimc_ctx *ctx)
break;
}
- cfg |= S5P_CITRGFMT_HSIZE(frame->width);
- cfg |= S5P_CITRGFMT_VSIZE(frame->height);
+ if (ctx->rotation == 90 || ctx->rotation == 270) {
+ cfg |= S5P_CITRGFMT_HSIZE(frame->height);
+ cfg |= S5P_CITRGFMT_VSIZE(frame->width);
+ } else {
- if (ctx->rotation == 0) {
- cfg &= ~S5P_CITRGFMT_FLIP_MASK;
- cfg |= fimc_hw_get_target_flip(ctx->flip);
+ cfg |= S5P_CITRGFMT_HSIZE(frame->width);
+ cfg |= S5P_CITRGFMT_VSIZE(frame->height);
}
+
writel(cfg, dev->regs + S5P_CITRGFMT);
cfg = readl(dev->regs + S5P_CITAREA) & ~S5P_CITAREA_MASK;
@@ -167,15 +171,10 @@ static void fimc_hw_set_out_dma_size(struct fimc_ctx *ctx)
{
struct fimc_dev *dev = ctx->fimc_dev;
struct fimc_frame *frame = &ctx->d_frame;
- u32 cfg = 0;
+ u32 cfg;
- if (ctx->rotation == 90 || ctx->rotation == 270) {
- cfg |= S5P_ORIG_SIZE_HOR(frame->f_height);
- cfg |= S5P_ORIG_SIZE_VER(frame->f_width);
- } else {
- cfg |= S5P_ORIG_SIZE_HOR(frame->f_width);
- cfg |= S5P_ORIG_SIZE_VER(frame->f_height);
- }
+ cfg = S5P_ORIG_SIZE_HOR(frame->f_width);
+ cfg |= S5P_ORIG_SIZE_VER(frame->f_height);
writel(cfg, dev->regs + S5P_ORGOSIZE);
}
--
1.7.3.1
^ permalink raw reply related
* [PATCH 2/5 v4] V4L/DVB: s5p-fimc: mem2mem driver refactoring and cleanup
From: Sylwester Nawrocki @ 2010-10-08 8:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1286527837-4980-1-git-send-email-s.nawrocki@samsung.com>
Register access functions refactored for camera capture interface
control. Removed the workqueue since it was only useful for FIFO
output mode which is not supported at this time.
Fixed errors on module unload. Comments and whitespace cleanup.
Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
drivers/media/video/s5p-fimc/fimc-core.c | 151 +++++++++++-------------------
drivers/media/video/s5p-fimc/fimc-core.h | 132 ++++++++++++++------------
drivers/media/video/s5p-fimc/fimc-reg.c | 43 ++++-----
3 files changed, 148 insertions(+), 178 deletions(-)
diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c
index c56029e..fccab13 100644
--- a/drivers/media/video/s5p-fimc/fimc-core.c
+++ b/drivers/media/video/s5p-fimc/fimc-core.c
@@ -117,7 +117,7 @@ static struct fimc_fmt fimc_formats[] = {
.buff_cnt = 1,
.planes_cnt = 2
}
- };
+};
static struct v4l2_queryctrl fimc_ctrls[] = {
{
@@ -127,16 +127,14 @@ static struct v4l2_queryctrl fimc_ctrls[] = {
.minimum = 0,
.maximum = 1,
.default_value = 0,
- },
- {
+ }, {
.id = V4L2_CID_VFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "Vertical flip",
.minimum = 0,
.maximum = 1,
.default_value = 0,
- },
- {
+ }, {
.id = V4L2_CID_ROTATE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Rotation (CCW)",
@@ -181,28 +179,23 @@ static int fimc_check_scaler_ratio(struct v4l2_rect *r, struct fimc_frame *f)
static int fimc_get_scaler_factor(u32 src, u32 tar, u32 *ratio, u32 *shift)
{
- if (src >= tar * 64) {
+ u32 sh = 6;
+
+ if (src >= 64 * tar)
return -EINVAL;
- } else if (src >= tar * 32) {
- *ratio = 32;
- *shift = 5;
- } else if (src >= tar * 16) {
- *ratio = 16;
- *shift = 4;
- } else if (src >= tar * 8) {
- *ratio = 8;
- *shift = 3;
- } else if (src >= tar * 4) {
- *ratio = 4;
- *shift = 2;
- } else if (src >= tar * 2) {
- *ratio = 2;
- *shift = 1;
- } else {
- *ratio = 1;
- *shift = 0;
+
+ while (sh--) {
+ u32 tmp = 1 << sh;
+ if (src >= tar * tmp) {
+ *shift = sh, *ratio = tmp;
+ return 0;
+ }
}
+ *shift = 0, *ratio = 1;
+
+ dbg("s: %d, t: %d, shift: %d, ratio: %d",
+ src, tar, *shift, *ratio);
return 0;
}
@@ -265,8 +258,8 @@ static int fimc_set_scaler_info(struct fimc_ctx *ctx)
static irqreturn_t fimc_isr(int irq, void *priv)
{
struct fimc_vid_buffer *src_buf, *dst_buf;
- struct fimc_dev *fimc = (struct fimc_dev *)priv;
struct fimc_ctx *ctx;
+ struct fimc_dev *fimc = priv;
BUG_ON(!fimc);
fimc_hw_clear_irq(fimc);
@@ -281,7 +274,7 @@ static irqreturn_t fimc_isr(int irq, void *priv)
dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
if (src_buf && dst_buf) {
spin_lock(&fimc->irqlock);
- src_buf->vb.state = dst_buf->vb.state = VIDEOBUF_DONE;
+ src_buf->vb.state = dst_buf->vb.state = VIDEOBUF_DONE;
wake_up(&src_buf->vb.done);
wake_up(&dst_buf->vb.done);
spin_unlock(&fimc->irqlock);
@@ -295,20 +288,13 @@ isr_unlock:
}
/* The color format (planes_cnt, buff_cnt) must be already configured. */
-static int fimc_prepare_addr(struct fimc_ctx *ctx,
- struct fimc_vid_buffer *buf, enum v4l2_buf_type type)
+int fimc_prepare_addr(struct fimc_ctx *ctx, struct fimc_vid_buffer *buf,
+ struct fimc_frame *frame, struct fimc_addr *paddr)
{
- struct fimc_frame *frame;
- struct fimc_addr *paddr;
- u32 pix_size;
int ret = 0;
+ u32 pix_size;
- frame = ctx_m2m_get_frame(ctx, type);
- if (IS_ERR(frame))
- return PTR_ERR(frame);
- paddr = &frame->paddr;
-
- if (!buf)
+ if (buf == NULL || frame == NULL)
return -EINVAL;
pix_size = frame->width * frame->height;
@@ -344,8 +330,8 @@ static int fimc_prepare_addr(struct fimc_ctx *ctx,
}
}
- dbg("PHYS_ADDR: type= %d, y= 0x%X cb= 0x%X cr= 0x%X ret= %d",
- type, paddr->y, paddr->cb, paddr->cr, ret);
+ dbg("PHYS_ADDR: y= 0x%X cb= 0x%X cr= 0x%X ret= %d",
+ paddr->y, paddr->cb, paddr->cr, ret);
return ret;
}
@@ -466,16 +452,14 @@ static int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags)
if (flags & FIMC_SRC_ADDR) {
buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
- ret = fimc_prepare_addr(ctx, buf,
- V4L2_BUF_TYPE_VIDEO_OUTPUT);
+ ret = fimc_prepare_addr(ctx, buf, s_frame, &s_frame->paddr);
if (ret)
return ret;
}
if (flags & FIMC_DST_ADDR) {
buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
- ret = fimc_prepare_addr(ctx, buf,
- V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ ret = fimc_prepare_addr(ctx, buf, d_frame, &d_frame->paddr);
}
return ret;
@@ -499,12 +483,14 @@ static void fimc_dma_run(void *priv)
ctx->state |= (FIMC_SRC_ADDR | FIMC_DST_ADDR);
ret = fimc_prepare_config(ctx, ctx->state);
if (ret) {
- err("general configuration error");
+ err("Wrong parameters");
goto dma_unlock;
}
-
- if (fimc->m2m.ctx != ctx)
+ /* Reconfigure hardware if the context has changed. */
+ if (fimc->m2m.ctx != ctx) {
ctx->state |= FIMC_PARAMS;
+ fimc->m2m.ctx = ctx;
+ }
fimc_hw_set_input_addr(fimc, &ctx->s_frame.paddr);
@@ -512,10 +498,9 @@ static void fimc_dma_run(void *priv)
fimc_hw_set_input_path(ctx);
fimc_hw_set_in_dma(ctx);
if (fimc_set_scaler_info(ctx)) {
- err("scaler configuration error");
+ err("Scaler setup error");
goto dma_unlock;
}
- fimc_hw_set_prescaler(ctx);
fimc_hw_set_scaler(ctx);
fimc_hw_set_target_format(ctx);
fimc_hw_set_rotation(ctx);
@@ -524,19 +509,15 @@ static void fimc_dma_run(void *priv)
fimc_hw_set_output_path(ctx);
if (ctx->state & (FIMC_DST_ADDR | FIMC_PARAMS))
- fimc_hw_set_output_addr(fimc, &ctx->d_frame.paddr);
+ fimc_hw_set_output_addr(fimc, &ctx->d_frame.paddr, -1);
if (ctx->state & FIMC_PARAMS)
fimc_hw_set_out_dma(ctx);
- if (ctx->scaler.enabled)
- fimc_hw_start_scaler(fimc);
- fimc_hw_en_capture(ctx);
-
ctx->state = 0;
- fimc_hw_start_in_dma(fimc);
+ fimc_activate_capture(ctx);
- fimc->m2m.ctx = ctx;
+ fimc_hw_activate_input_dma(fimc, true);
dma_unlock:
spin_unlock_irqrestore(&ctx->slock, flags);
@@ -560,7 +541,7 @@ static int fimc_buf_setup(struct videobuf_queue *vq, unsigned int *count,
struct fimc_ctx *ctx = vq->priv_data;
struct fimc_frame *frame;
- frame = ctx_m2m_get_frame(ctx, vq->type);
+ frame = ctx_get_frame(ctx, vq->type);
if (IS_ERR(frame))
return PTR_ERR(frame);
@@ -578,7 +559,7 @@ static int fimc_buf_prepare(struct videobuf_queue *vq,
struct fimc_frame *frame;
int ret;
- frame = ctx_m2m_get_frame(ctx, vq->type);
+ frame = ctx_get_frame(ctx, vq->type);
if (IS_ERR(frame))
return PTR_ERR(frame);
@@ -663,7 +644,7 @@ static int fimc_m2m_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
struct fimc_ctx *ctx = priv;
struct fimc_frame *frame;
- frame = ctx_m2m_get_frame(ctx, f->type);
+ frame = ctx_get_frame(ctx, f->type);
if (IS_ERR(frame))
return PTR_ERR(frame);
@@ -999,7 +980,7 @@ static int fimc_m2m_cropcap(struct file *file, void *fh,
struct fimc_frame *frame;
struct fimc_ctx *ctx = fh;
- frame = ctx_m2m_get_frame(ctx, cr->type);
+ frame = ctx_get_frame(ctx, cr->type);
if (IS_ERR(frame))
return PTR_ERR(frame);
@@ -1019,7 +1000,7 @@ static int fimc_m2m_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
struct fimc_frame *frame;
struct fimc_ctx *ctx = file->private_data;
- frame = ctx_m2m_get_frame(ctx, cr->type);
+ frame = ctx_get_frame(ctx, cr->type);
if (IS_ERR(frame))
return PTR_ERR(frame);
@@ -1052,7 +1033,7 @@ static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr)
return -EINVAL;
}
- f = ctx_m2m_get_frame(ctx, cr->type);
+ f = ctx_get_frame(ctx, cr->type);
if (IS_ERR(f))
return PTR_ERR(f);
@@ -1136,7 +1117,7 @@ static void queue_init(void *priv, struct videobuf_queue *vq,
struct fimc_dev *fimc = ctx->fimc_dev;
videobuf_queue_dma_contig_init(vq, &fimc_qops,
- fimc->m2m.v4l2_dev.dev,
+ &fimc->pdev->dev,
&fimc->irqlock, type, V4L2_FIELD_NONE,
sizeof(struct fimc_vid_buffer), priv, NULL);
}
@@ -1159,13 +1140,12 @@ static int fimc_m2m_open(struct file *file)
file->private_data = ctx;
ctx->fimc_dev = fimc;
- /* default format */
+ /* Default color format */
ctx->s_frame.fmt = &fimc_formats[0];
ctx->d_frame.fmt = &fimc_formats[0];
/* per user process device context initialization */
ctx->state = 0;
ctx->flags = 0;
- ctx->effect.type = S5P_FIMC_EFFECT_ORIGINAL;
ctx->in_path = FIMC_DMA;
ctx->out_path = FIMC_DMA;
spin_lock_init(&ctx->slock);
@@ -1241,7 +1221,7 @@ static int fimc_register_m2m_device(struct fimc_dev *fimc)
ret = v4l2_device_register(&pdev->dev, v4l2_dev);
if (ret)
- return ret;;
+ goto err_m2m_r1;
vfd = video_device_alloc();
if (!vfd) {
@@ -1293,7 +1273,7 @@ static void fimc_unregister_m2m_device(struct fimc_dev *fimc)
if (fimc) {
v4l2_m2m_release(fimc->m2m.m2m_dev);
video_unregister_device(fimc->m2m.vfd);
- video_device_release(fimc->m2m.vfd);
+
v4l2_device_unregister(&fimc->m2m.v4l2_dev);
}
}
@@ -1399,25 +1379,15 @@ static int fimc_probe(struct platform_device *pdev)
goto err_clk;
}
- fimc->work_queue = create_workqueue(dev_name(&fimc->pdev->dev));
- if (!fimc->work_queue) {
- ret = -ENOMEM;
- goto err_irq;
- }
-
ret = fimc_register_m2m_device(fimc);
if (ret)
- goto err_wq;
-
- fimc_hw_en_lastirq(fimc, true);
+ goto err_irq;
dev_dbg(&pdev->dev, "%s(): fimc-%d registered successfully\n",
__func__, fimc->id);
return 0;
-err_wq:
- destroy_workqueue(fimc->work_queue);
err_irq:
free_irq(fimc->irq, fimc);
err_clk:
@@ -1429,7 +1399,7 @@ err_req_region:
kfree(fimc->regs_res);
err_info:
kfree(fimc);
- dev_err(&pdev->dev, "failed to install\n");
+
return ret;
}
@@ -1438,10 +1408,7 @@ static int __devexit fimc_remove(struct platform_device *pdev)
struct fimc_dev *fimc =
(struct fimc_dev *)platform_get_drvdata(pdev);
- v4l2_info(&fimc->m2m.v4l2_dev, "Removing %s\n", pdev->name);
-
free_irq(fimc->irq, fimc);
-
fimc_hw_reset(fimc);
fimc_unregister_m2m_device(fimc);
@@ -1450,6 +1417,8 @@ static int __devexit fimc_remove(struct platform_device *pdev)
release_resource(fimc->regs_res);
kfree(fimc->regs_res);
kfree(fimc);
+
+ dev_info(&pdev->dev, "%s driver unloaded\n", pdev->name);
return 0;
}
@@ -1484,7 +1453,7 @@ static struct samsung_fimc_variant fimc01_variant_s5pv210 = {
.has_inp_rot = 1,
.has_out_rot = 1,
.min_inp_pixsize = 16,
- .min_out_pixsize = 32,
+ .min_out_pixsize = 16,
.scaler_en_w = 4224,
.scaler_dis_w = 8192,
@@ -1497,7 +1466,7 @@ static struct samsung_fimc_variant fimc01_variant_s5pv210 = {
static struct samsung_fimc_variant fimc2_variant_s5pv210 = {
.pix_hoff = 1,
.min_inp_pixsize = 16,
- .min_out_pixsize = 32,
+ .min_out_pixsize = 16,
.scaler_en_w = 1920,
.scaler_dis_w = 8192,
@@ -1547,20 +1516,12 @@ static struct platform_driver fimc_driver = {
}
};
-static char banner[] __initdata = KERN_INFO
- "S5PC Camera Interface V4L2 Driver, (c) 2010 Samsung Electronics\n";
-
static int __init fimc_init(void)
{
- u32 ret;
- printk(banner);
-
- ret = platform_driver_register(&fimc_driver);
- if (ret) {
- printk(KERN_ERR "FIMC platform driver register failed\n");
- return -1;
- }
- return 0;
+ int ret = platform_driver_register(&fimc_driver);
+ if (ret)
+ err("platform_driver_register failed: %d\n", ret);
+ return ret;
}
static void __exit fimc_exit(void)
diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h
index 6b3e0cd..5aeb3ef 100644
--- a/drivers/media/video/s5p-fimc/fimc-core.h
+++ b/drivers/media/video/s5p-fimc/fimc-core.h
@@ -34,6 +34,7 @@
#define FIMC_MAX_OUT_BUFS 4
#define SCALER_MAX_HRATIO 64
#define SCALER_MAX_VRATIO 64
+#define DMA_MIN_SIZE 8
enum {
ST_IDLE,
@@ -54,21 +55,21 @@ enum fimc_datapath {
};
enum fimc_color_fmt {
- S5P_FIMC_RGB565,
+ S5P_FIMC_RGB565 = 0x10,
S5P_FIMC_RGB666,
S5P_FIMC_RGB888,
- S5P_FIMC_YCBCR420,
+ S5P_FIMC_RGB30_LOCAL,
+ S5P_FIMC_YCBCR420 = 0x20,
S5P_FIMC_YCBCR422,
S5P_FIMC_YCBYCR422,
S5P_FIMC_YCRYCB422,
S5P_FIMC_CBYCRY422,
S5P_FIMC_CRYCBY422,
- S5P_FIMC_RGB30_LOCAL,
S5P_FIMC_YCBCR444_LOCAL,
- S5P_FIMC_MAX_COLOR = S5P_FIMC_YCBCR444_LOCAL,
- S5P_FIMC_COLOR_MASK = 0x0F,
};
+#define fimc_fmt_is_rgb(x) ((x) & 0x10)
+
/* Y/Cb/Cr components order at DMA output for 1 plane YCbCr 4:2:2 formats. */
#define S5P_FIMC_OUT_CRYCBY S5P_CIOCTRL_ORDER422_CRYCBY
#define S5P_FIMC_OUT_CBYCRY S5P_CIOCTRL_ORDER422_YCRYCB
@@ -93,11 +94,13 @@ enum fimc_color_fmt {
#define S5P_FIMC_EFFECT_SIKHOUETTE S5P_CIIMGEFF_FIN_SILHOUETTE
/* The hardware context state. */
-#define FIMC_PARAMS (1 << 0)
-#define FIMC_SRC_ADDR (1 << 1)
-#define FIMC_DST_ADDR (1 << 2)
-#define FIMC_SRC_FMT (1 << 3)
-#define FIMC_DST_FMT (1 << 4)
+#define FIMC_PARAMS (1 << 0)
+#define FIMC_SRC_ADDR (1 << 1)
+#define FIMC_DST_ADDR (1 << 2)
+#define FIMC_SRC_FMT (1 << 3)
+#define FIMC_DST_FMT (1 << 4)
+#define FIMC_CTX_M2M (1 << 5)
+#define FIMC_CTX_CAP (1 << 6)
/* Image conversion flags */
#define FIMC_IN_DMA_ACCESS_TILED (1 << 0)
@@ -106,7 +109,9 @@ enum fimc_color_fmt {
#define FIMC_OUT_DMA_ACCESS_LINEAR (0 << 1)
#define FIMC_SCAN_MODE_PROGRESSIVE (0 << 2)
#define FIMC_SCAN_MODE_INTERLACED (1 << 2)
-/* YCbCr data dynamic range for RGB-YUV color conversion. Y/Cb/Cr: (0 ~ 255) */
+/*
+ * YCbCr data dynamic range for RGB-YUV color conversion.
+ * Y/Cb/Cr: (0 ~ 255) */
#define FIMC_COLOR_RANGE_WIDE (0 << 3)
/* Y (16 ~ 235), Cb/Cr (16 ~ 240) */
#define FIMC_COLOR_RANGE_NARROW (1 << 3)
@@ -167,37 +172,37 @@ struct fimc_effect {
/**
* struct fimc_scaler - the configuration data for FIMC inetrnal scaler
*
- * @enabled: the flag set when the scaler is used
+ * @scaleup_h: flag indicating scaling up horizontally
+ * @scaleup_v: flag indicating scaling up vertically
+ * @copy_mode: flag indicating transparent DMA transfer (no scaling
+ * and color format conversion)
+ * @enabled: flag indicating if the scaler is used
* @hfactor: horizontal shift factor
* @vfactor: vertical shift factor
* @pre_hratio: horizontal ratio of the prescaler
* @pre_vratio: vertical ratio of the prescaler
* @pre_dst_width: the prescaler's destination width
* @pre_dst_height: the prescaler's destination height
- * @scaleup_h: flag indicating scaling up horizontally
- * @scaleup_v: flag indicating scaling up vertically
* @main_hratio: the main scaler's horizontal ratio
* @main_vratio: the main scaler's vertical ratio
- * @real_width: source width - offset
- * @real_height: source height - offset
- * @copy_mode: flag set if one-to-one mode is used, i.e. no scaling
- * and color format conversion
+ * @real_width: source pixel (width - offset)
+ * @real_height: source pixel (height - offset)
*/
struct fimc_scaler {
- u32 enabled;
+ int scaleup_h:1;
+ int scaleup_v:1;
+ int copy_mode:1;
+ int enabled:1;
u32 hfactor;
u32 vfactor;
u32 pre_hratio;
u32 pre_vratio;
u32 pre_dst_width;
u32 pre_dst_height;
- u32 scaleup_h;
- u32 scaleup_v;
u32 main_hratio;
u32 main_vratio;
u32 real_width;
u32 real_height;
- u32 copy_mode;
};
/**
@@ -222,8 +227,7 @@ struct fimc_vid_buffer {
};
/**
- * struct fimc_frame - input/output frame format properties
- *
+ * struct fimc_frame - source/target frame properties
* @f_width: image full width (virtual screen size)
* @f_height: image full height (virtual screen size)
* @o_width: original image width as set by S_FMT
@@ -279,10 +283,10 @@ struct fimc_m2m_device {
* @min_out_pixsize: minimum output pixel size
* @scaler_en_w: maximum input pixel width when the scaler is enabled
* @scaler_dis_w: maximum input pixel width when the scaler is disabled
- * @in_rot_en_h: maximum input width when the input rotator is used
- * @in_rot_dis_w: maximum input width when the input rotator is used
- * @out_rot_en_w: maximum output width for the output rotator enabled
- * @out_rot_dis_w: maximum output width for the output rotator enabled
+ * @in_rot_en_h: maximum input width when the input rotator is enabled
+ * @in_rot_dis_w: maximum input width when the input rotator is disabled
+ * @out_rot_en_w: maximum target width when the output rotator enabled
+ * @out_rot_dis_w: maximum target width when the output rotator disnabled
*/
struct samsung_fimc_variant {
unsigned int pix_hoff:1;
@@ -300,7 +304,7 @@ struct samsung_fimc_variant {
};
/**
- * struct samsung_fimc_driverdata - per-device type driver data for init time.
+ * struct samsung_fimc_driverdata - per device type driver data for init time.
*
* @variant: the variant information for this driver.
* @dev_cnt: number of fimc sub-devices available in SoC
@@ -313,7 +317,7 @@ struct samsung_fimc_driverdata {
struct fimc_ctx;
/**
- * struct fimc_subdev - abstraction for a FIMC entity
+ * struct fimc_dev - abstraction for FIMC entity
*
* @slock: the spinlock protecting this data structure
* @lock: the mutex protecting this data structure
@@ -323,7 +327,7 @@ struct fimc_ctx;
* @regs: the mapped hardware registers
* @regs_res: the resource claimed for IO registers
* @irq: interrupt number of the FIMC subdevice
- * @irqlock: spinlock protecting videbuffer queue
+ * @irqlock: spinlock protecting videobuffer queue
* @m2m: memory-to-memory V4L2 device information
* @state: the FIMC device state flags
*/
@@ -338,7 +342,6 @@ struct fimc_dev {
struct resource *regs_res;
int irq;
spinlock_t irqlock;
- struct workqueue_struct *work_queue;
struct fimc_m2m_device m2m;
unsigned long state;
};
@@ -359,7 +362,7 @@ struct fimc_dev {
* @effect: image effect
* @rotation: image clockwise rotation in degrees
* @flip: image flip mode
- * @flags: an additional flags for image conversion
+ * @flags: additional flags for image conversion
* @state: flags to keep track of user configuration
* @fimc_dev: the FIMC device this context applies to
* @m2m_ctx: memory-to-memory device context
@@ -397,18 +400,24 @@ static inline void fimc_hw_clear_irq(struct fimc_dev *dev)
writel(cfg, dev->regs + S5P_CIGCTRL);
}
-static inline void fimc_hw_start_scaler(struct fimc_dev *dev)
+static inline void fimc_hw_enable_scaler(struct fimc_dev *dev, bool on)
{
u32 cfg = readl(dev->regs + S5P_CISCCTRL);
- cfg |= S5P_CISCCTRL_SCALERSTART;
+ if (on)
+ cfg |= S5P_CISCCTRL_SCALERSTART;
+ else
+ cfg &= ~S5P_CISCCTRL_SCALERSTART;
writel(cfg, dev->regs + S5P_CISCCTRL);
}
-static inline void fimc_hw_stop_scaler(struct fimc_dev *dev)
+static inline void fimc_hw_activate_input_dma(struct fimc_dev *dev, bool on)
{
- u32 cfg = readl(dev->regs + S5P_CISCCTRL);
- cfg &= ~S5P_CISCCTRL_SCALERSTART;
- writel(cfg, dev->regs + S5P_CISCCTRL);
+ u32 cfg = readl(dev->regs + S5P_MSCTRL);
+ if (on)
+ cfg |= S5P_MSCTRL_ENVID;
+ else
+ cfg &= ~S5P_MSCTRL_ENVID;
+ writel(cfg, dev->regs + S5P_MSCTRL);
}
static inline void fimc_hw_dis_capture(struct fimc_dev *dev)
@@ -418,22 +427,8 @@ static inline void fimc_hw_dis_capture(struct fimc_dev *dev)
writel(cfg, dev->regs + S5P_CIIMGCPT);
}
-static inline void fimc_hw_start_in_dma(struct fimc_dev *dev)
-{
- u32 cfg = readl(dev->regs + S5P_MSCTRL);
- cfg |= S5P_MSCTRL_ENVID;
- writel(cfg, dev->regs + S5P_MSCTRL);
-}
-
-static inline void fimc_hw_stop_in_dma(struct fimc_dev *dev)
-{
- u32 cfg = readl(dev->regs + S5P_MSCTRL);
- cfg &= ~S5P_MSCTRL_ENVID;
- writel(cfg, dev->regs + S5P_MSCTRL);
-}
-
-static inline struct fimc_frame *ctx_m2m_get_frame(struct fimc_ctx *ctx,
- enum v4l2_buf_type type)
+static inline struct fimc_frame *ctx_get_frame(struct fimc_ctx *ctx,
+ enum v4l2_buf_type type)
{
struct fimc_frame *frame;
@@ -452,20 +447,35 @@ static inline struct fimc_frame *ctx_m2m_get_frame(struct fimc_ctx *ctx,
/* -----------------------------------------------------*/
/* fimc-reg.c */
-void fimc_hw_reset(struct fimc_dev *dev);
+void fimc_hw_reset(struct fimc_dev *fimc);
void fimc_hw_set_rotation(struct fimc_ctx *ctx);
void fimc_hw_set_target_format(struct fimc_ctx *ctx);
void fimc_hw_set_out_dma(struct fimc_ctx *ctx);
-void fimc_hw_en_lastirq(struct fimc_dev *dev, int enable);
-void fimc_hw_en_irq(struct fimc_dev *dev, int enable);
-void fimc_hw_set_prescaler(struct fimc_ctx *ctx);
+void fimc_hw_en_lastirq(struct fimc_dev *fimc, int enable);
+void fimc_hw_en_irq(struct fimc_dev *fimc, int enable);
void fimc_hw_set_scaler(struct fimc_ctx *ctx);
void fimc_hw_en_capture(struct fimc_ctx *ctx);
void fimc_hw_set_effect(struct fimc_ctx *ctx);
void fimc_hw_set_in_dma(struct fimc_ctx *ctx);
void fimc_hw_set_input_path(struct fimc_ctx *ctx);
void fimc_hw_set_output_path(struct fimc_ctx *ctx);
-void fimc_hw_set_input_addr(struct fimc_dev *dev, struct fimc_addr *paddr);
-void fimc_hw_set_output_addr(struct fimc_dev *dev, struct fimc_addr *paddr);
+void fimc_hw_set_input_addr(struct fimc_dev *fimc, struct fimc_addr *paddr);
+void fimc_hw_set_output_addr(struct fimc_dev *fimc, struct fimc_addr *paddr,
+ int index);
+
+/* Locking: the caller holds fimc->slock */
+static inline void fimc_activate_capture(struct fimc_ctx *ctx)
+{
+ fimc_hw_enable_scaler(ctx->fimc_dev, ctx->scaler.enabled);
+ fimc_hw_en_capture(ctx);
+}
+
+static inline void fimc_deactivate_capture(struct fimc_dev *fimc)
+{
+ fimc_hw_en_lastirq(fimc, true);
+ fimc_hw_dis_capture(fimc);
+ fimc_hw_enable_scaler(fimc, false);
+ fimc_hw_en_lastirq(fimc, false);
+}
#endif /* FIMC_CORE_H_ */
diff --git a/drivers/media/video/s5p-fimc/fimc-reg.c b/drivers/media/video/s5p-fimc/fimc-reg.c
index 70f29c5..94e98d4 100644
--- a/drivers/media/video/s5p-fimc/fimc-reg.c
+++ b/drivers/media/video/s5p-fimc/fimc-reg.c
@@ -29,7 +29,7 @@ void fimc_hw_reset(struct fimc_dev *dev)
cfg = readl(dev->regs + S5P_CIGCTRL);
cfg |= (S5P_CIGCTRL_SWRST | S5P_CIGCTRL_IRQ_LEVEL);
writel(cfg, dev->regs + S5P_CIGCTRL);
- msleep(1);
+ udelay(1000);
cfg = readl(dev->regs + S5P_CIGCTRL);
cfg &= ~S5P_CIGCTRL_SWRST;
@@ -247,21 +247,20 @@ void fimc_hw_en_lastirq(struct fimc_dev *dev, int enable)
spin_unlock_irqrestore(&dev->slock, flags);
}
-void fimc_hw_set_prescaler(struct fimc_ctx *ctx)
+static void fimc_hw_set_prescaler(struct fimc_ctx *ctx)
{
struct fimc_dev *dev = ctx->fimc_dev;
struct fimc_scaler *sc = &ctx->scaler;
- u32 cfg = 0, shfactor;
+ u32 cfg, shfactor;
shfactor = 10 - (sc->hfactor + sc->vfactor);
- cfg |= S5P_CISCPRERATIO_SHFACTOR(shfactor);
+ cfg = S5P_CISCPRERATIO_SHFACTOR(shfactor);
cfg |= S5P_CISCPRERATIO_HOR(sc->pre_hratio);
cfg |= S5P_CISCPRERATIO_VER(sc->pre_vratio);
writel(cfg, dev->regs + S5P_CISCPRERATIO);
- cfg = 0;
- cfg |= S5P_CISCPREDST_WIDTH(sc->pre_dst_width);
+ cfg = S5P_CISCPREDST_WIDTH(sc->pre_dst_width);
cfg |= S5P_CISCPREDST_HEIGHT(sc->pre_dst_height);
writel(cfg, dev->regs + S5P_CISCPREDST);
}
@@ -274,6 +273,8 @@ void fimc_hw_set_scaler(struct fimc_ctx *ctx)
struct fimc_frame *dst_frame = &ctx->d_frame;
u32 cfg = 0;
+ fimc_hw_set_prescaler(ctx);
+
if (!(ctx->flags & FIMC_COLOR_RANGE_NARROW))
cfg |= (S5P_CISCCTRL_CSCR2Y_WIDE | S5P_CISCCTRL_CSCY2R_WIDE);
@@ -364,7 +365,7 @@ static void fimc_hw_set_in_dma_size(struct fimc_ctx *ctx)
u32 cfg_r = 0;
if (FIMC_LCDFIFO == ctx->out_path)
- cfg_r |= S5P_CIREAL_ISIZE_AUTOLOAD_EN;
+ cfg_r |= S5P_CIREAL_ISIZE_AUTOLOAD_EN;
cfg_o |= S5P_ORIG_SIZE_HOR(frame->f_width);
cfg_o |= S5P_ORIG_SIZE_VER(frame->f_height);
@@ -380,27 +381,25 @@ void fimc_hw_set_in_dma(struct fimc_ctx *ctx)
struct fimc_dev *dev = ctx->fimc_dev;
struct fimc_frame *frame = &ctx->s_frame;
struct fimc_dma_offset *offset = &frame->dma_offset;
- u32 cfg = 0;
+ u32 cfg;
/* Set the pixel offsets. */
- cfg |= S5P_CIO_OFFS_HOR(offset->y_h);
+ cfg = S5P_CIO_OFFS_HOR(offset->y_h);
cfg |= S5P_CIO_OFFS_VER(offset->y_v);
writel(cfg, dev->regs + S5P_CIIYOFF);
- cfg = 0;
- cfg |= S5P_CIO_OFFS_HOR(offset->cb_h);
+ cfg = S5P_CIO_OFFS_HOR(offset->cb_h);
cfg |= S5P_CIO_OFFS_VER(offset->cb_v);
writel(cfg, dev->regs + S5P_CIICBOFF);
- cfg = 0;
- cfg |= S5P_CIO_OFFS_HOR(offset->cr_h);
+ cfg = S5P_CIO_OFFS_HOR(offset->cr_h);
cfg |= S5P_CIO_OFFS_VER(offset->cr_v);
writel(cfg, dev->regs + S5P_CIICROFF);
/* Input original and real size. */
fimc_hw_set_in_dma_size(ctx);
- /* Autoload is used currently only in FIFO mode. */
+ /* Use DMA autoload only in FIFO mode. */
fimc_hw_en_autoload(dev, ctx->out_path == FIMC_LCDFIFO);
/* Set the input DMA to process single frame only. */
@@ -501,9 +500,7 @@ void fimc_hw_set_output_path(struct fimc_ctx *ctx)
void fimc_hw_set_input_addr(struct fimc_dev *dev, struct fimc_addr *paddr)
{
- u32 cfg = 0;
-
- cfg = readl(dev->regs + S5P_CIREAL_ISIZE);
+ u32 cfg = readl(dev->regs + S5P_CIREAL_ISIZE);
cfg |= S5P_CIREAL_ISIZE_ADDR_CH_DIS;
writel(cfg, dev->regs + S5P_CIREAL_ISIZE);
@@ -515,13 +512,15 @@ void fimc_hw_set_input_addr(struct fimc_dev *dev, struct fimc_addr *paddr)
writel(cfg, dev->regs + S5P_CIREAL_ISIZE);
}
-void fimc_hw_set_output_addr(struct fimc_dev *dev, struct fimc_addr *paddr)
+void fimc_hw_set_output_addr(struct fimc_dev *dev,
+ struct fimc_addr *paddr, int index)
{
- int i;
- /* Set all the output register sets to point to single video buffer. */
- for (i = 0; i < FIMC_MAX_OUT_BUFS; i++) {
+ int i = (index == -1) ? 0 : index;
+ do {
writel(paddr->y, dev->regs + S5P_CIOYSA(i));
writel(paddr->cb, dev->regs + S5P_CIOCBSA(i));
writel(paddr->cr, dev->regs + S5P_CIOCRSA(i));
- }
+ dbg("dst_buf[%d]: 0x%X, cb: 0x%X, cr: 0x%X",
+ i, paddr->y, paddr->cb, paddr->cr);
+ } while (index == -1 && ++i < FIMC_MAX_OUT_BUFS);
}
--
1.7.3.1
^ permalink raw reply related
* [PATCH 2/5 v4] V4L/DVB: s5p-fimc: mem2mem driver refactoring and cleanup
From: Sylwester Nawrocki @ 2010-10-08 8:50 UTC (permalink / raw)
To: linux-media, linux-arm-kernel, linux-samsung-soc
Cc: m.szyprowski, kyungmin.park, s.nawrocki
In-Reply-To: <1286527837-4980-1-git-send-email-s.nawrocki@samsung.com>
Register access functions refactored for camera capture interface
control. Removed the workqueue since it was only useful for FIFO
output mode which is not supported at this time.
Fixed errors on module unload. Comments and whitespace cleanup.
Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
drivers/media/video/s5p-fimc/fimc-core.c | 151 +++++++++++-------------------
drivers/media/video/s5p-fimc/fimc-core.h | 132 ++++++++++++++------------
drivers/media/video/s5p-fimc/fimc-reg.c | 43 ++++-----
3 files changed, 148 insertions(+), 178 deletions(-)
diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c
index c56029e..fccab13 100644
--- a/drivers/media/video/s5p-fimc/fimc-core.c
+++ b/drivers/media/video/s5p-fimc/fimc-core.c
@@ -117,7 +117,7 @@ static struct fimc_fmt fimc_formats[] = {
.buff_cnt = 1,
.planes_cnt = 2
}
- };
+};
static struct v4l2_queryctrl fimc_ctrls[] = {
{
@@ -127,16 +127,14 @@ static struct v4l2_queryctrl fimc_ctrls[] = {
.minimum = 0,
.maximum = 1,
.default_value = 0,
- },
- {
+ }, {
.id = V4L2_CID_VFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "Vertical flip",
.minimum = 0,
.maximum = 1,
.default_value = 0,
- },
- {
+ }, {
.id = V4L2_CID_ROTATE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Rotation (CCW)",
@@ -181,28 +179,23 @@ static int fimc_check_scaler_ratio(struct v4l2_rect *r, struct fimc_frame *f)
static int fimc_get_scaler_factor(u32 src, u32 tar, u32 *ratio, u32 *shift)
{
- if (src >= tar * 64) {
+ u32 sh = 6;
+
+ if (src >= 64 * tar)
return -EINVAL;
- } else if (src >= tar * 32) {
- *ratio = 32;
- *shift = 5;
- } else if (src >= tar * 16) {
- *ratio = 16;
- *shift = 4;
- } else if (src >= tar * 8) {
- *ratio = 8;
- *shift = 3;
- } else if (src >= tar * 4) {
- *ratio = 4;
- *shift = 2;
- } else if (src >= tar * 2) {
- *ratio = 2;
- *shift = 1;
- } else {
- *ratio = 1;
- *shift = 0;
+
+ while (sh--) {
+ u32 tmp = 1 << sh;
+ if (src >= tar * tmp) {
+ *shift = sh, *ratio = tmp;
+ return 0;
+ }
}
+ *shift = 0, *ratio = 1;
+
+ dbg("s: %d, t: %d, shift: %d, ratio: %d",
+ src, tar, *shift, *ratio);
return 0;
}
@@ -265,8 +258,8 @@ static int fimc_set_scaler_info(struct fimc_ctx *ctx)
static irqreturn_t fimc_isr(int irq, void *priv)
{
struct fimc_vid_buffer *src_buf, *dst_buf;
- struct fimc_dev *fimc = (struct fimc_dev *)priv;
struct fimc_ctx *ctx;
+ struct fimc_dev *fimc = priv;
BUG_ON(!fimc);
fimc_hw_clear_irq(fimc);
@@ -281,7 +274,7 @@ static irqreturn_t fimc_isr(int irq, void *priv)
dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
if (src_buf && dst_buf) {
spin_lock(&fimc->irqlock);
- src_buf->vb.state = dst_buf->vb.state = VIDEOBUF_DONE;
+ src_buf->vb.state = dst_buf->vb.state = VIDEOBUF_DONE;
wake_up(&src_buf->vb.done);
wake_up(&dst_buf->vb.done);
spin_unlock(&fimc->irqlock);
@@ -295,20 +288,13 @@ isr_unlock:
}
/* The color format (planes_cnt, buff_cnt) must be already configured. */
-static int fimc_prepare_addr(struct fimc_ctx *ctx,
- struct fimc_vid_buffer *buf, enum v4l2_buf_type type)
+int fimc_prepare_addr(struct fimc_ctx *ctx, struct fimc_vid_buffer *buf,
+ struct fimc_frame *frame, struct fimc_addr *paddr)
{
- struct fimc_frame *frame;
- struct fimc_addr *paddr;
- u32 pix_size;
int ret = 0;
+ u32 pix_size;
- frame = ctx_m2m_get_frame(ctx, type);
- if (IS_ERR(frame))
- return PTR_ERR(frame);
- paddr = &frame->paddr;
-
- if (!buf)
+ if (buf == NULL || frame == NULL)
return -EINVAL;
pix_size = frame->width * frame->height;
@@ -344,8 +330,8 @@ static int fimc_prepare_addr(struct fimc_ctx *ctx,
}
}
- dbg("PHYS_ADDR: type= %d, y= 0x%X cb= 0x%X cr= 0x%X ret= %d",
- type, paddr->y, paddr->cb, paddr->cr, ret);
+ dbg("PHYS_ADDR: y= 0x%X cb= 0x%X cr= 0x%X ret= %d",
+ paddr->y, paddr->cb, paddr->cr, ret);
return ret;
}
@@ -466,16 +452,14 @@ static int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags)
if (flags & FIMC_SRC_ADDR) {
buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
- ret = fimc_prepare_addr(ctx, buf,
- V4L2_BUF_TYPE_VIDEO_OUTPUT);
+ ret = fimc_prepare_addr(ctx, buf, s_frame, &s_frame->paddr);
if (ret)
return ret;
}
if (flags & FIMC_DST_ADDR) {
buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
- ret = fimc_prepare_addr(ctx, buf,
- V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ ret = fimc_prepare_addr(ctx, buf, d_frame, &d_frame->paddr);
}
return ret;
@@ -499,12 +483,14 @@ static void fimc_dma_run(void *priv)
ctx->state |= (FIMC_SRC_ADDR | FIMC_DST_ADDR);
ret = fimc_prepare_config(ctx, ctx->state);
if (ret) {
- err("general configuration error");
+ err("Wrong parameters");
goto dma_unlock;
}
-
- if (fimc->m2m.ctx != ctx)
+ /* Reconfigure hardware if the context has changed. */
+ if (fimc->m2m.ctx != ctx) {
ctx->state |= FIMC_PARAMS;
+ fimc->m2m.ctx = ctx;
+ }
fimc_hw_set_input_addr(fimc, &ctx->s_frame.paddr);
@@ -512,10 +498,9 @@ static void fimc_dma_run(void *priv)
fimc_hw_set_input_path(ctx);
fimc_hw_set_in_dma(ctx);
if (fimc_set_scaler_info(ctx)) {
- err("scaler configuration error");
+ err("Scaler setup error");
goto dma_unlock;
}
- fimc_hw_set_prescaler(ctx);
fimc_hw_set_scaler(ctx);
fimc_hw_set_target_format(ctx);
fimc_hw_set_rotation(ctx);
@@ -524,19 +509,15 @@ static void fimc_dma_run(void *priv)
fimc_hw_set_output_path(ctx);
if (ctx->state & (FIMC_DST_ADDR | FIMC_PARAMS))
- fimc_hw_set_output_addr(fimc, &ctx->d_frame.paddr);
+ fimc_hw_set_output_addr(fimc, &ctx->d_frame.paddr, -1);
if (ctx->state & FIMC_PARAMS)
fimc_hw_set_out_dma(ctx);
- if (ctx->scaler.enabled)
- fimc_hw_start_scaler(fimc);
- fimc_hw_en_capture(ctx);
-
ctx->state = 0;
- fimc_hw_start_in_dma(fimc);
+ fimc_activate_capture(ctx);
- fimc->m2m.ctx = ctx;
+ fimc_hw_activate_input_dma(fimc, true);
dma_unlock:
spin_unlock_irqrestore(&ctx->slock, flags);
@@ -560,7 +541,7 @@ static int fimc_buf_setup(struct videobuf_queue *vq, unsigned int *count,
struct fimc_ctx *ctx = vq->priv_data;
struct fimc_frame *frame;
- frame = ctx_m2m_get_frame(ctx, vq->type);
+ frame = ctx_get_frame(ctx, vq->type);
if (IS_ERR(frame))
return PTR_ERR(frame);
@@ -578,7 +559,7 @@ static int fimc_buf_prepare(struct videobuf_queue *vq,
struct fimc_frame *frame;
int ret;
- frame = ctx_m2m_get_frame(ctx, vq->type);
+ frame = ctx_get_frame(ctx, vq->type);
if (IS_ERR(frame))
return PTR_ERR(frame);
@@ -663,7 +644,7 @@ static int fimc_m2m_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
struct fimc_ctx *ctx = priv;
struct fimc_frame *frame;
- frame = ctx_m2m_get_frame(ctx, f->type);
+ frame = ctx_get_frame(ctx, f->type);
if (IS_ERR(frame))
return PTR_ERR(frame);
@@ -999,7 +980,7 @@ static int fimc_m2m_cropcap(struct file *file, void *fh,
struct fimc_frame *frame;
struct fimc_ctx *ctx = fh;
- frame = ctx_m2m_get_frame(ctx, cr->type);
+ frame = ctx_get_frame(ctx, cr->type);
if (IS_ERR(frame))
return PTR_ERR(frame);
@@ -1019,7 +1000,7 @@ static int fimc_m2m_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
struct fimc_frame *frame;
struct fimc_ctx *ctx = file->private_data;
- frame = ctx_m2m_get_frame(ctx, cr->type);
+ frame = ctx_get_frame(ctx, cr->type);
if (IS_ERR(frame))
return PTR_ERR(frame);
@@ -1052,7 +1033,7 @@ static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr)
return -EINVAL;
}
- f = ctx_m2m_get_frame(ctx, cr->type);
+ f = ctx_get_frame(ctx, cr->type);
if (IS_ERR(f))
return PTR_ERR(f);
@@ -1136,7 +1117,7 @@ static void queue_init(void *priv, struct videobuf_queue *vq,
struct fimc_dev *fimc = ctx->fimc_dev;
videobuf_queue_dma_contig_init(vq, &fimc_qops,
- fimc->m2m.v4l2_dev.dev,
+ &fimc->pdev->dev,
&fimc->irqlock, type, V4L2_FIELD_NONE,
sizeof(struct fimc_vid_buffer), priv, NULL);
}
@@ -1159,13 +1140,12 @@ static int fimc_m2m_open(struct file *file)
file->private_data = ctx;
ctx->fimc_dev = fimc;
- /* default format */
+ /* Default color format */
ctx->s_frame.fmt = &fimc_formats[0];
ctx->d_frame.fmt = &fimc_formats[0];
/* per user process device context initialization */
ctx->state = 0;
ctx->flags = 0;
- ctx->effect.type = S5P_FIMC_EFFECT_ORIGINAL;
ctx->in_path = FIMC_DMA;
ctx->out_path = FIMC_DMA;
spin_lock_init(&ctx->slock);
@@ -1241,7 +1221,7 @@ static int fimc_register_m2m_device(struct fimc_dev *fimc)
ret = v4l2_device_register(&pdev->dev, v4l2_dev);
if (ret)
- return ret;;
+ goto err_m2m_r1;
vfd = video_device_alloc();
if (!vfd) {
@@ -1293,7 +1273,7 @@ static void fimc_unregister_m2m_device(struct fimc_dev *fimc)
if (fimc) {
v4l2_m2m_release(fimc->m2m.m2m_dev);
video_unregister_device(fimc->m2m.vfd);
- video_device_release(fimc->m2m.vfd);
+
v4l2_device_unregister(&fimc->m2m.v4l2_dev);
}
}
@@ -1399,25 +1379,15 @@ static int fimc_probe(struct platform_device *pdev)
goto err_clk;
}
- fimc->work_queue = create_workqueue(dev_name(&fimc->pdev->dev));
- if (!fimc->work_queue) {
- ret = -ENOMEM;
- goto err_irq;
- }
-
ret = fimc_register_m2m_device(fimc);
if (ret)
- goto err_wq;
-
- fimc_hw_en_lastirq(fimc, true);
+ goto err_irq;
dev_dbg(&pdev->dev, "%s(): fimc-%d registered successfully\n",
__func__, fimc->id);
return 0;
-err_wq:
- destroy_workqueue(fimc->work_queue);
err_irq:
free_irq(fimc->irq, fimc);
err_clk:
@@ -1429,7 +1399,7 @@ err_req_region:
kfree(fimc->regs_res);
err_info:
kfree(fimc);
- dev_err(&pdev->dev, "failed to install\n");
+
return ret;
}
@@ -1438,10 +1408,7 @@ static int __devexit fimc_remove(struct platform_device *pdev)
struct fimc_dev *fimc =
(struct fimc_dev *)platform_get_drvdata(pdev);
- v4l2_info(&fimc->m2m.v4l2_dev, "Removing %s\n", pdev->name);
-
free_irq(fimc->irq, fimc);
-
fimc_hw_reset(fimc);
fimc_unregister_m2m_device(fimc);
@@ -1450,6 +1417,8 @@ static int __devexit fimc_remove(struct platform_device *pdev)
release_resource(fimc->regs_res);
kfree(fimc->regs_res);
kfree(fimc);
+
+ dev_info(&pdev->dev, "%s driver unloaded\n", pdev->name);
return 0;
}
@@ -1484,7 +1453,7 @@ static struct samsung_fimc_variant fimc01_variant_s5pv210 = {
.has_inp_rot = 1,
.has_out_rot = 1,
.min_inp_pixsize = 16,
- .min_out_pixsize = 32,
+ .min_out_pixsize = 16,
.scaler_en_w = 4224,
.scaler_dis_w = 8192,
@@ -1497,7 +1466,7 @@ static struct samsung_fimc_variant fimc01_variant_s5pv210 = {
static struct samsung_fimc_variant fimc2_variant_s5pv210 = {
.pix_hoff = 1,
.min_inp_pixsize = 16,
- .min_out_pixsize = 32,
+ .min_out_pixsize = 16,
.scaler_en_w = 1920,
.scaler_dis_w = 8192,
@@ -1547,20 +1516,12 @@ static struct platform_driver fimc_driver = {
}
};
-static char banner[] __initdata = KERN_INFO
- "S5PC Camera Interface V4L2 Driver, (c) 2010 Samsung Electronics\n";
-
static int __init fimc_init(void)
{
- u32 ret;
- printk(banner);
-
- ret = platform_driver_register(&fimc_driver);
- if (ret) {
- printk(KERN_ERR "FIMC platform driver register failed\n");
- return -1;
- }
- return 0;
+ int ret = platform_driver_register(&fimc_driver);
+ if (ret)
+ err("platform_driver_register failed: %d\n", ret);
+ return ret;
}
static void __exit fimc_exit(void)
diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h
index 6b3e0cd..5aeb3ef 100644
--- a/drivers/media/video/s5p-fimc/fimc-core.h
+++ b/drivers/media/video/s5p-fimc/fimc-core.h
@@ -34,6 +34,7 @@
#define FIMC_MAX_OUT_BUFS 4
#define SCALER_MAX_HRATIO 64
#define SCALER_MAX_VRATIO 64
+#define DMA_MIN_SIZE 8
enum {
ST_IDLE,
@@ -54,21 +55,21 @@ enum fimc_datapath {
};
enum fimc_color_fmt {
- S5P_FIMC_RGB565,
+ S5P_FIMC_RGB565 = 0x10,
S5P_FIMC_RGB666,
S5P_FIMC_RGB888,
- S5P_FIMC_YCBCR420,
+ S5P_FIMC_RGB30_LOCAL,
+ S5P_FIMC_YCBCR420 = 0x20,
S5P_FIMC_YCBCR422,
S5P_FIMC_YCBYCR422,
S5P_FIMC_YCRYCB422,
S5P_FIMC_CBYCRY422,
S5P_FIMC_CRYCBY422,
- S5P_FIMC_RGB30_LOCAL,
S5P_FIMC_YCBCR444_LOCAL,
- S5P_FIMC_MAX_COLOR = S5P_FIMC_YCBCR444_LOCAL,
- S5P_FIMC_COLOR_MASK = 0x0F,
};
+#define fimc_fmt_is_rgb(x) ((x) & 0x10)
+
/* Y/Cb/Cr components order at DMA output for 1 plane YCbCr 4:2:2 formats. */
#define S5P_FIMC_OUT_CRYCBY S5P_CIOCTRL_ORDER422_CRYCBY
#define S5P_FIMC_OUT_CBYCRY S5P_CIOCTRL_ORDER422_YCRYCB
@@ -93,11 +94,13 @@ enum fimc_color_fmt {
#define S5P_FIMC_EFFECT_SIKHOUETTE S5P_CIIMGEFF_FIN_SILHOUETTE
/* The hardware context state. */
-#define FIMC_PARAMS (1 << 0)
-#define FIMC_SRC_ADDR (1 << 1)
-#define FIMC_DST_ADDR (1 << 2)
-#define FIMC_SRC_FMT (1 << 3)
-#define FIMC_DST_FMT (1 << 4)
+#define FIMC_PARAMS (1 << 0)
+#define FIMC_SRC_ADDR (1 << 1)
+#define FIMC_DST_ADDR (1 << 2)
+#define FIMC_SRC_FMT (1 << 3)
+#define FIMC_DST_FMT (1 << 4)
+#define FIMC_CTX_M2M (1 << 5)
+#define FIMC_CTX_CAP (1 << 6)
/* Image conversion flags */
#define FIMC_IN_DMA_ACCESS_TILED (1 << 0)
@@ -106,7 +109,9 @@ enum fimc_color_fmt {
#define FIMC_OUT_DMA_ACCESS_LINEAR (0 << 1)
#define FIMC_SCAN_MODE_PROGRESSIVE (0 << 2)
#define FIMC_SCAN_MODE_INTERLACED (1 << 2)
-/* YCbCr data dynamic range for RGB-YUV color conversion. Y/Cb/Cr: (0 ~ 255) */
+/*
+ * YCbCr data dynamic range for RGB-YUV color conversion.
+ * Y/Cb/Cr: (0 ~ 255) */
#define FIMC_COLOR_RANGE_WIDE (0 << 3)
/* Y (16 ~ 235), Cb/Cr (16 ~ 240) */
#define FIMC_COLOR_RANGE_NARROW (1 << 3)
@@ -167,37 +172,37 @@ struct fimc_effect {
/**
* struct fimc_scaler - the configuration data for FIMC inetrnal scaler
*
- * @enabled: the flag set when the scaler is used
+ * @scaleup_h: flag indicating scaling up horizontally
+ * @scaleup_v: flag indicating scaling up vertically
+ * @copy_mode: flag indicating transparent DMA transfer (no scaling
+ * and color format conversion)
+ * @enabled: flag indicating if the scaler is used
* @hfactor: horizontal shift factor
* @vfactor: vertical shift factor
* @pre_hratio: horizontal ratio of the prescaler
* @pre_vratio: vertical ratio of the prescaler
* @pre_dst_width: the prescaler's destination width
* @pre_dst_height: the prescaler's destination height
- * @scaleup_h: flag indicating scaling up horizontally
- * @scaleup_v: flag indicating scaling up vertically
* @main_hratio: the main scaler's horizontal ratio
* @main_vratio: the main scaler's vertical ratio
- * @real_width: source width - offset
- * @real_height: source height - offset
- * @copy_mode: flag set if one-to-one mode is used, i.e. no scaling
- * and color format conversion
+ * @real_width: source pixel (width - offset)
+ * @real_height: source pixel (height - offset)
*/
struct fimc_scaler {
- u32 enabled;
+ int scaleup_h:1;
+ int scaleup_v:1;
+ int copy_mode:1;
+ int enabled:1;
u32 hfactor;
u32 vfactor;
u32 pre_hratio;
u32 pre_vratio;
u32 pre_dst_width;
u32 pre_dst_height;
- u32 scaleup_h;
- u32 scaleup_v;
u32 main_hratio;
u32 main_vratio;
u32 real_width;
u32 real_height;
- u32 copy_mode;
};
/**
@@ -222,8 +227,7 @@ struct fimc_vid_buffer {
};
/**
- * struct fimc_frame - input/output frame format properties
- *
+ * struct fimc_frame - source/target frame properties
* @f_width: image full width (virtual screen size)
* @f_height: image full height (virtual screen size)
* @o_width: original image width as set by S_FMT
@@ -279,10 +283,10 @@ struct fimc_m2m_device {
* @min_out_pixsize: minimum output pixel size
* @scaler_en_w: maximum input pixel width when the scaler is enabled
* @scaler_dis_w: maximum input pixel width when the scaler is disabled
- * @in_rot_en_h: maximum input width when the input rotator is used
- * @in_rot_dis_w: maximum input width when the input rotator is used
- * @out_rot_en_w: maximum output width for the output rotator enabled
- * @out_rot_dis_w: maximum output width for the output rotator enabled
+ * @in_rot_en_h: maximum input width when the input rotator is enabled
+ * @in_rot_dis_w: maximum input width when the input rotator is disabled
+ * @out_rot_en_w: maximum target width when the output rotator enabled
+ * @out_rot_dis_w: maximum target width when the output rotator disnabled
*/
struct samsung_fimc_variant {
unsigned int pix_hoff:1;
@@ -300,7 +304,7 @@ struct samsung_fimc_variant {
};
/**
- * struct samsung_fimc_driverdata - per-device type driver data for init time.
+ * struct samsung_fimc_driverdata - per device type driver data for init time.
*
* @variant: the variant information for this driver.
* @dev_cnt: number of fimc sub-devices available in SoC
@@ -313,7 +317,7 @@ struct samsung_fimc_driverdata {
struct fimc_ctx;
/**
- * struct fimc_subdev - abstraction for a FIMC entity
+ * struct fimc_dev - abstraction for FIMC entity
*
* @slock: the spinlock protecting this data structure
* @lock: the mutex protecting this data structure
@@ -323,7 +327,7 @@ struct fimc_ctx;
* @regs: the mapped hardware registers
* @regs_res: the resource claimed for IO registers
* @irq: interrupt number of the FIMC subdevice
- * @irqlock: spinlock protecting videbuffer queue
+ * @irqlock: spinlock protecting videobuffer queue
* @m2m: memory-to-memory V4L2 device information
* @state: the FIMC device state flags
*/
@@ -338,7 +342,6 @@ struct fimc_dev {
struct resource *regs_res;
int irq;
spinlock_t irqlock;
- struct workqueue_struct *work_queue;
struct fimc_m2m_device m2m;
unsigned long state;
};
@@ -359,7 +362,7 @@ struct fimc_dev {
* @effect: image effect
* @rotation: image clockwise rotation in degrees
* @flip: image flip mode
- * @flags: an additional flags for image conversion
+ * @flags: additional flags for image conversion
* @state: flags to keep track of user configuration
* @fimc_dev: the FIMC device this context applies to
* @m2m_ctx: memory-to-memory device context
@@ -397,18 +400,24 @@ static inline void fimc_hw_clear_irq(struct fimc_dev *dev)
writel(cfg, dev->regs + S5P_CIGCTRL);
}
-static inline void fimc_hw_start_scaler(struct fimc_dev *dev)
+static inline void fimc_hw_enable_scaler(struct fimc_dev *dev, bool on)
{
u32 cfg = readl(dev->regs + S5P_CISCCTRL);
- cfg |= S5P_CISCCTRL_SCALERSTART;
+ if (on)
+ cfg |= S5P_CISCCTRL_SCALERSTART;
+ else
+ cfg &= ~S5P_CISCCTRL_SCALERSTART;
writel(cfg, dev->regs + S5P_CISCCTRL);
}
-static inline void fimc_hw_stop_scaler(struct fimc_dev *dev)
+static inline void fimc_hw_activate_input_dma(struct fimc_dev *dev, bool on)
{
- u32 cfg = readl(dev->regs + S5P_CISCCTRL);
- cfg &= ~S5P_CISCCTRL_SCALERSTART;
- writel(cfg, dev->regs + S5P_CISCCTRL);
+ u32 cfg = readl(dev->regs + S5P_MSCTRL);
+ if (on)
+ cfg |= S5P_MSCTRL_ENVID;
+ else
+ cfg &= ~S5P_MSCTRL_ENVID;
+ writel(cfg, dev->regs + S5P_MSCTRL);
}
static inline void fimc_hw_dis_capture(struct fimc_dev *dev)
@@ -418,22 +427,8 @@ static inline void fimc_hw_dis_capture(struct fimc_dev *dev)
writel(cfg, dev->regs + S5P_CIIMGCPT);
}
-static inline void fimc_hw_start_in_dma(struct fimc_dev *dev)
-{
- u32 cfg = readl(dev->regs + S5P_MSCTRL);
- cfg |= S5P_MSCTRL_ENVID;
- writel(cfg, dev->regs + S5P_MSCTRL);
-}
-
-static inline void fimc_hw_stop_in_dma(struct fimc_dev *dev)
-{
- u32 cfg = readl(dev->regs + S5P_MSCTRL);
- cfg &= ~S5P_MSCTRL_ENVID;
- writel(cfg, dev->regs + S5P_MSCTRL);
-}
-
-static inline struct fimc_frame *ctx_m2m_get_frame(struct fimc_ctx *ctx,
- enum v4l2_buf_type type)
+static inline struct fimc_frame *ctx_get_frame(struct fimc_ctx *ctx,
+ enum v4l2_buf_type type)
{
struct fimc_frame *frame;
@@ -452,20 +447,35 @@ static inline struct fimc_frame *ctx_m2m_get_frame(struct fimc_ctx *ctx,
/* -----------------------------------------------------*/
/* fimc-reg.c */
-void fimc_hw_reset(struct fimc_dev *dev);
+void fimc_hw_reset(struct fimc_dev *fimc);
void fimc_hw_set_rotation(struct fimc_ctx *ctx);
void fimc_hw_set_target_format(struct fimc_ctx *ctx);
void fimc_hw_set_out_dma(struct fimc_ctx *ctx);
-void fimc_hw_en_lastirq(struct fimc_dev *dev, int enable);
-void fimc_hw_en_irq(struct fimc_dev *dev, int enable);
-void fimc_hw_set_prescaler(struct fimc_ctx *ctx);
+void fimc_hw_en_lastirq(struct fimc_dev *fimc, int enable);
+void fimc_hw_en_irq(struct fimc_dev *fimc, int enable);
void fimc_hw_set_scaler(struct fimc_ctx *ctx);
void fimc_hw_en_capture(struct fimc_ctx *ctx);
void fimc_hw_set_effect(struct fimc_ctx *ctx);
void fimc_hw_set_in_dma(struct fimc_ctx *ctx);
void fimc_hw_set_input_path(struct fimc_ctx *ctx);
void fimc_hw_set_output_path(struct fimc_ctx *ctx);
-void fimc_hw_set_input_addr(struct fimc_dev *dev, struct fimc_addr *paddr);
-void fimc_hw_set_output_addr(struct fimc_dev *dev, struct fimc_addr *paddr);
+void fimc_hw_set_input_addr(struct fimc_dev *fimc, struct fimc_addr *paddr);
+void fimc_hw_set_output_addr(struct fimc_dev *fimc, struct fimc_addr *paddr,
+ int index);
+
+/* Locking: the caller holds fimc->slock */
+static inline void fimc_activate_capture(struct fimc_ctx *ctx)
+{
+ fimc_hw_enable_scaler(ctx->fimc_dev, ctx->scaler.enabled);
+ fimc_hw_en_capture(ctx);
+}
+
+static inline void fimc_deactivate_capture(struct fimc_dev *fimc)
+{
+ fimc_hw_en_lastirq(fimc, true);
+ fimc_hw_dis_capture(fimc);
+ fimc_hw_enable_scaler(fimc, false);
+ fimc_hw_en_lastirq(fimc, false);
+}
#endif /* FIMC_CORE_H_ */
diff --git a/drivers/media/video/s5p-fimc/fimc-reg.c b/drivers/media/video/s5p-fimc/fimc-reg.c
index 70f29c5..94e98d4 100644
--- a/drivers/media/video/s5p-fimc/fimc-reg.c
+++ b/drivers/media/video/s5p-fimc/fimc-reg.c
@@ -29,7 +29,7 @@ void fimc_hw_reset(struct fimc_dev *dev)
cfg = readl(dev->regs + S5P_CIGCTRL);
cfg |= (S5P_CIGCTRL_SWRST | S5P_CIGCTRL_IRQ_LEVEL);
writel(cfg, dev->regs + S5P_CIGCTRL);
- msleep(1);
+ udelay(1000);
cfg = readl(dev->regs + S5P_CIGCTRL);
cfg &= ~S5P_CIGCTRL_SWRST;
@@ -247,21 +247,20 @@ void fimc_hw_en_lastirq(struct fimc_dev *dev, int enable)
spin_unlock_irqrestore(&dev->slock, flags);
}
-void fimc_hw_set_prescaler(struct fimc_ctx *ctx)
+static void fimc_hw_set_prescaler(struct fimc_ctx *ctx)
{
struct fimc_dev *dev = ctx->fimc_dev;
struct fimc_scaler *sc = &ctx->scaler;
- u32 cfg = 0, shfactor;
+ u32 cfg, shfactor;
shfactor = 10 - (sc->hfactor + sc->vfactor);
- cfg |= S5P_CISCPRERATIO_SHFACTOR(shfactor);
+ cfg = S5P_CISCPRERATIO_SHFACTOR(shfactor);
cfg |= S5P_CISCPRERATIO_HOR(sc->pre_hratio);
cfg |= S5P_CISCPRERATIO_VER(sc->pre_vratio);
writel(cfg, dev->regs + S5P_CISCPRERATIO);
- cfg = 0;
- cfg |= S5P_CISCPREDST_WIDTH(sc->pre_dst_width);
+ cfg = S5P_CISCPREDST_WIDTH(sc->pre_dst_width);
cfg |= S5P_CISCPREDST_HEIGHT(sc->pre_dst_height);
writel(cfg, dev->regs + S5P_CISCPREDST);
}
@@ -274,6 +273,8 @@ void fimc_hw_set_scaler(struct fimc_ctx *ctx)
struct fimc_frame *dst_frame = &ctx->d_frame;
u32 cfg = 0;
+ fimc_hw_set_prescaler(ctx);
+
if (!(ctx->flags & FIMC_COLOR_RANGE_NARROW))
cfg |= (S5P_CISCCTRL_CSCR2Y_WIDE | S5P_CISCCTRL_CSCY2R_WIDE);
@@ -364,7 +365,7 @@ static void fimc_hw_set_in_dma_size(struct fimc_ctx *ctx)
u32 cfg_r = 0;
if (FIMC_LCDFIFO == ctx->out_path)
- cfg_r |= S5P_CIREAL_ISIZE_AUTOLOAD_EN;
+ cfg_r |= S5P_CIREAL_ISIZE_AUTOLOAD_EN;
cfg_o |= S5P_ORIG_SIZE_HOR(frame->f_width);
cfg_o |= S5P_ORIG_SIZE_VER(frame->f_height);
@@ -380,27 +381,25 @@ void fimc_hw_set_in_dma(struct fimc_ctx *ctx)
struct fimc_dev *dev = ctx->fimc_dev;
struct fimc_frame *frame = &ctx->s_frame;
struct fimc_dma_offset *offset = &frame->dma_offset;
- u32 cfg = 0;
+ u32 cfg;
/* Set the pixel offsets. */
- cfg |= S5P_CIO_OFFS_HOR(offset->y_h);
+ cfg = S5P_CIO_OFFS_HOR(offset->y_h);
cfg |= S5P_CIO_OFFS_VER(offset->y_v);
writel(cfg, dev->regs + S5P_CIIYOFF);
- cfg = 0;
- cfg |= S5P_CIO_OFFS_HOR(offset->cb_h);
+ cfg = S5P_CIO_OFFS_HOR(offset->cb_h);
cfg |= S5P_CIO_OFFS_VER(offset->cb_v);
writel(cfg, dev->regs + S5P_CIICBOFF);
- cfg = 0;
- cfg |= S5P_CIO_OFFS_HOR(offset->cr_h);
+ cfg = S5P_CIO_OFFS_HOR(offset->cr_h);
cfg |= S5P_CIO_OFFS_VER(offset->cr_v);
writel(cfg, dev->regs + S5P_CIICROFF);
/* Input original and real size. */
fimc_hw_set_in_dma_size(ctx);
- /* Autoload is used currently only in FIFO mode. */
+ /* Use DMA autoload only in FIFO mode. */
fimc_hw_en_autoload(dev, ctx->out_path == FIMC_LCDFIFO);
/* Set the input DMA to process single frame only. */
@@ -501,9 +500,7 @@ void fimc_hw_set_output_path(struct fimc_ctx *ctx)
void fimc_hw_set_input_addr(struct fimc_dev *dev, struct fimc_addr *paddr)
{
- u32 cfg = 0;
-
- cfg = readl(dev->regs + S5P_CIREAL_ISIZE);
+ u32 cfg = readl(dev->regs + S5P_CIREAL_ISIZE);
cfg |= S5P_CIREAL_ISIZE_ADDR_CH_DIS;
writel(cfg, dev->regs + S5P_CIREAL_ISIZE);
@@ -515,13 +512,15 @@ void fimc_hw_set_input_addr(struct fimc_dev *dev, struct fimc_addr *paddr)
writel(cfg, dev->regs + S5P_CIREAL_ISIZE);
}
-void fimc_hw_set_output_addr(struct fimc_dev *dev, struct fimc_addr *paddr)
+void fimc_hw_set_output_addr(struct fimc_dev *dev,
+ struct fimc_addr *paddr, int index)
{
- int i;
- /* Set all the output register sets to point to single video buffer. */
- for (i = 0; i < FIMC_MAX_OUT_BUFS; i++) {
+ int i = (index == -1) ? 0 : index;
+ do {
writel(paddr->y, dev->regs + S5P_CIOYSA(i));
writel(paddr->cb, dev->regs + S5P_CIOCBSA(i));
writel(paddr->cr, dev->regs + S5P_CIOCRSA(i));
- }
+ dbg("dst_buf[%d]: 0x%X, cb: 0x%X, cr: 0x%X",
+ i, paddr->y, paddr->cb, paddr->cr);
+ } while (index == -1 && ++i < FIMC_MAX_OUT_BUFS);
}
--
1.7.3.1
^ permalink raw reply related
* Re: [PATCH v3] serio: add support for PS2Mult multiplexer protocol
From: Dmitry Eremin-Solenikov @ 2010-10-08 8:50 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: linux-input
In-Reply-To: <20101007163606.GA24406@core.coreip.homeip.net>
Hello,
On Thu, Oct 7, 2010 at 8:36 PM, Dmitry Torokhov
<dmitry.torokhov@gmail.com> wrote:
> On Thu, Oct 07, 2010 at 07:19:57PM +0400, Dmitry Eremin-Solenikov wrote:
>> Hello,
>>
>> On Thu, Sep 30, 2010 at 10:25 AM, Dmitry Torokhov
>> <dmitry.torokhov@gmail.com> wrote:
>> > On Wed, Sep 29, 2010 at 04:45:53PM +0400, Dmitry Eremin-Solenikov wrote:
>> >> On Thu, Sep 23, 2010 at 8:44 PM, Dmitry Eremin-Solenikov
>> >> <dbaryshkov@gmail.com> wrote:
>> >> > PS2Mult is a simple serial protocol used for multiplexing several PS/2 streams
>> >> > into one serial data stream. It's used e.g. on TQM85xx serie of boards.
>> >> >
>> >> > Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
>> >> > ---
>> >> >
>> >> > It actually depends on "serio: multiple children" patch. I'm not resending it
>> >> > as you were the originator of the latest version of the patch.
>> >>
>> >> So, what about this version of patch?
>> >>
>> >
>> > Looks better but I think you also need ->start() to make sure you do not
>> > try to deliver events too early. Does the following still work for you?
>>
>> Sorry for the delay. Crashes w/o the attached patch.
>>
>
> Ah, I see, however what I actually wanted is to create ports before hand
> and handle any errors that might arise and then enable the device and
> register child ports.
>
> If you apply the patch below instead of yours does it still work?
It won't work, as we don't set psm->ports[i].serio before ps2mult_serio_start()
>
> Thanks.
>
> --
> Dmitry
>
> Input: ps2mult - don't register ports twice
>
> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
> ---
>
> drivers/input/serio/ps2mult.c | 11 ++++++-----
> 1 files changed, 6 insertions(+), 5 deletions(-)
>
>
> diff --git a/drivers/input/serio/ps2mult.c b/drivers/input/serio/ps2mult.c
> index 3664398..52b58de 100644
> --- a/drivers/input/serio/ps2mult.c
> +++ b/drivers/input/serio/ps2mult.c
> @@ -144,9 +144,6 @@ static int ps2mult_create_port(struct ps2mult *psm, int i)
> serio->parent = psm->mx_serio;
> serio->port_data = &psm->ports[i];
>
> - serio_register_port(serio);
> - dev_info(&serio->dev, "%s port at %s\n", serio->name, mx_serio->phys);
> -
> return 0;
> }
>
> @@ -196,8 +193,12 @@ static int ps2mult_connect(struct serio *serio, struct serio_driver *drv)
>
> ps2mult_reset(psm);
>
> - for (i = 0; i < PS2MULT_NUM_PORTS; i++)
> - serio_register_port(psm->ports[i].serio);
> + for (i = 0; i < PS2MULT_NUM_PORTS; i++) {
> + struct serio *s = psm->ports[i].serio;
> +
> + dev_info(&serio->dev, "%s port at %s\n", s->name, serio->phys);
> + serio_register_port(s);
> + }
>
> return 0;
>
>
--
With best wishes
Dmitry
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH 1/5 v4] V4L/DVB: s5p-fimc: Register definition cleanup
From: Sylwester Nawrocki @ 2010-10-08 8:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1286527837-4980-1-git-send-email-s.nawrocki@samsung.com>
Add MIPI CSI format definitions, prepare DMA address
definitions for interlaced input frame mode.
Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
drivers/media/video/s5p-fimc/fimc-reg.c | 6 +-
drivers/media/video/s5p-fimc/regs-fimc.h | 61 ++++++++++++-----------------
2 files changed, 28 insertions(+), 39 deletions(-)
diff --git a/drivers/media/video/s5p-fimc/fimc-reg.c b/drivers/media/video/s5p-fimc/fimc-reg.c
index 5570f1c..70f29c5 100644
--- a/drivers/media/video/s5p-fimc/fimc-reg.c
+++ b/drivers/media/video/s5p-fimc/fimc-reg.c
@@ -507,9 +507,9 @@ void fimc_hw_set_input_addr(struct fimc_dev *dev, struct fimc_addr *paddr)
cfg |= S5P_CIREAL_ISIZE_ADDR_CH_DIS;
writel(cfg, dev->regs + S5P_CIREAL_ISIZE);
- writel(paddr->y, dev->regs + S5P_CIIYSA0);
- writel(paddr->cb, dev->regs + S5P_CIICBSA0);
- writel(paddr->cr, dev->regs + S5P_CIICRSA0);
+ writel(paddr->y, dev->regs + S5P_CIIYSA(0));
+ writel(paddr->cb, dev->regs + S5P_CIICBSA(0));
+ writel(paddr->cr, dev->regs + S5P_CIICRSA(0));
cfg &= ~S5P_CIREAL_ISIZE_ADDR_CH_DIS;
writel(cfg, dev->regs + S5P_CIREAL_ISIZE);
diff --git a/drivers/media/video/s5p-fimc/regs-fimc.h b/drivers/media/video/s5p-fimc/regs-fimc.h
index a3cfe82..9e83315 100644
--- a/drivers/media/video/s5p-fimc/regs-fimc.h
+++ b/drivers/media/video/s5p-fimc/regs-fimc.h
@@ -11,10 +11,6 @@
#ifndef REGS_FIMC_H_
#define REGS_FIMC_H_
-#define S5P_CIOYSA(__x) (0x18 + (__x) * 4)
-#define S5P_CIOCBSA(__x) (0x28 + (__x) * 4)
-#define S5P_CIOCRSA(__x) (0x38 + (__x) * 4)
-
/* Input source format */
#define S5P_CISRCFMT 0x00
#define S5P_CISRCFMT_ITU601_8BIT (1 << 31)
@@ -28,22 +24,21 @@
/* Window offset */
#define S5P_CIWDOFST 0x04
-#define S5P_CIWDOFST_WINOFSEN (1 << 31)
+#define S5P_CIWDOFST_OFF_EN (1 << 31)
#define S5P_CIWDOFST_CLROVFIY (1 << 30)
#define S5P_CIWDOFST_CLROVRLB (1 << 29)
-#define S5P_CIWDOFST_WINHOROFST_MASK (0x7ff << 16)
+#define S5P_CIWDOFST_HOROFF_MASK (0x7ff << 16)
#define S5P_CIWDOFST_CLROVFICB (1 << 15)
#define S5P_CIWDOFST_CLROVFICR (1 << 14)
-#define S5P_CIWDOFST_WINHOROFST(x) ((x) << 16)
-#define S5P_CIWDOFST_WINVEROFST(x) ((x) << 0)
-#define S5P_CIWDOFST_WINVEROFST_MASK (0xfff << 0)
+#define S5P_CIWDOFST_HOROFF(x) ((x) << 16)
+#define S5P_CIWDOFST_VEROFF(x) ((x) << 0)
+#define S5P_CIWDOFST_VEROFF_MASK (0xfff << 0)
/* Global control */
#define S5P_CIGCTRL 0x08
#define S5P_CIGCTRL_SWRST (1 << 31)
#define S5P_CIGCTRL_CAMRST_A (1 << 30)
#define S5P_CIGCTRL_SELCAM_ITU_A (1 << 29)
-#define S5P_CIGCTRL_SELCAM_ITU_MASK (1 << 29)
#define S5P_CIGCTRL_TESTPAT_NORMAL (0 << 27)
#define S5P_CIGCTRL_TESTPAT_COLOR_BAR (1 << 27)
#define S5P_CIGCTRL_TESTPAT_HOR_INC (2 << 27)
@@ -61,6 +56,8 @@
#define S5P_CIGCTRL_SHDW_DISABLE (1 << 12)
#define S5P_CIGCTRL_SELCAM_MIPI_A (1 << 7)
#define S5P_CIGCTRL_CAMIF_SELWB (1 << 6)
+/* 0 - ITU601; 1 - ITU709 */
+#define S5P_CIGCTRL_CSC_ITU601_709 (1 << 5)
#define S5P_CIGCTRL_INVPOLHSYNC (1 << 4)
#define S5P_CIGCTRL_SELCAM_MIPI (1 << 3)
#define S5P_CIGCTRL_INTERLACE (1 << 0)
@@ -72,23 +69,10 @@
#define S5P_CIWDOFST2_HOROFF(x) ((x) << 16)
#define S5P_CIWDOFST2_VEROFF(x) ((x) << 0)
-/* Output DMA Y plane start address */
-#define S5P_CIOYSA1 0x18
-#define S5P_CIOYSA2 0x1c
-#define S5P_CIOYSA3 0x20
-#define S5P_CIOYSA4 0x24
-
-/* Output DMA Cb plane start address */
-#define S5P_CIOCBSA1 0x28
-#define S5P_CIOCBSA2 0x2c
-#define S5P_CIOCBSA3 0x30
-#define S5P_CIOCBSA4 0x34
-
-/* Output DMA Cr plane start address */
-#define S5P_CIOCRSA1 0x38
-#define S5P_CIOCRSA2 0x3c
-#define S5P_CIOCRSA3 0x40
-#define S5P_CIOCRSA4 0x44
+/* Output DMA Y/Cb/Cr plane start addresses */
+#define S5P_CIOYSA(n) (0x18 + (n) * 4)
+#define S5P_CIOCBSA(n) (0x28 + (n) * 4)
+#define S5P_CIOCRSA(n) (0x38 + (n) * 4)
/* Target image format */
#define S5P_CITRGFMT 0x48
@@ -168,6 +152,8 @@
#define S5P_CISTATUS_OVFICB (1 << 30)
#define S5P_CISTATUS_OVFICR (1 << 29)
#define S5P_CISTATUS_VSYNC (1 << 28)
+#define S5P_CISTATUS_FRAMECNT_MASK (3 << 26)
+#define S5P_CISTATUS_FRAMECNT_SHIFT 26
#define S5P_CISTATUS_WINOFF_EN (1 << 25)
#define S5P_CISTATUS_IMGCPT_EN (1 << 22)
#define S5P_CISTATUS_IMGCPT_SCEN (1 << 21)
@@ -206,10 +192,10 @@
#define S5P_CIIMGEFF_PAT_CB(x) ((x) << 13)
#define S5P_CIIMGEFF_PAT_CR(x) ((x) << 0)
-/* Input DMA Y/Cb/Cr plane start address 0 */
-#define S5P_CIIYSA0 0xd4
-#define S5P_CIICBSA0 0xd8
-#define S5P_CIICRSA0 0xdc
+/* Input DMA Y/Cb/Cr plane start address 0/1 */
+#define S5P_CIIYSA(n) (0xd4 + (n) * 0x70)
+#define S5P_CIICBSA(n) (0xd8 + (n) * 0x70)
+#define S5P_CIICRSA(n) (0xdc + (n) * 0x70)
/* Real input DMA image size */
#define S5P_CIREAL_ISIZE 0xf8
@@ -250,11 +236,6 @@
#define S5P_MSCTRL_ENVID (1 << 0)
#define S5P_MSCTRL_FRAME_COUNT(x) ((x) << 24)
-/* Input DMA Y/Cb/Cr plane start address 1 */
-#define S5P_CIIYSA1 0x144
-#define S5P_CIICBSA1 0x148
-#define S5P_CIICRSA1 0x14c
-
/* Output DMA Y/Cb/Cr offset */
#define S5P_CIOYOFF 0x168
#define S5P_CIOCBOFF 0x16c
@@ -289,5 +270,13 @@
/* MIPI CSI image format */
#define S5P_CSIIMGFMT 0x194
+#define S5P_CSIIMGFMT_YCBCR422_8BIT 0x1e
+#define S5P_CSIIMGFMT_RAW8 0x2a
+#define S5P_CSIIMGFMT_RAW10 0x2b
+#define S5P_CSIIMGFMT_RAW12 0x2c
+#define S5P_CSIIMGFMT_USER1 0x30
+#define S5P_CSIIMGFMT_USER2 0x31
+#define S5P_CSIIMGFMT_USER3 0x32
+#define S5P_CSIIMGFMT_USER4 0x33
#endif /* REGS_FIMC_H_ */
--
1.7.3.1
^ permalink raw reply related
* [PATCH v4 0/4] Add support for camera capture in s5p-fimc driver
From: Sylwester Nawrocki @ 2010-10-08 8:50 UTC (permalink / raw)
To: linux-arm-kernel
Hi all,
here is a fourth version of patches adding camera capture capability
to the s5p-fimc driver. It contains minor changes to adhere to patch
submitting rules.
Changes since v1:
- entirely removed plat-samsung/include/plat/fimc.h header so there is no
platform code dependency
- improved s/try_fmt ioctl and introduced common ioctl handlers for mem2mem
and capture node where it's reasonable
- register definition changes merged with previous commit
[3/8] v4l: s5p-fimc: Register definition cleanup
Changes since v2:
- improved s/g/crop(cap) handling in capture node
- added passing of v4l controls to the sensor subdevice
Changes since v3:
- changed summary of patch [4/4] to adhere to patch submitting guidelines
- patch "V4L/DVB: s5p-fimc: M2M driver cleanup.." split to 2 separate
commits - 2/5 and 3/5 in this series
The patch series contains:
[PATCH 1/5] V4L/DVB: s5p-fimc: Register definition cleanup
[PATCH 2/5] V4L/DVB: s5p-fimc: mem2mem driver refactoring and cleanup
[PATCH 3/5] V4L/DVB: s5p-fimc: Fix 90/270 deg rotation errors
[PATCH 4/5] V4L/DVB: s5p-fimc: Do not lock both capture and output buffer queue in s_fmt
[PATCH 5/5] V4L/DVB: s5p-fimc: Add camera capture support
It has been rebased onto linuxtv/staging-2.6.37 branch at
git://linuxtv.org/media_tree.git with 2 bugfix patches:
v4l: s5p-fimc: Fix 3-planar formats handling and pixel offset error on S5PV210 SoCs
v4l: s5p-fimc: Fix return value on probe() failure
also applied.
Regards,
Sylwester
--
Sylwester Nawrocki
Linux Platform Group
Samsung Poland R&D Center
^ permalink raw reply
* [Qemu-devel] Re: [PATCH 5/6] Switch migrate_set_speed() to take an 'o' argument rather than a float.
From: Jes Sorensen @ 2010-10-08 8:50 UTC (permalink / raw)
To: Paolo Bonzini; +Cc: qemu-devel, armbru
In-Reply-To: <4CADEF6D.3010706@redhat.com>
On 10/07/10 18:03, Paolo Bonzini wrote:
> On 10/07/2010 05:01 PM, Jes.Sorensen@redhat.com wrote:
>> diff --git a/hmp-commands.hx b/hmp-commands.hx
>> index 81999aa..95bdb91 100644
>> --- a/hmp-commands.hx
>> +++ b/hmp-commands.hx
>> @@ -754,7 +754,7 @@ ETEXI
>>
>> {
>> .name = "migrate_set_speed",
>> - .args_type = "value:f",
>> + .args_type = "value:o",
>> .params = "value",
>> .help = "set maximum speed (in bytes) for migrations",
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>
> Is this still accurate?
>
> Alternatively, you said it's a mess to distinguish the defaults on the
> command line and the monitor, but is it harder than the attached patch?
I guess that depends on how you look at it, but I guess I could improve
the error message to make it clearer.
Cheers,
Jes
^ permalink raw reply
* [PATCH v3] i.MX31 and i.MX35 : fix errate TLSbo65953 and ENGcm09472
From: Eric Bénard @ 2010-10-08 8:49 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4CAC58E3.9040503@eukrea.com>
Without this exiting WFI can result in cache corruption.
Code taken from Freescale's 2.6.27 BSP and tested on i.MX35
Signed-off-by: Eric B?nard <eric@eukrea.com>
---
- v3 : fix following UWE's review
- v2 : use cpu_ismx3x() and add comments.
arch/arm/plat-mxc/include/mach/system.h | 32 ++++++++++++++++++++++++++++--
1 files changed, 29 insertions(+), 3 deletions(-)
diff --git a/arch/arm/plat-mxc/include/mach/system.h b/arch/arm/plat-mxc/include/mach/system.h
index 4acd114..95be51b 100644
--- a/arch/arm/plat-mxc/include/mach/system.h
+++ b/arch/arm/plat-mxc/include/mach/system.h
@@ -1,7 +1,7 @@
/*
* Copyright (C) 1999 ARM Limited
* Copyright (C) 2000 Deep Blue Solutions Ltd
- * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2004-2008 Freescale Semiconductor, Inc. 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 as published by
@@ -28,8 +28,34 @@ static inline void arch_idle(void)
mxc91231_prepare_idle();
}
#endif
-
- cpu_do_idle();
+ /* fix i.MX31 errata TLSbo65953 and i.MX35 errata ENGcm09472 */
+ if (cpu_is_mx31() || cpu_is_mx35()) {
+ unsigned long reg = 0;
+ __asm__ __volatile__(
+ /* disable I and D cache */
+ "mrc p15, 0, %0, c1, c0, 0\n"
+ "bic %0, %0, #0x00001000\n"
+ "bic %0, %0, #0x00000004\n"
+ "mcr p15, 0, %0, c1, c0, 0\n"
+ /* invalidate I cache */
+ "mov %0, #0\n"
+ "mcr p15, 0, %0, c7, c5, 0\n"
+ /* clear and invalidate D cache */
+ "mov %0, #0\n"
+ "mcr p15, 0, %0, c7, c14, 0\n"
+ /* WFI */
+ "mov %0, #0\n"
+ "mcr p15, 0, %0, c7, c0, 4\n"
+ "nop\n" "nop\n" "nop\n" "nop\n"
+ "nop\n" "nop\n" "nop\n"
+ /* enable I and D cache */
+ "mrc p15, 0, %0, c1, c0, 0\n"
+ "orr %0, %0, #0x00001000\n"
+ "orr %0, %0, #0x00000004\n"
+ "mcr p15, 0, %0, c1, c0, 0\n"
+ : "=r" (reg));
+ } else
+ cpu_do_idle();
}
void arch_reset(char mode, const char *cmd);
--
1.7.0.4
^ permalink raw reply related
* question about vfs->writepage
From: ma ming @ 2010-10-08 8:48 UTC (permalink / raw)
To: linux-fsdevel
Hi,all
I am new to mailing list, sorry if I made any mistake.
I need to get the file content when flushing page for my file system.
So I do this in address_space_operations->writepage.
But I found that some block's content on hard disk is not as my fs saw
in writepage.
May I ask whether the content can change after writepage and before
really flush to harddisk? If yes, is there any method to avoid that?
Regards,
Ma Ming Cao
mamingcao@gmail.com
The Chinese University of Hong Kong
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: 2.6.36-rc7: kernel panic with SECURITY_TOMOYO=y
From: James Morris @ 2010-10-08 8:47 UTC (permalink / raw)
To: Tetsuo Handa
Cc: kosaki.motohiro, linux-kernel, takedakn, lists, kawime, jkosina,
linux-security-module
In-Reply-To: <201010080626.o986QJX4002281@www262.sakura.ne.jp>
On Fri, 8 Oct 2010, Tetsuo Handa wrote:
> Date: Fri, 8 Oct 2010 14:43:22 +0900
> Subject: [PATCH] TOMOYO: Print URL information before panic().
>
> Configuration files for TOMOYO 2.3 are not compatible with TOMOYO 2.2.
> But current panic() message is too unfriendly and is confusing users.
>
> Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Applied to
git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6#next
--
James Morris
<jmorris@namei.org>
^ permalink raw reply
* RE: Configuration of nestedhvm
From: Dong, Eddie @ 2010-10-08 8:47 UTC (permalink / raw)
To: Keir Fraser; +Cc: Xen-devel, Dong, Eddie
In-Reply-To: <C8D49364.256F0%keir@xen.org>
Keir Fraser wrote:
> On 08/10/2010 08:56, "Dong, Eddie" <eddie.dong@intel.com> wrote:
>
>>> What's the point when a per-domain config option is going to be
>>> implemented? You can then simply not configure nestedhvm for a
>>> domain you want to test without that capability? I suppose it makes
>>> your second patch make a bit more sense than it would in total
>>> isolation.
>>
>> I want double-lock (AND) like other components such as IOMMU.
>> If the global switch is off, even per domain configuration is turned
>> on, the final effect is "OFF".
>>
>> The point here is to avoid manual mistake when the nested code is
>> built in as formal release but targeting for pilot. Relying on HVM
>> guest configuration only may cause the host crash or performance
>> impact if the code has a bug and a guest enables nested
>> virtualization feature.
>>
>> This switch is mainly for developer only at least for now.
>
> Well, at least it should only be disallowing toolstack to set the
> per-domain config option. Then it won't need to be accessed on every
The tools side patch will hypercall to try to set, but it is hypervisor's decision to allow the setting or not.
The userland CPUID emulation will rely on the VMM returned setting.
> use of is_nestedhvm(). So again it depends on that, mainly tool-side,
> patch.
It is chicken and egg then :) emulation of per domain setting hypercall relies on the global setting. is_nestedhvm relies on the per domain setting :)
But it is fine too, as if you want the global control, and Chris may merge the patch into his if he needs to repost..
>
> -- Keir
So can Ian have a look at the previous Chris patch again? What is the reason to block that patch?
Thx, Eddie
^ permalink raw reply
* Re: [PATCH 2/2] device-assignment: Allow PCI to manage the option ROM
From: Michael S. Tsirkin @ 2010-10-08 8:40 UTC (permalink / raw)
To: Alex Williamson; +Cc: kvm, ddutile, chrisw
In-Reply-To: <1286510545.3016.36.camel@x201>
On Thu, Oct 07, 2010 at 10:02:25PM -0600, Alex Williamson wrote:
> On Fri, 2010-10-08 at 00:45 +0200, Michael S. Tsirkin wrote:
> > On Thu, Oct 07, 2010 at 11:34:01AM -0600, Alex Williamson wrote:
> > > On Thu, 2010-10-07 at 19:18 +0200, Michael S. Tsirkin wrote:
> > > > On Mon, Oct 04, 2010 at 03:26:30PM -0600, Alex Williamson wrote:
> > > > > --- a/hw/device-assignment.c
> > > > > +++ b/hw/device-assignment.c
> > > ...
> > > > > @@ -1644,58 +1621,64 @@ void add_assigned_devices(PCIBus *bus, const char **devices, int n_devices)
> > > > > */
> > > > > static void assigned_dev_load_option_rom(AssignedDevice *dev)
> > > > > {
> > > > > - int size, len, ret;
> > > > > - void *buf;
> > > > > + char name[32], rom_file[64];
> > > > > FILE *fp;
> > > > > - uint8_t i = 1;
> > > > > - char rom_file[64];
> > > > > + uint8_t val;
> > > > > + struct stat st;
> > > > > + void *ptr;
> > > > > +
> > > > > + /* If loading ROM from file, pci handles it */
> > > > > + if (dev->dev.romfile || !dev->dev.rom_bar)
> > > > > + return;
> > > > >
> > > > > snprintf(rom_file, sizeof(rom_file),
> > > > > "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/rom",
> > > > > dev->host.seg, dev->host.bus, dev->host.dev, dev->host.func);
> > > > >
> > > > > - if (access(rom_file, F_OK))
> > > > > + if (stat(rom_file, &st)) {
> > > > > return;
> > > > > + }
> > > > >
> > > >
> > > > Just a note that stat on the ROM sysfs file returns window size,
> > > > not the ROM size. So this allocates more ram than really necessary for
> > > > ROM. Real size is returned by fread.
> > > >
> > > > Do we care?
> > >
> > > That was my intention with using stat. I thought that by default the
> > > ROM BAR should match physical hardware, so even if the contents could be
> > > rounded down to a smaller size, we maintain the size of the physical
> > > device. To use the minimum size, the contents could be extracted using
> > > pci-sysfs and passed with the romfile option, or the ROM could be
> > > disabled altogether with the rombar=0 option. Sound reasonable?
> > > Thanks,
> > >
> > > Alex
> >
> > For BAR size yes, but we do not need the buffer full of 0xff as it is
> > never accessed: let's have buffer size match real ROM, avoid wasting
> > memory: this can come up to megabytes easily.
> > Makes sense?
>
> I tend to doubt that hardware vendors are going to waste money putting
> seriously oversized eeproms on devices. It does seem pretty typical to
> find graphics cards with 128K ROM BARs where the actual ROM squeezes
> just under 64K, but that's a long way from megabytes of wasted memory.
> The only device I have with a ROM BAR in the megabytes is an 82576, but
> it comes up as an invalid rom through pci-sysfs, so we skip it. I
> assume that just means someone was lazy and didn't bother to fuse a
> transistor that disables the ROM BAR, leaving it at it's maximum
> aperture w/ no eeprom to back it. Anyone know? Examples to the
> contrary welcome.
>
> So I think the question comes down to whether there's any value to
> trying to exactly mimic the resource layout of the device. I'm doubtful
> that there is, but at the potential cost of 10-100s of KBs of memory, I
> thought it might be worthwhile. If you feel strongly otherwise, I'll
> follow-up with a patch to size it by the actual readable contents.
> Thanks,
>
> Alex
I actually agree sizing ROM BAR exactly the same as the device
is a good idea. I just thought we can save the extra memory
by not allocating the RAM in question, and writing code
to return 0xff on reads within the BAR but outside ROM.
And no, I don't feel strongly about this optimization.
--
MST
^ permalink raw reply
* [PATCH V3 2/2] sdhci-s3c: Add support no internal clock divider in host controller
From: Kukjin Kim @ 2010-10-08 8:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1286527581-24903-1-git-send-email-kgene.kim@samsung.com>
From: Jeongbae Seo <jeongbae.seo@samsung.com>
This patch adds to support no internal clock divider in SDHCI.
The external clock divider can be used to make a proper clock
because SDHCI doesn't support internal clock divider by itself.
If external clock divider type is selected, some functions related
with clock control will be overridened by other functions.
The current clock control index is added to let you know which
clock bus is used for SDHCI when using overriding functions.
The checking functions is added into sdhci_s3c_consider_clock,
because clock divider step is different from that of host controller.
Signed-off-by: Jeongbae Seo <jeongbae.seo@samsung.com>
Cc: Jaehoon Chung <jh80.chung@samsung.com>
Cc: Ben Dooks <ben-linux@fluff.org>
Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
---
Changes since v2:
- Changed clock control method to overriding from using quirk
- This patch is referred from that of Jaehoon Chung's support non-standard clock setting
Changes since v1:
- Separated to each topic
NOTE :
- This patch depends on following.
[PATCH 4/5] ARM: SAMSUNG : Add clock types into platform data
drivers/mmc/host/sdhci-s3c.c | 62 ++++++++++++++++++++++++++++++++++++++++++
1 files changed, 62 insertions(+), 0 deletions(-)
diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c
index a7710f5..1720358 100644
--- a/drivers/mmc/host/sdhci-s3c.c
+++ b/drivers/mmc/host/sdhci-s3c.c
@@ -130,6 +130,15 @@ static unsigned int sdhci_s3c_consider_clock(struct sdhci_s3c *ourhost,
if (!clksrc)
return UINT_MAX;
+ /*
+ * Clock divider's step is different as 1 from that of host controller
+ * when 'clk_type' is S3C_SDHCI_CLK_DIV_EXTERNAL.
+ */
+ if (ourhost->pdata->clk_type) {
+ rate = clk_round_rate(clksrc, wanted);
+ return wanted - rate;
+ }
+
rate = clk_get_rate(clksrc);
for (div = 1; div < 256; div *= 2) {
@@ -232,6 +241,42 @@ static unsigned int sdhci_s3c_get_min_clock(struct sdhci_host *host)
return min;
}
+/* sdhci_cmu_get_max_clk - callback to get maximum clock frequency.*/
+static unsigned int sdhci_cmu_get_max_clock(struct sdhci_host *host)
+{
+ struct sdhci_s3c *ourhost = to_s3c(host);
+
+ return clk_round_rate(ourhost->clk_bus[ourhost->cur_clk], UINT_MAX);
+}
+
+/* sdhci_cmu_get_min_clock - callback to get minimal supported clock value. */
+static unsigned int sdhci_cmu_get_min_clock(struct sdhci_host *host)
+{
+ struct sdhci_s3c *ourhost = to_s3c(host);
+
+ /*
+ * initial clock can be in the frequency range of
+ * 100KHz-400KHz, so we set it as max value.
+ */
+ return clk_round_rate(ourhost->clk_bus[ourhost->cur_clk], 400000);
+}
+
+/* sdhci_cmu_set_clock - callback on clock change.*/
+static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+ struct sdhci_s3c *ourhost = to_s3c(host);
+
+ /* don't bother if the clock is going off */
+ if (clock == 0)
+ return;
+
+ sdhci_s3c_set_clock(host, clock);
+
+ clk_set_rate(ourhost->clk_bus[ourhost->cur_clk], clock);
+
+ host->clock = clock;
+}
+
static struct sdhci_ops sdhci_s3c_ops = {
.get_max_clock = sdhci_s3c_get_max_clk,
.set_clock = sdhci_s3c_set_clock,
@@ -361,6 +406,13 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
clks++;
sc->clk_bus[ptr] = clk;
+
+ /*
+ * save current clock index to know which clock bus
+ * is used later in overriding functions.
+ */
+ sc->cur_clk = ptr;
+
clk_enable(clk);
dev_info(dev, "clock source %d: %s (%ld Hz)\n",
@@ -427,6 +479,16 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
/* HSMMC on Samsung SoCs uses SDCLK as timeout clock */
host->quirks |= SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK;
+ /*
+ * If controller does not have internal clock divider,
+ * we can use overriding functions instead of default.
+ */
+ if (pdata->clk_type) {
+ sdhci_s3c_ops.set_clock = sdhci_cmu_set_clock;
+ sdhci_s3c_ops.get_min_clock = sdhci_cmu_get_min_clock;
+ sdhci_s3c_ops.get_max_clock = sdhci_cmu_get_max_clock;
+ }
+
/* It supports additional host capabilities if needed */
if (pdata->host_caps)
host->mmc->caps |= pdata->host_caps;
--
1.6.2.5
^ permalink raw reply related
* [PATCH V3 2/2] sdhci-s3c: Add support no internal clock divider in host controller
From: Kukjin Kim @ 2010-10-08 8:46 UTC (permalink / raw)
To: linux-arm-kernel, linux-samsung-soc, linux-mmc
Cc: ben-linux, akpm, cjb, Jeongbae Seo, Jaehoon Chung, Kukjin Kim
In-Reply-To: <1286527581-24903-1-git-send-email-kgene.kim@samsung.com>
From: Jeongbae Seo <jeongbae.seo@samsung.com>
This patch adds to support no internal clock divider in SDHCI.
The external clock divider can be used to make a proper clock
because SDHCI doesn't support internal clock divider by itself.
If external clock divider type is selected, some functions related
with clock control will be overridened by other functions.
The current clock control index is added to let you know which
clock bus is used for SDHCI when using overriding functions.
The checking functions is added into sdhci_s3c_consider_clock,
because clock divider step is different from that of host controller.
Signed-off-by: Jeongbae Seo <jeongbae.seo@samsung.com>
Cc: Jaehoon Chung <jh80.chung@samsung.com>
Cc: Ben Dooks <ben-linux@fluff.org>
Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
---
Changes since v2:
- Changed clock control method to overriding from using quirk
- This patch is referred from that of Jaehoon Chung's support non-standard clock setting
Changes since v1:
- Separated to each topic
NOTE :
- This patch depends on following.
[PATCH 4/5] ARM: SAMSUNG : Add clock types into platform data
drivers/mmc/host/sdhci-s3c.c | 62 ++++++++++++++++++++++++++++++++++++++++++
1 files changed, 62 insertions(+), 0 deletions(-)
diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c
index a7710f5..1720358 100644
--- a/drivers/mmc/host/sdhci-s3c.c
+++ b/drivers/mmc/host/sdhci-s3c.c
@@ -130,6 +130,15 @@ static unsigned int sdhci_s3c_consider_clock(struct sdhci_s3c *ourhost,
if (!clksrc)
return UINT_MAX;
+ /*
+ * Clock divider's step is different as 1 from that of host controller
+ * when 'clk_type' is S3C_SDHCI_CLK_DIV_EXTERNAL.
+ */
+ if (ourhost->pdata->clk_type) {
+ rate = clk_round_rate(clksrc, wanted);
+ return wanted - rate;
+ }
+
rate = clk_get_rate(clksrc);
for (div = 1; div < 256; div *= 2) {
@@ -232,6 +241,42 @@ static unsigned int sdhci_s3c_get_min_clock(struct sdhci_host *host)
return min;
}
+/* sdhci_cmu_get_max_clk - callback to get maximum clock frequency.*/
+static unsigned int sdhci_cmu_get_max_clock(struct sdhci_host *host)
+{
+ struct sdhci_s3c *ourhost = to_s3c(host);
+
+ return clk_round_rate(ourhost->clk_bus[ourhost->cur_clk], UINT_MAX);
+}
+
+/* sdhci_cmu_get_min_clock - callback to get minimal supported clock value. */
+static unsigned int sdhci_cmu_get_min_clock(struct sdhci_host *host)
+{
+ struct sdhci_s3c *ourhost = to_s3c(host);
+
+ /*
+ * initial clock can be in the frequency range of
+ * 100KHz-400KHz, so we set it as max value.
+ */
+ return clk_round_rate(ourhost->clk_bus[ourhost->cur_clk], 400000);
+}
+
+/* sdhci_cmu_set_clock - callback on clock change.*/
+static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+ struct sdhci_s3c *ourhost = to_s3c(host);
+
+ /* don't bother if the clock is going off */
+ if (clock == 0)
+ return;
+
+ sdhci_s3c_set_clock(host, clock);
+
+ clk_set_rate(ourhost->clk_bus[ourhost->cur_clk], clock);
+
+ host->clock = clock;
+}
+
static struct sdhci_ops sdhci_s3c_ops = {
.get_max_clock = sdhci_s3c_get_max_clk,
.set_clock = sdhci_s3c_set_clock,
@@ -361,6 +406,13 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
clks++;
sc->clk_bus[ptr] = clk;
+
+ /*
+ * save current clock index to know which clock bus
+ * is used later in overriding functions.
+ */
+ sc->cur_clk = ptr;
+
clk_enable(clk);
dev_info(dev, "clock source %d: %s (%ld Hz)\n",
@@ -427,6 +479,16 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
/* HSMMC on Samsung SoCs uses SDCLK as timeout clock */
host->quirks |= SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK;
+ /*
+ * If controller does not have internal clock divider,
+ * we can use overriding functions instead of default.
+ */
+ if (pdata->clk_type) {
+ sdhci_s3c_ops.set_clock = sdhci_cmu_set_clock;
+ sdhci_s3c_ops.get_min_clock = sdhci_cmu_get_min_clock;
+ sdhci_s3c_ops.get_max_clock = sdhci_cmu_get_max_clock;
+ }
+
/* It supports additional host capabilities if needed */
if (pdata->host_caps)
host->mmc->caps |= pdata->host_caps;
--
1.6.2.5
^ permalink raw reply related
* [PATCH RESEND 1/2] sdhci-s3c: Add support additional host capabilities
From: Kukjin Kim @ 2010-10-08 8:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1286527581-24903-1-git-send-email-kgene.kim@samsung.com>
From: Jeongbae Seo <jeongbae.seo@samsung.com>
This patch adds to support additional host capabilities like SD/MMC high speed, SDHCI bus width and
etc.
Signed-off-by: Jeongbae Seo <jeongbae.seo@samsung.com>
Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
---
drivers/mmc/host/sdhci-s3c.c | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c
index aacb862..a7710f5 100644
--- a/drivers/mmc/host/sdhci-s3c.c
+++ b/drivers/mmc/host/sdhci-s3c.c
@@ -427,6 +427,10 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
/* HSMMC on Samsung SoCs uses SDCLK as timeout clock */
host->quirks |= SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK;
+ /* It supports additional host capabilities if needed */
+ if (pdata->host_caps)
+ host->mmc->caps |= pdata->host_caps;
+
ret = sdhci_add_host(host);
if (ret) {
dev_err(dev, "sdhci_add_host() failed\n");
--
1.6.2.5
^ permalink raw reply related
* [PATCH 0/2] sdhci-s3c: Add support S5PV310/S5PC210 HSMMC
From: Kukjin Kim @ 2010-10-08 8:46 UTC (permalink / raw)
To: linux-arm-kernel
This patch adds support S5PV310/S5PC210 HSMMC and additional host capabilities.
HSMMC of S5PV310 does not have internal clock divider so need to update for it.
Changes since v2:
- Changed clock control method to overriding from using quirk
- This patch is referred from that of Jaehoon Chung's support non-standard clock setting
Changes since v1:
- Separated to each topic
NOTE:
- This patch depends on following.
[PATCH 4/5] ARM: SAMSUNG : Add clock types into platform data
This includes following.
[PATCH RESEND 1/2] sdhci-s3c: Add support additional host capabilities
[PATCH V3 2/2] sdhci-s3c: Add support no internal clock divider in host controller
^ permalink raw reply
* [PATCH 0/2] sdhci-s3c: Add support S5PV310/S5PC210 HSMMC
From: Kukjin Kim @ 2010-10-08 8:46 UTC (permalink / raw)
To: linux-arm-kernel, linux-samsung-soc, linux-mmc; +Cc: ben-linux, akpm, cjb
This patch adds support S5PV310/S5PC210 HSMMC and additional host capabilities.
HSMMC of S5PV310 does not have internal clock divider so need to update for it.
Changes since v2:
- Changed clock control method to overriding from using quirk
- This patch is referred from that of Jaehoon Chung's support non-standard clock setting
Changes since v1:
- Separated to each topic
NOTE:
- This patch depends on following.
[PATCH 4/5] ARM: SAMSUNG : Add clock types into platform data
This includes following.
[PATCH RESEND 1/2] sdhci-s3c: Add support additional host capabilities
[PATCH V3 2/2] sdhci-s3c: Add support no internal clock divider in host controller
^ permalink raw reply
* Re: [PATCH 0/9] [GIT PULL] tracing: updates for 2.6.37
From: Ingo Molnar @ 2010-10-08 8:45 UTC (permalink / raw)
To: Steven Rostedt; +Cc: linux-kernel, Andrew Morton, Frederic Weisbecker
In-Reply-To: <20101008081655.GC13754@elte.hu>
[-- Attachment #1: Type: text/plain, Size: 365 bytes --]
hm, i'm getting:
arch/x86/kernel/alternative.c: Assembler messages:
arch/x86/kernel/alternative.c:674: Error: symbol `ftrace_test_jmp' is already defined
arch/x86/kernel/alternative.c:678: Error: symbol `ftrace_test_p6nop' is already defined
arch/x86/kernel/alternative.c:680: Error: symbol `ftrace_test_nop5' is already defined
Config attached.
Thanks,
Ingo
[-- Attachment #2: config --]
[-- Type: text/plain, Size: 41169 bytes --]
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.36-rc7
# Fri Oct 8 11:58:59 2010
#
CONFIG_64BIT=y
# CONFIG_X86_32 is not set
CONFIG_X86_64=y
CONFIG_X86=y
CONFIG_INSTRUCTION_DECODER=y
CONFIG_OUTPUT_FORMAT="elf64-x86-64"
CONFIG_ARCH_DEFCONFIG="arch/x86/configs/x86_64_defconfig"
CONFIG_GENERIC_CMOS_UPDATE=y
CONFIG_CLOCKSOURCE_WATCHDOG=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
CONFIG_MMU=y
CONFIG_ZONE_DMA=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NEED_SG_DMA_LENGTH=y
CONFIG_GENERIC_ISA_DMA=y
CONFIG_GENERIC_IOMAP=y
CONFIG_GENERIC_BUG=y
CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_ARCH_MAY_HAVE_PC_FDC=y
# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_ARCH_HAS_CPU_RELAX=y
CONFIG_ARCH_HAS_DEFAULT_IDLE=y
CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y
CONFIG_HAVE_SETUP_PER_CPU_AREA=y
CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y
CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
CONFIG_HAVE_CPUMASK_OF_CPU_MAP=y
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_ZONE_DMA32=y
CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_AUDIT_ARCH=y
CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_USE_GENERIC_SMP_HELPERS=y
CONFIG_X86_64_SMP=y
CONFIG_X86_HT=y
CONFIG_X86_TRAMPOLINE=y
CONFIG_ARCH_HWEIGHT_CFLAGS="-fcall-saved-rdi -fcall-saved-rsi -fcall-saved-rdx -fcall-saved-rcx -fcall-saved-r8 -fcall-saved-r9 -fcall-saved-r10 -fcall-saved-r11"
# CONFIG_KTIME_SCALAR is not set
# CONFIG_BOOTPARAM_SUPPORT_NOT_WANTED is not set
CONFIG_BOOTPARAM_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
CONFIG_CONSTRUCTORS=y
#
# General setup
#
CONFIG_EXPERIMENTAL=y
CONFIG_BROKEN_BOOT_ALLOWED4=y
CONFIG_BROKEN_BOOT_ALLOWED3=y
CONFIG_BROKEN_BOOT_ALLOWED2=y
# CONFIG_BROKEN_BOOT_DISALLOWED is not set
CONFIG_BROKEN_BOOT_ALLOWED=y
CONFIG_BROKEN_BOOT=y
CONFIG_BROKEN_BOOT_EUROPE=y
CONFIG_BROKEN_BOOT_TITAN=y
CONFIG_LOCK_KERNEL=y
CONFIG_INIT_ENV_ARG_LIMIT=32
CONFIG_CROSS_COMPILE=""
CONFIG_LOCALVERSION=""
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_HAVE_KERNEL_GZIP=y
CONFIG_HAVE_KERNEL_BZIP2=y
CONFIG_HAVE_KERNEL_LZMA=y
CONFIG_HAVE_KERNEL_LZO=y
CONFIG_KERNEL_GZIP=y
# CONFIG_KERNEL_BZIP2 is not set
# CONFIG_KERNEL_LZMA is not set
# CONFIG_KERNEL_LZO is not set
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_HAVE_GENERIC_HARDIRQS=y
#
# IRQ subsystem
#
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_GENERIC_HARDIRQS_NO_DEPRECATED is not set
CONFIG_HAVE_SPARSE_IRQ=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_GENERIC_PENDING_IRQ=y
# CONFIG_AUTO_IRQ_AFFINITY is not set
# CONFIG_IRQ_PER_CPU is not set
# CONFIG_HARDIRQS_SW_RESEND is not set
# CONFIG_SPARSE_IRQ is not set
#
# RCU Subsystem
#
CONFIG_TREE_PREEMPT_RCU=y
CONFIG_PREEMPT_RCU=y
# CONFIG_RCU_TRACE is not set
CONFIG_RCU_FANOUT=64
# CONFIG_RCU_FANOUT_EXACT is not set
# CONFIG_TREE_RCU_TRACE is not set
CONFIG_IKCONFIG=y
CONFIG_LOG_BUF_SHIFT=20
CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y
# CONFIG_CGROUPS is not set
# CONFIG_RELAY is not set
CONFIG_NAMESPACES=y
CONFIG_UTS_NS=y
CONFIG_IPC_NS=y
CONFIG_USER_NS=y
# CONFIG_PID_NS is not set
# CONFIG_BLK_DEV_INITRD is not set
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_ANON_INODES=y
CONFIG_EMBEDDED=y
# CONFIG_UID16 is not set
CONFIG_KALLSYMS=y
CONFIG_KALLSYMS_ALL=y
CONFIG_KALLSYMS_EXTRA_PASS=y
CONFIG_HOTPLUG=y
# CONFIG_PRINTK is not set
CONFIG_BUG=y
CONFIG_ELF_CORE=y
# CONFIG_PCSPKR_PLATFORM is not set
# CONFIG_BASE_FULL is not set
CONFIG_FUTEX=y
# CONFIG_EPOLL is not set
# CONFIG_SIGNALFD is not set
# CONFIG_TIMERFD is not set
CONFIG_EVENTFD=y
# CONFIG_SHMEM is not set
# CONFIG_AIO is not set
CONFIG_HAVE_PERF_EVENTS=y
CONFIG_PERF_USE_VMALLOC=y
#
# Kernel Performance Events And Counters
#
CONFIG_PERF_EVENTS=y
# CONFIG_PERF_COUNTERS is not set
CONFIG_DEBUG_PERF_USE_VMALLOC=y
CONFIG_VM_EVENT_COUNTERS=y
# CONFIG_PCI_QUIRKS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
# CONFIG_SLOB is not set
# CONFIG_PROFILING is not set
CONFIG_HAVE_OPROFILE=y
CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
CONFIG_USER_RETURN_NOTIFIER=y
CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_OPTPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
CONFIG_HAVE_DMA_ATTRS=y
CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
CONFIG_HAVE_DMA_API_DEBUG=y
CONFIG_HAVE_HW_BREAKPOINT=y
CONFIG_HAVE_MIXED_BREAKPOINTS_REGS=y
CONFIG_HAVE_USER_RETURN_NOTIFIER=y
CONFIG_HAVE_PERF_EVENTS_NMI=y
CONFIG_HAVE_ARCH_JUMP_LABEL=y
#
# GCOV-based kernel profiling
#
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_RT_MUTEXES=y
CONFIG_BASE_SMALL=1
# CONFIG_MODULES is not set
CONFIG_BLOCK=y
CONFIG_BLK_DEV_BSG=y
# CONFIG_BLK_DEV_INTEGRITY is not set
CONFIG_BLOCK_COMPAT=y
#
# IO Schedulers
#
CONFIG_IOSCHED_NOOP=y
# CONFIG_IOSCHED_DEADLINE is not set
CONFIG_IOSCHED_CFQ=y
# CONFIG_DEFAULT_CFQ is not set
CONFIG_DEFAULT_NOOP=y
CONFIG_DEFAULT_IOSCHED="noop"
CONFIG_PREEMPT_NOTIFIERS=y
# CONFIG_INLINE_SPIN_TRYLOCK is not set
# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
# CONFIG_INLINE_SPIN_LOCK is not set
# CONFIG_INLINE_SPIN_LOCK_BH is not set
# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
# CONFIG_INLINE_SPIN_UNLOCK is not set
# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set
# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
# CONFIG_INLINE_READ_TRYLOCK is not set
# CONFIG_INLINE_READ_LOCK is not set
# CONFIG_INLINE_READ_LOCK_BH is not set
# CONFIG_INLINE_READ_LOCK_IRQ is not set
# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
# CONFIG_INLINE_READ_UNLOCK is not set
# CONFIG_INLINE_READ_UNLOCK_BH is not set
# CONFIG_INLINE_READ_UNLOCK_IRQ is not set
# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
# CONFIG_INLINE_WRITE_TRYLOCK is not set
# CONFIG_INLINE_WRITE_LOCK is not set
# CONFIG_INLINE_WRITE_LOCK_BH is not set
# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
# CONFIG_INLINE_WRITE_UNLOCK is not set
# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set
# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
# CONFIG_MUTEX_SPIN_ON_OWNER is not set
# CONFIG_FREEZER is not set
#
# Processor type and features
#
# CONFIG_NO_HZ is not set
CONFIG_BOOTPARAM_NO_HZ_OFF=y
# CONFIG_HIGH_RES_TIMERS is not set
CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
# CONFIG_BOOTPARAM_HIGHRES_OFF is not set
CONFIG_SMP_SUPPORT=y
CONFIG_X86_MPPARSE=y
CONFIG_X86_EXTENDED_PLATFORM=y
# CONFIG_X86_VSMP is not set
CONFIG_SCHED_OMIT_FRAME_POINTER=y
# CONFIG_PARAVIRT_GUEST is not set
CONFIG_NO_BOOTMEM=y
# CONFIG_MEMTEST is not set
# CONFIG_MK8 is not set
# CONFIG_MPSC is not set
# CONFIG_MCORE2 is not set
# CONFIG_MATOM is not set
CONFIG_GENERIC_CPU=y
CONFIG_X86_CPU=y
CONFIG_X86_INTERNODE_CACHE_SHIFT=7
CONFIG_X86_CMPXCHG=y
CONFIG_X86_L1_CACHE_SHIFT=6
CONFIG_X86_XADD=y
CONFIG_X86_WP_WORKS_OK=y
CONFIG_X86_TSC=y
CONFIG_X86_CMPXCHG64=y
CONFIG_X86_CMOV=y
CONFIG_X86_MINIMUM_CPU_FAMILY=64
CONFIG_X86_DEBUGCTLMSR=y
CONFIG_PROCESSOR_SELECT=y
# CONFIG_CPU_SUP_INTEL is not set
CONFIG_CPU_SUP_AMD=y
CONFIG_CPU_SUP_CENTAUR=y
CONFIG_HPET_TIMER=y
# CONFIG_DMI is not set
# CONFIG_GART_IOMMU is not set
CONFIG_CALGARY_IOMMU=y
CONFIG_CALGARY_IOMMU_ENABLED_BY_DEFAULT=y
CONFIG_SWIOTLB=y
CONFIG_IOMMU_HELPER=y
# CONFIG_IOMMU_API is not set
# CONFIG_MAXSMP is not set
CONFIG_NR_CPUS=8
CONFIG_SCHED_SMT=y
CONFIG_SCHED_MC=y
# CONFIG_PREEMPT_NONE is not set
# CONFIG_PREEMPT_VOLUNTARY is not set
CONFIG_PREEMPT=y
CONFIG_X86_LOCAL_APIC=y
CONFIG_X86_IO_APIC=y
# CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS is not set
# CONFIG_X86_MCE is not set
CONFIG_I8K=y
CONFIG_MICROCODE=y
# CONFIG_MICROCODE_INTEL is not set
# CONFIG_MICROCODE_AMD is not set
CONFIG_MICROCODE_OLD_INTERFACE=y
# CONFIG_X86_MSR is not set
# CONFIG_X86_CPUID is not set
# CONFIG_UP_WANTED_1 is not set
CONFIG_SMP=y
CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
# CONFIG_DIRECT_GBPAGES is not set
CONFIG_NUMA=y
CONFIG_K8_NUMA=y
# CONFIG_NUMA_EMU is not set
CONFIG_NODES_SHIFT=6
CONFIG_ARCH_SPARSEMEM_DEFAULT=y
CONFIG_ARCH_SPARSEMEM_ENABLE=y
CONFIG_ARCH_SELECT_MEMORY_MODEL=y
CONFIG_ARCH_MEMORY_PROBE=y
CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_SPARSEMEM_MANUAL=y
CONFIG_SPARSEMEM=y
CONFIG_NEED_MULTIPLE_NODES=y
CONFIG_HAVE_MEMORY_PRESENT=y
CONFIG_SPARSEMEM_EXTREME=y
CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
CONFIG_SPARSEMEM_ALLOC_MEM_MAP_TOGETHER=y
# CONFIG_SPARSEMEM_VMEMMAP is not set
CONFIG_HAVE_MEMBLOCK=y
CONFIG_MEMORY_HOTPLUG=y
CONFIG_MEMORY_HOTPLUG_SPARSE=y
# CONFIG_MEMORY_HOTREMOVE is not set
CONFIG_PAGEFLAGS_EXTENDED=y
CONFIG_SPLIT_PTLOCK_CPUS=999999
CONFIG_MIGRATION=y
CONFIG_PHYS_ADDR_T_64BIT=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
CONFIG_MMU_NOTIFIER=y
CONFIG_KSM=y
CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_X86_CHECK_BIOS_CORRUPTION=y
# CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK is not set
CONFIG_X86_RESERVE_LOW=64
CONFIG_MTRR=y
# CONFIG_MTRR_SANITIZER is not set
CONFIG_X86_PAT=y
CONFIG_ARCH_USES_PG_UNCACHED=y
CONFIG_SECCOMP=y
CONFIG_CC_STACKPROTECTOR=y
# CONFIG_HZ_100 is not set
CONFIG_HZ_250=y
# CONFIG_HZ_300 is not set
# CONFIG_HZ_1000 is not set
CONFIG_HZ=250
# CONFIG_SCHED_HRTICK is not set
# CONFIG_KEXEC is not set
CONFIG_CRASH_DUMP=y
CONFIG_PHYSICAL_START=0x1000000
CONFIG_RELOCATABLE=y
CONFIG_PHYSICAL_ALIGN=0x1000000
# CONFIG_HOTPLUG_CPU is not set
# CONFIG_COMPAT_VDSO is not set
# CONFIG_CMDLINE_BOOL is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y
CONFIG_USE_PERCPU_NUMA_NODE_ID=y
#
# Power management and ACPI options
#
# CONFIG_PM is not set
# CONFIG_SFI is not set
#
# CPU Frequency scaling
#
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_TABLE=y
CONFIG_CPU_FREQ_DEBUG=y
# CONFIG_CPU_FREQ_STAT is not set
# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
#
# CPUFreq processor drivers
#
CONFIG_X86_P4_CLOCKMOD=y
#
# shared options
#
CONFIG_X86_SPEEDSTEP_LIB=y
# CONFIG_CPU_IDLE is not set
#
# Memory power savings
#
# CONFIG_I7300_IDLE is not set
#
# Bus options (PCI etc.)
#
CONFIG_PCI=y
CONFIG_PCI_DIRECT=y
CONFIG_PCI_DOMAINS=y
CONFIG_PCI_CNB20LE_QUIRK=y
CONFIG_PCIEPORTBUS=y
CONFIG_PCIEAER=y
CONFIG_PCIE_ECRC=y
# CONFIG_PCIEAER_INJECT is not set
# CONFIG_PCIEASPM is not set
CONFIG_ARCH_SUPPORTS_MSI=y
# CONFIG_PCI_MSI is not set
CONFIG_PCI_DEBUG=y
CONFIG_PCI_STUB=y
# CONFIG_HT_IRQ is not set
CONFIG_PCI_IOV=y
CONFIG_ISA_DMA_API=y
CONFIG_AMD_NB=y
# CONFIG_PCCARD is not set
CONFIG_BOOTPARAM_NMI_WATCHDOG_BIT_0=y
CONFIG_BOOTPARAM_NMI_WATCHDOG_BIT_1=y
CONFIG_BOOTPARAM_NOLAPIC_TIMER=y
CONFIG_BOOTPARAM_LAPIC=y
CONFIG_BOOTPARAM_HPET_DISABLE=y
CONFIG_BOOTPARAM_IDLE_MWAIT=y
CONFIG_BOOTPARAM_IDLE_POLL=y
# CONFIG_BOOTPARAM_HIGHMEM_512M is not set
# CONFIG_BOOTPARAM_NOPAT is not set
CONFIG_BOOTPARAM_NOTSC=y
# CONFIG_BOOTPARAM_ACPI_OFF is not set
# CONFIG_BOOTPARAM_PCI_NOACPI is not set
# CONFIG_BOOTPARAM_PCI_NOMSI is not set
#
# Executable file formats / Emulations
#
CONFIG_BINFMT_ELF=y
CONFIG_COMPAT_BINFMT_ELF=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
# CONFIG_HAVE_AOUT is not set
# CONFIG_BINFMT_MISC is not set
CONFIG_IA32_EMULATION=y
# CONFIG_IA32_AOUT is not set
CONFIG_COMPAT=y
CONFIG_COMPAT_FOR_U64_ALIGNMENT=y
CONFIG_SYSVIPC_COMPAT=y
# CONFIG_NET is not set
#
# Device Drivers
#
#
# Generic Driver Options
#
CONFIG_UEVENT_HELPER_PATH=""
CONFIG_DEVTMPFS=y
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
CONFIG_FW_LOADER=y
CONFIG_FIRMWARE_IN_KERNEL=y
CONFIG_EXTRA_FIRMWARE=""
CONFIG_DEBUG_DRIVER=y
# CONFIG_DEBUG_DEVRES is not set
# CONFIG_SYS_HYPERVISOR is not set
# CONFIG_MTD is not set
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
CONFIG_BLK_DEV_FD=y
CONFIG_BLK_CPQ_DA=y
# CONFIG_BLK_CPQ_CISS_DA is not set
CONFIG_BLK_DEV_DAC960=y
# CONFIG_BLK_DEV_UMEM is not set
# CONFIG_BLK_DEV_COW_COMMON is not set
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_CRYPTOLOOP=y
#
# DRBD disabled because PROC_FS, INET or CONNECTOR not selected
#
CONFIG_BLK_DEV_SX8=y
CONFIG_BLK_DEV_UB=y
# CONFIG_BLK_DEV_RAM is not set
CONFIG_CDROM_PKTCDVD=y
CONFIG_CDROM_PKTCDVD_BUFFERS=8
CONFIG_CDROM_PKTCDVD_WCACHE=y
CONFIG_VIRTIO_BLK=y
# CONFIG_BLK_DEV_HD is not set
# CONFIG_MISC_DEVICES is not set
CONFIG_CB710_CORE=y
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
#
# SCSI device support
#
CONFIG_SCSI_MOD=y
CONFIG_RAID_ATTRS=y
# CONFIG_SCSI is not set
# CONFIG_SCSI_DMA is not set
# CONFIG_SCSI_NETLINK is not set
# CONFIG_ATA is not set
CONFIG_MD=y
CONFIG_BLK_DEV_MD=y
CONFIG_MD_AUTODETECT=y
CONFIG_MD_LINEAR=y
# CONFIG_MD_RAID0 is not set
CONFIG_MD_RAID1=y
# CONFIG_MD_RAID10 is not set
# CONFIG_MD_RAID456 is not set
CONFIG_MD_MULTIPATH=y
# CONFIG_MD_FAULTY is not set
# CONFIG_BLK_DEV_DM is not set
# CONFIG_FUSION is not set
#
# IEEE 1394 (FireWire) support
#
#
# You can enable one or both FireWire driver stacks.
#
#
# The newer stack is recommended.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_FIREWIRE_NOSY is not set
# CONFIG_I2O is not set
CONFIG_MACINTOSH_DRIVERS=y
# CONFIG_PHONE is not set
#
# Input device support
#
CONFIG_INPUT=y
CONFIG_INPUT_FF_MEMLESS=y
CONFIG_INPUT_POLLDEV=y
# CONFIG_INPUT_SPARSEKMAP is not set
#
# Userland interfaces
#
CONFIG_INPUT_MOUSEDEV=y
# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
CONFIG_INPUT_JOYDEV=y
# CONFIG_INPUT_EVDEV is not set
CONFIG_INPUT_EVBUG=y
#
# Input Device Drivers
#
CONFIG_INPUT_KEYBOARD=y
CONFIG_KEYBOARD_ATKBD=y
CONFIG_KEYBOARD_LKKBD=y
# CONFIG_KEYBOARD_NEWTON is not set
# CONFIG_KEYBOARD_OPENCORES is not set
CONFIG_KEYBOARD_STOWAWAY=y
# CONFIG_KEYBOARD_SUNKBD is not set
CONFIG_KEYBOARD_XTKBD=y
CONFIG_INPUT_MOUSE=y
# CONFIG_MOUSE_PS2 is not set
# CONFIG_MOUSE_SERIAL is not set
CONFIG_MOUSE_APPLETOUCH=y
# CONFIG_MOUSE_BCM5974 is not set
# CONFIG_MOUSE_VSXXXAA is not set
CONFIG_INPUT_JOYSTICK=y
CONFIG_JOYSTICK_ANALOG=y
# CONFIG_JOYSTICK_A3D is not set
# CONFIG_JOYSTICK_ADI is not set
CONFIG_JOYSTICK_COBRA=y
CONFIG_JOYSTICK_GF2K=y
# CONFIG_JOYSTICK_GRIP is not set
# CONFIG_JOYSTICK_GRIP_MP is not set
# CONFIG_JOYSTICK_GUILLEMOT is not set
# CONFIG_JOYSTICK_INTERACT is not set
CONFIG_JOYSTICK_SIDEWINDER=y
CONFIG_JOYSTICK_TMDC=y
CONFIG_JOYSTICK_IFORCE=y
CONFIG_JOYSTICK_IFORCE_USB=y
# CONFIG_JOYSTICK_IFORCE_232 is not set
# CONFIG_JOYSTICK_WARRIOR is not set
CONFIG_JOYSTICK_MAGELLAN=y
CONFIG_JOYSTICK_SPACEORB=y
# CONFIG_JOYSTICK_SPACEBALL is not set
# CONFIG_JOYSTICK_STINGER is not set
# CONFIG_JOYSTICK_TWIDJOY is not set
# CONFIG_JOYSTICK_ZHENHUA is not set
CONFIG_JOYSTICK_JOYDUMP=y
CONFIG_JOYSTICK_XPAD=y
# CONFIG_JOYSTICK_XPAD_FF is not set
# CONFIG_JOYSTICK_XPAD_LEDS is not set
# CONFIG_INPUT_TABLET is not set
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_AD7879=y
CONFIG_TOUCHSCREEN_DYNAPRO=y
CONFIG_TOUCHSCREEN_HAMPSHIRE=y
CONFIG_TOUCHSCREEN_FUJITSU=y
CONFIG_TOUCHSCREEN_GUNZE=y
CONFIG_TOUCHSCREEN_ELO=y
CONFIG_TOUCHSCREEN_WACOM_W8001=y
# CONFIG_TOUCHSCREEN_MTOUCH is not set
# CONFIG_TOUCHSCREEN_INEXIO is not set
# CONFIG_TOUCHSCREEN_MK712 is not set
# CONFIG_TOUCHSCREEN_PENMOUNT is not set
# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
CONFIG_TOUCHSCREEN_TOUCHWIN=y
# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
CONFIG_TOUCHSCREEN_TOUCHIT213=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_AD714X=y
# CONFIG_INPUT_ATI_REMOTE is not set
CONFIG_INPUT_ATI_REMOTE2=y
# CONFIG_INPUT_KEYSPAN_REMOTE is not set
CONFIG_INPUT_POWERMATE=y
# CONFIG_INPUT_YEALINK is not set
CONFIG_INPUT_CM109=y
# CONFIG_INPUT_UINPUT is not set
# CONFIG_INPUT_ADXL34X is not set
#
# Hardware I/O ports
#
CONFIG_SERIO=y
CONFIG_SERIO_I8042=y
# CONFIG_SERIO_SERPORT is not set
# CONFIG_SERIO_CT82C710 is not set
# CONFIG_SERIO_PCIPS2 is not set
CONFIG_SERIO_LIBPS2=y
# CONFIG_SERIO_RAW is not set
# CONFIG_SERIO_ALTERA_PS2 is not set
CONFIG_GAMEPORT=y
# CONFIG_GAMEPORT_NS558 is not set
CONFIG_GAMEPORT_L4=y
CONFIG_GAMEPORT_EMU10K1=y
CONFIG_GAMEPORT_FM801=y
#
# Character devices
#
CONFIG_VT=y
# CONFIG_CONSOLE_TRANSLATIONS is not set
# CONFIG_VT_CONSOLE is not set
CONFIG_HW_CONSOLE=y
# CONFIG_VT_HW_CONSOLE_BINDING is not set
# CONFIG_DEVKMEM is not set
# CONFIG_SERIAL_NONSTANDARD is not set
CONFIG_NOZOMI=y
#
# Serial drivers
#
CONFIG_SERIAL_8250=y
# CONFIG_SERIAL_8250_CONSOLE is not set
CONFIG_FIX_EARLYCON_MEM=y
CONFIG_SERIAL_8250_PCI=y
CONFIG_SERIAL_8250_NR_UARTS=4
CONFIG_SERIAL_8250_RUNTIME_UARTS=4
# CONFIG_SERIAL_8250_EXTENDED is not set
#
# Non-8250 serial port support
#
CONFIG_SERIAL_MFD_HSU=y
# CONFIG_SERIAL_MFD_HSU_CONSOLE is not set
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_CONSOLE_POLL=y
CONFIG_SERIAL_JSM=y
CONFIG_SERIAL_TIMBERDALE=y
# CONFIG_SERIAL_ALTERA_JTAGUART is not set
CONFIG_SERIAL_ALTERA_UART=y
CONFIG_SERIAL_ALTERA_UART_MAXPORTS=4
CONFIG_SERIAL_ALTERA_UART_BAUDRATE=115200
CONFIG_SERIAL_ALTERA_UART_CONSOLE=y
# CONFIG_UNIX98_PTYS is not set
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
# CONFIG_VIRTIO_CONSOLE is not set
# CONFIG_IPMI_HANDLER is not set
CONFIG_HW_RANDOM=y
# CONFIG_HW_RANDOM_TIMERIOMEM is not set
# CONFIG_HW_RANDOM_INTEL is not set
CONFIG_HW_RANDOM_AMD=y
# CONFIG_HW_RANDOM_VIA is not set
# CONFIG_HW_RANDOM_VIRTIO is not set
# CONFIG_NVRAM is not set
# CONFIG_R3964 is not set
CONFIG_APPLICOM=y
# CONFIG_MWAVE is not set
CONFIG_RAW_DRIVER=y
CONFIG_MAX_RAW_DEVS=256
CONFIG_HANGCHECK_TIMER=y
CONFIG_TCG_TPM=y
# CONFIG_TCG_TIS is not set
# CONFIG_TCG_NSC is not set
# CONFIG_TCG_ATMEL is not set
# CONFIG_TELCLOCK is not set
CONFIG_DEVPORT=y
CONFIG_RAMOOPS=y
# CONFIG_I2C is not set
# CONFIG_SPI is not set
#
# PPS support
#
CONFIG_PPS=y
# CONFIG_PPS_DEBUG is not set
#
# PPS clients support
#
CONFIG_PPS_CLIENT_KTIMER=y
CONFIG_PPS_CLIENT_LDISC=y
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
# CONFIG_POWER_SUPPLY is not set
CONFIG_HWMON=y
CONFIG_HWMON_VID=y
CONFIG_HWMON_DEBUG_CHIP=y
#
# Native drivers
#
CONFIG_SENSORS_ABITUGURU=y
CONFIG_SENSORS_ABITUGURU3=y
CONFIG_SENSORS_K8TEMP=y
CONFIG_SENSORS_K10TEMP=y
CONFIG_SENSORS_I5K_AMB=y
CONFIG_SENSORS_F71805F=y
CONFIG_SENSORS_F71882FG=y
CONFIG_SENSORS_CORETEMP=y
CONFIG_SENSORS_PKGTEMP=y
CONFIG_SENSORS_IT87=y
# CONFIG_SENSORS_PC87360 is not set
# CONFIG_SENSORS_PC87427 is not set
# CONFIG_SENSORS_SIS5595 is not set
# CONFIG_SENSORS_SMSC47M1 is not set
# CONFIG_SENSORS_SMSC47B397 is not set
CONFIG_SENSORS_VIA_CPUTEMP=y
CONFIG_SENSORS_VIA686A=y
CONFIG_SENSORS_VT1211=y
CONFIG_SENSORS_VT8231=y
CONFIG_SENSORS_HDAPS=y
CONFIG_SENSORS_APPLESMC=y
# CONFIG_THERMAL is not set
CONFIG_WATCHDOG=y
CONFIG_WATCHDOG_NOWAYOUT=y
#
# Watchdog Device Drivers
#
CONFIG_SOFT_WATCHDOG=y
# CONFIG_ACQUIRE_WDT is not set
# CONFIG_ADVANTECH_WDT is not set
# CONFIG_ALIM1535_WDT is not set
CONFIG_ALIM7101_WDT=y
# CONFIG_F71808E_WDT is not set
# CONFIG_SC520_WDT is not set
# CONFIG_EUROTECH_WDT is not set
# CONFIG_IB700_WDT is not set
# CONFIG_IBMASR is not set
# CONFIG_WAFER_WDT is not set
# CONFIG_I6300ESB_WDT is not set
# CONFIG_ITCO_WDT is not set
CONFIG_IT8712F_WDT=y
# CONFIG_IT87_WDT is not set
# CONFIG_HP_WATCHDOG is not set
# CONFIG_SC1200_WDT is not set
CONFIG_PC87413_WDT=y
# CONFIG_60XX_WDT is not set
# CONFIG_SBC8360_WDT is not set
# CONFIG_CPU5_WDT is not set
CONFIG_SMSC_SCH311X_WDT=y
# CONFIG_SMSC37B787_WDT is not set
# CONFIG_W83627HF_WDT is not set
CONFIG_W83877F_WDT=y
CONFIG_W83977F_WDT=y
CONFIG_MACHZ_WDT=y
# CONFIG_SBC_EPX_C3_WATCHDOG is not set
#
# PCI-based Watchdog Cards
#
CONFIG_PCIPCWATCHDOG=y
CONFIG_WDTPCI=y
#
# USB-based Watchdog Cards
#
# CONFIG_USBPCWATCHDOG is not set
CONFIG_SSB_POSSIBLE=y
#
# Sonics Silicon Backplane
#
CONFIG_SSB=y
CONFIG_SSB_PCIHOST_POSSIBLE=y
# CONFIG_SSB_PCIHOST is not set
CONFIG_SSB_SDIOHOST_POSSIBLE=y
# CONFIG_SSB_SDIOHOST is not set
CONFIG_SSB_SILENT=y
# CONFIG_MFD_SUPPORT is not set
# CONFIG_REGULATOR is not set
CONFIG_MEDIA_SUPPORT=y
#
# Multimedia core support
#
CONFIG_VIDEO_DEV=y
CONFIG_VIDEO_V4L2_COMMON=y
# CONFIG_VIDEO_ALLOW_V4L1 is not set
CONFIG_VIDEO_V4L1_COMPAT=y
CONFIG_VIDEO_MEDIA=y
#
# Multimedia drivers
#
CONFIG_IR_CORE=y
CONFIG_VIDEO_IR=y
CONFIG_LIRC=y
# CONFIG_RC_MAP is not set
# CONFIG_IR_NEC_DECODER is not set
# CONFIG_IR_RC5_DECODER is not set
CONFIG_IR_RC6_DECODER=y
CONFIG_IR_JVC_DECODER=y
# CONFIG_IR_SONY_DECODER is not set
# CONFIG_IR_LIRC_CODEC is not set
CONFIG_IR_IMON=y
# CONFIG_IR_MCEUSB is not set
# CONFIG_IR_STREAMZAP is not set
CONFIG_VIDEO_V4L2=y
CONFIG_VIDEOBUF_GEN=y
CONFIG_VIDEOBUF_VMALLOC=y
CONFIG_V4L2_MEM2MEM_DEV=y
CONFIG_VIDEO_CAPTURE_DRIVERS=y
CONFIG_VIDEO_ADV_DEBUG=y
CONFIG_VIDEO_FIXED_MINOR_RANGES=y
# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set
#
# Encoders/decoders and other helper chips
#
#
# Audio decoders
#
#
# RDS decoders
#
#
# Video decoders
#
#
# Video and audio decoders
#
#
# MPEG video encoders
#
CONFIG_VIDEO_CX2341X=y
#
# Video encoders
#
#
# Video improvement chips
#
# CONFIG_VIDEO_VIVI is not set
CONFIG_V4L_USB_DRIVERS=y
# CONFIG_USB_VIDEO_CLASS is not set
CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y
CONFIG_USB_GSPCA=y
CONFIG_USB_M5602=y
# CONFIG_USB_STV06XX is not set
CONFIG_USB_GL860=y
CONFIG_USB_GSPCA_BENQ=y
# CONFIG_USB_GSPCA_CONEX is not set
# CONFIG_USB_GSPCA_CPIA1 is not set
CONFIG_USB_GSPCA_ETOMS=y
CONFIG_USB_GSPCA_FINEPIX=y
# CONFIG_USB_GSPCA_JEILINJ is not set
# CONFIG_USB_GSPCA_MARS is not set
CONFIG_USB_GSPCA_MR97310A=y
CONFIG_USB_GSPCA_OV519=y
# CONFIG_USB_GSPCA_OV534 is not set
CONFIG_USB_GSPCA_OV534_9=y
CONFIG_USB_GSPCA_PAC207=y
# CONFIG_USB_GSPCA_PAC7302 is not set
CONFIG_USB_GSPCA_PAC7311=y
CONFIG_USB_GSPCA_SN9C2028=y
CONFIG_USB_GSPCA_SN9C20X=y
CONFIG_USB_GSPCA_SONIXB=y
# CONFIG_USB_GSPCA_SONIXJ is not set
# CONFIG_USB_GSPCA_SPCA500 is not set
# CONFIG_USB_GSPCA_SPCA501 is not set
CONFIG_USB_GSPCA_SPCA505=y
# CONFIG_USB_GSPCA_SPCA506 is not set
CONFIG_USB_GSPCA_SPCA508=y
# CONFIG_USB_GSPCA_SPCA561 is not set
# CONFIG_USB_GSPCA_SPCA1528 is not set
CONFIG_USB_GSPCA_SQ905=y
CONFIG_USB_GSPCA_SQ905C=y
# CONFIG_USB_GSPCA_SQ930X is not set
CONFIG_USB_GSPCA_STK014=y
CONFIG_USB_GSPCA_STV0680=y
# CONFIG_USB_GSPCA_SUNPLUS is not set
CONFIG_USB_GSPCA_T613=y
# CONFIG_USB_GSPCA_TV8532 is not set
CONFIG_USB_GSPCA_VC032X=y
CONFIG_USB_GSPCA_ZC3XX=y
CONFIG_VIDEO_HDPVR=y
CONFIG_USB_ET61X251=y
# CONFIG_USB_SN9C102 is not set
CONFIG_USB_ZR364XX=y
# CONFIG_USB_STKWEBCAM is not set
# CONFIG_USB_S2255 is not set
CONFIG_V4L_MEM2MEM_DRIVERS=y
CONFIG_VIDEO_MEM2MEM_TESTDEV=y
# CONFIG_RADIO_ADAPTERS is not set
# CONFIG_DAB is not set
#
# Graphics support
#
# CONFIG_AGP is not set
CONFIG_VGA_ARB=y
CONFIG_VGA_ARB_MAX_GPUS=16
# CONFIG_DRM is not set
CONFIG_VGASTATE=y
# CONFIG_VIDEO_OUTPUT_CONTROL is not set
CONFIG_FB=y
# CONFIG_FIRMWARE_EDID is not set
# CONFIG_FB_DDC is not set
# CONFIG_FB_BOOT_VESA_SUPPORT is not set
CONFIG_FB_CFB_FILLRECT=y
CONFIG_FB_CFB_COPYAREA=y
CONFIG_FB_CFB_IMAGEBLIT=y
# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
CONFIG_FB_SYS_FILLRECT=y
CONFIG_FB_SYS_COPYAREA=y
CONFIG_FB_SYS_IMAGEBLIT=y
# CONFIG_FB_FOREIGN_ENDIAN is not set
CONFIG_FB_SYS_FOPS=y
CONFIG_FB_DEFERRED_IO=y
CONFIG_FB_SVGALIB=y
# CONFIG_FB_MACMODES is not set
CONFIG_FB_BACKLIGHT=y
CONFIG_FB_MODE_HELPERS=y
CONFIG_FB_TILEBLITTING=y
#
# Frame buffer hardware drivers
#
# CONFIG_FB_CIRRUS is not set
CONFIG_FB_PM2=y
CONFIG_FB_PM2_FIFO_DISCONNECT=y
CONFIG_FB_CYBER2000=y
# CONFIG_FB_ARC is not set
# CONFIG_FB_ASILIANT is not set
# CONFIG_FB_IMSTT is not set
CONFIG_FB_VGA16=y
# CONFIG_FB_VESA is not set
# CONFIG_FB_N411 is not set
# CONFIG_FB_HGA is not set
# CONFIG_FB_S1D13XXX is not set
CONFIG_FB_NVIDIA=y
# CONFIG_FB_NVIDIA_I2C is not set
# CONFIG_FB_NVIDIA_DEBUG is not set
CONFIG_FB_NVIDIA_BACKLIGHT=y
CONFIG_FB_RIVA=y
# CONFIG_FB_RIVA_I2C is not set
CONFIG_FB_RIVA_DEBUG=y
CONFIG_FB_RIVA_BACKLIGHT=y
# CONFIG_FB_LE80578 is not set
CONFIG_FB_MATROX=y
# CONFIG_FB_MATROX_MILLENIUM is not set
CONFIG_FB_MATROX_MYSTIQUE=y
# CONFIG_FB_MATROX_G is not set
# CONFIG_FB_MATROX_I2C is not set
# CONFIG_FB_RADEON is not set
# CONFIG_FB_ATY128 is not set
# CONFIG_FB_ATY is not set
CONFIG_FB_S3=y
# CONFIG_FB_SAVAGE is not set
# CONFIG_FB_SIS is not set
# CONFIG_FB_VIA is not set
# CONFIG_FB_NEOMAGIC is not set
CONFIG_FB_KYRO=y
# CONFIG_FB_3DFX is not set
CONFIG_FB_VOODOO1=y
# CONFIG_FB_VT8623 is not set
# CONFIG_FB_TRIDENT is not set
# CONFIG_FB_ARK is not set
# CONFIG_FB_PM3 is not set
# CONFIG_FB_CARMINE is not set
CONFIG_FB_GEODE=y
# CONFIG_FB_GEODE_LX is not set
CONFIG_FB_GEODE_GX=y
# CONFIG_FB_GEODE_GX1 is not set
CONFIG_FB_VIRTUAL=y
# CONFIG_FB_METRONOME is not set
# CONFIG_FB_MB862XX is not set
# CONFIG_FB_BROADSHEET is not set
CONFIG_BACKLIGHT_LCD_SUPPORT=y
CONFIG_LCD_CLASS_DEVICE=y
# CONFIG_LCD_PLATFORM is not set
CONFIG_BACKLIGHT_CLASS_DEVICE=y
CONFIG_BACKLIGHT_GENERIC=y
CONFIG_BACKLIGHT_PROGEAR=y
CONFIG_BACKLIGHT_MBP_NVIDIA=y
# CONFIG_BACKLIGHT_SAHARA is not set
#
# Display device support
#
# CONFIG_DISPLAY_SUPPORT is not set
#
# Console display driver support
#
# CONFIG_VGA_CONSOLE is not set
CONFIG_DUMMY_CONSOLE=y
CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
CONFIG_FONTS=y
# CONFIG_FONT_8x8 is not set
CONFIG_FONT_8x16=y
# CONFIG_FONT_6x11 is not set
CONFIG_FONT_7x14=y
# CONFIG_FONT_PEARL_8x8 is not set
# CONFIG_FONT_ACORN_8x8 is not set
CONFIG_FONT_MINI_4x6=y
# CONFIG_FONT_SUN8x16 is not set
CONFIG_FONT_SUN12x22=y
CONFIG_FONT_10x18=y
# CONFIG_LOGO is not set
# CONFIG_SOUND is not set
CONFIG_HID_SUPPORT=y
CONFIG_HID=y
CONFIG_HIDRAW=y
#
# USB Input Devices
#
CONFIG_USB_HID=y
CONFIG_HID_PID=y
CONFIG_USB_HIDDEV=y
#
# Special HID drivers
#
CONFIG_HID_3M_PCT=y
# CONFIG_HID_A4TECH is not set
CONFIG_HID_ACRUX_FF=y
CONFIG_HID_APPLE=y
# CONFIG_HID_BELKIN is not set
# CONFIG_HID_CANDO is not set
CONFIG_HID_CHERRY=y
# CONFIG_HID_CHICONY is not set
CONFIG_HID_CYPRESS=y
# CONFIG_HID_DRAGONRISE is not set
CONFIG_HID_EGALAX=y
CONFIG_HID_EZKEY=y
# CONFIG_HID_KYE is not set
CONFIG_HID_GYRATION=y
CONFIG_HID_TWINHAN=y
# CONFIG_HID_KENSINGTON is not set
CONFIG_HID_LOGITECH=y
CONFIG_LOGITECH_FF=y
# CONFIG_LOGIRUMBLEPAD2_FF is not set
# CONFIG_LOGIG940_FF is not set
CONFIG_HID_MICROSOFT=y
# CONFIG_HID_MOSART is not set
# CONFIG_HID_MONTEREY is not set
# CONFIG_HID_NTRIG is not set
CONFIG_HID_ORTEK=y
CONFIG_HID_PANTHERLORD=y
# CONFIG_PANTHERLORD_FF is not set
CONFIG_HID_PETALYNX=y
CONFIG_HID_PICOLCD=y
CONFIG_HID_PICOLCD_FB=y
# CONFIG_HID_PICOLCD_BACKLIGHT is not set
CONFIG_HID_PICOLCD_LCD=y
# CONFIG_HID_PICOLCD_LEDS is not set
# CONFIG_HID_QUANTA is not set
CONFIG_HID_ROCCAT=y
CONFIG_HID_ROCCAT_KONE=y
CONFIG_HID_SAMSUNG=y
# CONFIG_HID_SONY is not set
# CONFIG_HID_STANTUM is not set
# CONFIG_HID_SUNPLUS is not set
CONFIG_HID_GREENASIA=y
CONFIG_GREENASIA_FF=y
# CONFIG_HID_SMARTJOYPLUS is not set
CONFIG_HID_TOPSEED=y
# CONFIG_HID_THRUSTMASTER is not set
# CONFIG_HID_ZEROPLUS is not set
CONFIG_HID_ZYDACRON=y
CONFIG_USB_SUPPORT=y
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
CONFIG_USB_ARCH_HAS_EHCI=y
CONFIG_USB=y
CONFIG_USB_DEBUG=y
# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
#
# Miscellaneous USB options
#
# CONFIG_USB_DEVICEFS is not set
# CONFIG_USB_DEVICE_CLASS is not set
# CONFIG_USB_DYNAMIC_MINORS is not set
CONFIG_USB_OTG_WHITELIST=y
# CONFIG_USB_OTG_BLACKLIST_HUB is not set
# CONFIG_USB_MON is not set
CONFIG_USB_WUSB=y
# CONFIG_USB_WUSB_CBAF is not set
#
# USB Host Controller Drivers
#
# CONFIG_USB_C67X00_HCD is not set
# CONFIG_USB_XHCI_HCD is not set
CONFIG_USB_EHCI_HCD=y
# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
CONFIG_USB_OXU210HP_HCD=y
CONFIG_USB_ISP116X_HCD=y
CONFIG_USB_ISP1760_HCD=y
# CONFIG_USB_ISP1362_HCD is not set
# CONFIG_USB_OHCI_HCD is not set
CONFIG_USB_UHCI_HCD=y
CONFIG_USB_SL811_HCD=y
CONFIG_USB_R8A66597_HCD=y
CONFIG_USB_HWA_HCD=y
#
# USB Device Class drivers
#
# CONFIG_USB_ACM is not set
CONFIG_USB_PRINTER=y
CONFIG_USB_WDM=y
# CONFIG_USB_TMC is not set
#
# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
#
#
# also be needed; see USB_STORAGE Help for more info
#
CONFIG_USB_LIBUSUAL=y
#
# USB Imaging devices
#
CONFIG_USB_MDC800=y
#
# USB port drivers
#
# CONFIG_USB_SERIAL is not set
#
# USB Miscellaneous drivers
#
CONFIG_USB_EMI62=y
CONFIG_USB_EMI26=y
# CONFIG_USB_ADUTUX is not set
# CONFIG_USB_SEVSEG is not set
# CONFIG_USB_RIO500 is not set
CONFIG_USB_LEGOTOWER=y
# CONFIG_USB_LCD is not set
# CONFIG_USB_LED is not set
CONFIG_USB_CYPRESS_CY7C63=y
# CONFIG_USB_CYTHERM is not set
# CONFIG_USB_IDMOUSE is not set
# CONFIG_USB_FTDI_ELAN is not set
CONFIG_USB_APPLEDISPLAY=y
CONFIG_USB_SISUSBVGA=y
# CONFIG_USB_SISUSBVGA_CON is not set
CONFIG_USB_LD=y
CONFIG_USB_TRANCEVIBRATOR=y
CONFIG_USB_IOWARRIOR=y
# CONFIG_USB_TEST is not set
CONFIG_USB_ISIGHTFW=y
# CONFIG_USB_GADGET is not set
#
# OTG and related infrastructure
#
CONFIG_USB_OTG_UTILS=y
CONFIG_NOP_USB_XCEIV=y
CONFIG_UWB=y
CONFIG_UWB_HWA=y
CONFIG_UWB_WHCI=y
CONFIG_UWB_I1480U=y
CONFIG_MMC=y
CONFIG_MMC_DEBUG=y
CONFIG_MMC_UNSAFE_RESUME=y
#
# MMC/SD/SDIO Card Drivers
#
CONFIG_MMC_BLOCK=y
# CONFIG_MMC_BLOCK_BOUNCE is not set
CONFIG_SDIO_UART=y
# CONFIG_MMC_TEST is not set
#
# MMC/SD/SDIO Host Controller Drivers
#
CONFIG_MMC_SDHCI=y
# CONFIG_MMC_SDHCI_PCI is not set
CONFIG_MMC_SDHCI_PLTFM=y
# CONFIG_MMC_WBSD is not set
# CONFIG_MMC_TIFM_SD is not set
CONFIG_MMC_CB710=y
# CONFIG_MMC_VIA_SDMMC is not set
CONFIG_MEMSTICK=y
CONFIG_MEMSTICK_DEBUG=y
#
# MemoryStick drivers
#
CONFIG_MEMSTICK_UNSAFE_RESUME=y
# CONFIG_MSPRO_BLOCK is not set
#
# MemoryStick Host Controller Drivers
#
# CONFIG_MEMSTICK_TIFM_MS is not set
CONFIG_MEMSTICK_JMICRON_38X=y
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
#
# LED drivers
#
# CONFIG_LEDS_ALIX2 is not set
CONFIG_LEDS_TRIGGERS=y
#
# LED Triggers
#
CONFIG_LEDS_TRIGGER_TIMER=y
# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
CONFIG_LEDS_TRIGGER_BACKLIGHT=y
CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
#
# iptables trigger is under Netfilter config (LED target)
#
# CONFIG_ACCESSIBILITY is not set
CONFIG_INFINIBAND=y
# CONFIG_INFINIBAND_USER_MAD is not set
# CONFIG_INFINIBAND_USER_ACCESS is not set
CONFIG_INFINIBAND_MTHCA=y
CONFIG_INFINIBAND_MTHCA_DEBUG=y
# CONFIG_MLX4_INFINIBAND is not set
# CONFIG_EDAC is not set
CONFIG_RTC_LIB=y
CONFIG_RTC_CLASS=y
# CONFIG_RTC_HCTOSYS is not set
CONFIG_RTC_DEBUG=y
#
# RTC interfaces
#
# CONFIG_RTC_INTF_DEV is not set
CONFIG_RTC_DRV_TEST=y
#
# SPI RTC drivers
#
#
# Platform RTC drivers
#
# CONFIG_RTC_DRV_CMOS is not set
# CONFIG_RTC_DRV_DS1286 is not set
# CONFIG_RTC_DRV_DS1511 is not set
CONFIG_RTC_DRV_DS1553=y
# CONFIG_RTC_DRV_DS1742 is not set
# CONFIG_RTC_DRV_STK17TA8 is not set
# CONFIG_RTC_DRV_M48T86 is not set
# CONFIG_RTC_DRV_M48T35 is not set
CONFIG_RTC_DRV_M48T59=y
# CONFIG_RTC_DRV_MSM6242 is not set
CONFIG_RTC_DRV_BQ4802=y
# CONFIG_RTC_DRV_RP5C01 is not set
# CONFIG_RTC_DRV_V3020 is not set
#
# on-CPU RTC drivers
#
CONFIG_DMADEVICES=y
CONFIG_DMADEVICES_DEBUG=y
CONFIG_DMADEVICES_VDEBUG=y
#
# DMA Devices
#
# CONFIG_INTEL_MID_DMAC is not set
# CONFIG_INTEL_IOATDMA is not set
CONFIG_TIMB_DMA=y
# CONFIG_PCH_DMA is not set
CONFIG_DMA_ENGINE=y
#
# DMA Clients
#
# CONFIG_ASYNC_TX_DMA is not set
# CONFIG_DMATEST is not set
# CONFIG_AUXDISPLAY is not set
CONFIG_UIO=y
# CONFIG_UIO_CIF is not set
# CONFIG_UIO_PDRV is not set
CONFIG_UIO_PDRV_GENIRQ=y
CONFIG_UIO_AEC=y
# CONFIG_UIO_SERCOS3 is not set
# CONFIG_UIO_PCI_GENERIC is not set
# CONFIG_UIO_NETX is not set
# CONFIG_X86_PLATFORM_DEVICES is not set
#
# Firmware Drivers
#
CONFIG_EDD=y
# CONFIG_EDD_OFF is not set
CONFIG_FIRMWARE_MEMMAP=y
CONFIG_DELL_RBU=y
CONFIG_DCDBAS=y
CONFIG_ISCSI_IBFT_FIND=y
#
# File systems
#
# CONFIG_EXT2_FS is not set
# CONFIG_EXT3_FS is not set
CONFIG_EXT4_FS=y
CONFIG_EXT4_USE_FOR_EXT23=y
# CONFIG_EXT4_FS_XATTR is not set
CONFIG_EXT4_DEBUG=y
CONFIG_JBD2=y
CONFIG_REISERFS_FS=y
# CONFIG_REISERFS_CHECK is not set
CONFIG_REISERFS_FS_XATTR=y
CONFIG_REISERFS_FS_POSIX_ACL=y
# CONFIG_REISERFS_FS_SECURITY is not set
CONFIG_JFS_FS=y
CONFIG_JFS_POSIX_ACL=y
# CONFIG_JFS_SECURITY is not set
CONFIG_JFS_DEBUG=y
# CONFIG_JFS_STATISTICS is not set
CONFIG_FS_POSIX_ACL=y
# CONFIG_XFS_FS is not set
CONFIG_GFS2_FS=y
CONFIG_BTRFS_FS=y
CONFIG_BTRFS_FS_POSIX_ACL=y
# CONFIG_NILFS2_FS is not set
CONFIG_FILE_LOCKING=y
# CONFIG_FSNOTIFY is not set
# CONFIG_DNOTIFY is not set
# CONFIG_INOTIFY_USER is not set
# CONFIG_FANOTIFY is not set
# CONFIG_QUOTA is not set
CONFIG_QUOTACTL=y
CONFIG_QUOTACTL_COMPAT=y
CONFIG_AUTOFS_FS=y
CONFIG_AUTOFS4_FS=y
CONFIG_FUSE_FS=y
CONFIG_CUSE=y
#
# Caches
#
CONFIG_FSCACHE=y
CONFIG_FSCACHE_DEBUG=y
CONFIG_CACHEFILES=y
CONFIG_CACHEFILES_DEBUG=y
#
# CD-ROM/DVD Filesystems
#
CONFIG_ISO9660_FS=y
# CONFIG_JOLIET is not set
# CONFIG_ZISOFS is not set
# CONFIG_UDF_FS is not set
#
# DOS/FAT/NT Filesystems
#
# CONFIG_MSDOS_FS is not set
# CONFIG_VFAT_FS is not set
# CONFIG_NTFS_FS is not set
#
# Pseudo filesystems
#
# CONFIG_PROC_FS is not set
# CONFIG_SYSFS is not set
# CONFIG_HUGETLBFS is not set
# CONFIG_HUGETLB_PAGE is not set
# CONFIG_MISC_FILESYSTEMS is not set
#
# Partition Types
#
# CONFIG_PARTITION_ADVANCED is not set
CONFIG_MSDOS_PARTITION=y
CONFIG_NLS=y
CONFIG_NLS_DEFAULT="iso8859-1"
CONFIG_NLS_CODEPAGE_437=y
# CONFIG_NLS_CODEPAGE_737 is not set
# CONFIG_NLS_CODEPAGE_775 is not set
# CONFIG_NLS_CODEPAGE_850 is not set
CONFIG_NLS_CODEPAGE_852=y
CONFIG_NLS_CODEPAGE_855=y
CONFIG_NLS_CODEPAGE_857=y
# CONFIG_NLS_CODEPAGE_860 is not set
CONFIG_NLS_CODEPAGE_861=y
# CONFIG_NLS_CODEPAGE_862 is not set
# CONFIG_NLS_CODEPAGE_863 is not set
# CONFIG_NLS_CODEPAGE_864 is not set
# CONFIG_NLS_CODEPAGE_865 is not set
CONFIG_NLS_CODEPAGE_866=y
# CONFIG_NLS_CODEPAGE_869 is not set
CONFIG_NLS_CODEPAGE_936=y
# CONFIG_NLS_CODEPAGE_950 is not set
# CONFIG_NLS_CODEPAGE_932 is not set
CONFIG_NLS_CODEPAGE_949=y
# CONFIG_NLS_CODEPAGE_874 is not set
CONFIG_NLS_ISO8859_8=y
CONFIG_NLS_CODEPAGE_1250=y
CONFIG_NLS_CODEPAGE_1251=y
CONFIG_NLS_ASCII=y
# CONFIG_NLS_ISO8859_1 is not set
# CONFIG_NLS_ISO8859_2 is not set
CONFIG_NLS_ISO8859_3=y
CONFIG_NLS_ISO8859_4=y
CONFIG_NLS_ISO8859_5=y
CONFIG_NLS_ISO8859_6=y
CONFIG_NLS_ISO8859_7=y
CONFIG_NLS_ISO8859_9=y
# CONFIG_NLS_ISO8859_13 is not set
# CONFIG_NLS_ISO8859_14 is not set
# CONFIG_NLS_ISO8859_15 is not set
# CONFIG_NLS_KOI8_R is not set
CONFIG_NLS_KOI8_U=y
CONFIG_NLS_UTF8=y
#
# Kernel hacking
#
CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_ENABLE_WARN_DEPRECATED is not set
# CONFIG_ENABLE_MUST_CHECK is not set
CONFIG_FRAME_WARN=2048
CONFIG_MAGIC_SYSRQ=y
CONFIG_STRIP_ASM_SYMS=y
# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_DEBUG_FS is not set
CONFIG_HEADERS_CHECK=y
CONFIG_DEBUG_KERNEL=y
# CONFIG_DEBUG_SHIRQ is not set
# CONFIG_LOCKUP_DETECTOR is not set
# CONFIG_HARDLOCKUP_DETECTOR is not set
# CONFIG_DETECT_HUNG_TASK is not set
# CONFIG_DEBUG_OBJECTS is not set
# CONFIG_DEBUG_PREEMPT is not set
# CONFIG_DEBUG_RT_MUTEXES is not set
CONFIG_RT_MUTEX_TESTER=y
CONFIG_DEBUG_SPINLOCK=y
CONFIG_DEBUG_MUTEXES=y
CONFIG_DEBUG_LOCK_ALLOC=y
CONFIG_PROVE_LOCKING=y
# CONFIG_PROVE_RCU is not set
CONFIG_SPARSE_RCU_POINTER=y
CONFIG_LOCKDEP=y
# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_LOCKDEP is not set
CONFIG_TRACE_IRQFLAGS=y
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
CONFIG_DEBUG_LOCKING_API_SELFTESTS=y
CONFIG_STACKTRACE=y
# CONFIG_DEBUG_KOBJECT is not set
# CONFIG_DEBUG_BUGVERBOSE is not set
CONFIG_DEBUG_VM=y
CONFIG_DEBUG_VIRTUAL=y
# CONFIG_DEBUG_WRITECOUNT is not set
# CONFIG_DEBUG_MEMORY_INIT is not set
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
CONFIG_DEBUG_NOTIFIERS=y
# CONFIG_DEBUG_CREDENTIALS is not set
CONFIG_ARCH_WANT_FRAME_POINTERS=y
CONFIG_FRAME_POINTER=y
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
CONFIG_BACKTRACE_SELF_TEST=y
CONFIG_DEBUG_BLOCK_EXT_DEVT=y
# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
# CONFIG_FAULT_INJECTION is not set
CONFIG_USER_STACKTRACE_SUPPORT=y
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST=y
CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
CONFIG_TRACING_SUPPORT=y
# CONFIG_FTRACE is not set
CONFIG_PROVIDE_OHCI1394_DMA_INIT=y
# CONFIG_BUILD_DOCSRC is not set
CONFIG_DMA_API_DEBUG=y
CONFIG_ATOMIC64_SELFTEST=y
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
CONFIG_KGDB=y
CONFIG_KGDB_SERIAL_CONSOLE=y
CONFIG_KGDB_TESTS=y
CONFIG_KGDB_TESTS_ON_BOOT=y
CONFIG_KGDB_TESTS_BOOT_STRING="V1F100"
CONFIG_KGDB_LOW_LEVEL_TRAP=y
# CONFIG_KGDB_KDB is not set
CONFIG_HAVE_ARCH_KMEMCHECK=y
CONFIG_KMEMCHECK=y
# CONFIG_KMEMCHECK_DISABLED_BY_DEFAULT is not set
CONFIG_KMEMCHECK_ENABLED_BY_DEFAULT=y
# CONFIG_KMEMCHECK_ONESHOT_BY_DEFAULT is not set
CONFIG_KMEMCHECK_QUEUE_SIZE=64
CONFIG_KMEMCHECK_SHADOW_COPY_SHIFT=5
# CONFIG_KMEMCHECK_PARTIAL_OK is not set
CONFIG_KMEMCHECK_BITOPS_OK=y
# CONFIG_STRICT_DEVMEM is not set
# CONFIG_X86_VERBOSE_BOOTUP is not set
CONFIG_EARLY_PRINTK=y
CONFIG_EARLY_PRINTK_DBGP=y
# CONFIG_DEBUG_STACKOVERFLOW is not set
# CONFIG_DEBUG_STACK_USAGE is not set
CONFIG_DEBUG_PER_CPU_MAPS=y
# CONFIG_X86_PTDUMP is not set
# CONFIG_DEBUG_RODATA is not set
CONFIG_IOMMU_STRESS=y
CONFIG_HAVE_MMIOTRACE_SUPPORT=y
CONFIG_IO_DELAY_TYPE_0X80=0
CONFIG_IO_DELAY_TYPE_0XED=1
CONFIG_IO_DELAY_TYPE_UDELAY=2
CONFIG_IO_DELAY_TYPE_NONE=3
# CONFIG_IO_DELAY_0X80 is not set
# CONFIG_IO_DELAY_0XED is not set
# CONFIG_IO_DELAY_UDELAY is not set
CONFIG_IO_DELAY_NONE=y
CONFIG_DEFAULT_IO_DELAY_TYPE=3
CONFIG_CPA_DEBUG=y
# CONFIG_OPTIMIZE_INLINING is not set
#
# Security options
#
# CONFIG_KEYS is not set
CONFIG_SECURITYFS=y
CONFIG_DEFAULT_SECURITY_DAC=y
CONFIG_DEFAULT_SECURITY=""
CONFIG_CRYPTO=y
#
# Crypto core or helper
#
CONFIG_CRYPTO_ALGAPI=y
CONFIG_CRYPTO_ALGAPI2=y
CONFIG_CRYPTO_AEAD=y
CONFIG_CRYPTO_AEAD2=y
CONFIG_CRYPTO_BLKCIPHER=y
CONFIG_CRYPTO_BLKCIPHER2=y
CONFIG_CRYPTO_HASH=y
CONFIG_CRYPTO_HASH2=y
CONFIG_CRYPTO_RNG=y
CONFIG_CRYPTO_RNG2=y
CONFIG_CRYPTO_PCOMP=y
CONFIG_CRYPTO_PCOMP2=y
CONFIG_CRYPTO_MANAGER=y
CONFIG_CRYPTO_MANAGER2=y
CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
CONFIG_CRYPTO_GF128MUL=y
CONFIG_CRYPTO_NULL=y
# CONFIG_CRYPTO_PCRYPT is not set
CONFIG_CRYPTO_WORKQUEUE=y
CONFIG_CRYPTO_CRYPTD=y
# CONFIG_CRYPTO_AUTHENC is not set
#
# Authenticated Encryption with Associated Data
#
# CONFIG_CRYPTO_CCM is not set
CONFIG_CRYPTO_GCM=y
CONFIG_CRYPTO_SEQIV=y
#
# Block modes
#
CONFIG_CRYPTO_CBC=y
CONFIG_CRYPTO_CTR=y
# CONFIG_CRYPTO_CTS is not set
# CONFIG_CRYPTO_ECB is not set
# CONFIG_CRYPTO_LRW is not set
# CONFIG_CRYPTO_PCBC is not set
CONFIG_CRYPTO_XTS=y
CONFIG_CRYPTO_FPU=y
#
# Hash modes
#
# CONFIG_CRYPTO_HMAC is not set
CONFIG_CRYPTO_XCBC=y
# CONFIG_CRYPTO_VMAC is not set
#
# Digest
#
CONFIG_CRYPTO_CRC32C=y
# CONFIG_CRYPTO_CRC32C_INTEL is not set
CONFIG_CRYPTO_GHASH=y
# CONFIG_CRYPTO_MD4 is not set
# CONFIG_CRYPTO_MD5 is not set
# CONFIG_CRYPTO_MICHAEL_MIC is not set
CONFIG_CRYPTO_RMD128=y
CONFIG_CRYPTO_RMD160=y
# CONFIG_CRYPTO_RMD256 is not set
CONFIG_CRYPTO_RMD320=y
CONFIG_CRYPTO_SHA1=y
# CONFIG_CRYPTO_SHA256 is not set
CONFIG_CRYPTO_SHA512=y
CONFIG_CRYPTO_TGR192=y
# CONFIG_CRYPTO_WP512 is not set
CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL=y
#
# Ciphers
#
CONFIG_CRYPTO_AES=y
CONFIG_CRYPTO_AES_X86_64=y
CONFIG_CRYPTO_AES_NI_INTEL=y
CONFIG_CRYPTO_ANUBIS=y
CONFIG_CRYPTO_ARC4=y
# CONFIG_CRYPTO_BLOWFISH is not set
CONFIG_CRYPTO_CAMELLIA=y
CONFIG_CRYPTO_CAST5=y
CONFIG_CRYPTO_CAST6=y
CONFIG_CRYPTO_DES=y
# CONFIG_CRYPTO_FCRYPT is not set
# CONFIG_CRYPTO_KHAZAD is not set
# CONFIG_CRYPTO_SALSA20 is not set
# CONFIG_CRYPTO_SALSA20_X86_64 is not set
# CONFIG_CRYPTO_SEED is not set
# CONFIG_CRYPTO_SERPENT is not set
# CONFIG_CRYPTO_TEA is not set
# CONFIG_CRYPTO_TWOFISH is not set
# CONFIG_CRYPTO_TWOFISH_X86_64 is not set
#
# Compression
#
# CONFIG_CRYPTO_DEFLATE is not set
CONFIG_CRYPTO_ZLIB=y
CONFIG_CRYPTO_LZO=y
#
# Random Number Generation
#
# CONFIG_CRYPTO_ANSI_CPRNG is not set
# CONFIG_CRYPTO_HW is not set
CONFIG_HAVE_KVM=y
CONFIG_HAVE_KVM_IRQCHIP=y
CONFIG_HAVE_KVM_EVENTFD=y
CONFIG_KVM_APIC_ARCHITECTURE=y
CONFIG_KVM_MMIO=y
CONFIG_VIRTUALIZATION=y
CONFIG_KVM=y
# CONFIG_KVM_INTEL is not set
CONFIG_KVM_AMD=y
CONFIG_VIRTIO=y
CONFIG_VIRTIO_RING=y
CONFIG_VIRTIO_PCI=y
# CONFIG_VIRTIO_BALLOON is not set
# CONFIG_BINARY_PRINTF is not set
#
# Library routines
#
CONFIG_BITREVERSE=y
CONFIG_GENERIC_FIND_FIRST_BIT=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_FIND_LAST_BIT=y
CONFIG_CRC_CCITT=y
CONFIG_CRC16=y
CONFIG_CRC_T10DIF=y
# CONFIG_CRC_ITU_T is not set
CONFIG_CRC32=y
# CONFIG_CRC7 is not set
CONFIG_LIBCRC32C=y
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=y
CONFIG_LZO_COMPRESS=y
CONFIG_LZO_DECOMPRESS=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
# CONFIG_CPUMASK_OFFSTACK is not set
CONFIG_NLATTR=y
CONFIG_FORCE_SUCCESSFUL_BUILD=y
^ permalink raw reply
* [PATCH] Switch the i.MX27's PLL in a safe manner
From: Juergen Beisert @ 2010-10-08 8:45 UTC (permalink / raw)
To: barebox
In-Reply-To: <1286527540-9857-1-git-send-email-jbe@pengutronix.de>
Changing PLL settings is somehow tricky on the i.MX27: Whenever the clock
speed of the main PLL is changed, the clock stops for about 100 us until the
PLL locks into the new frequency. While this clock stop, also the SDRAM
controller cannot refresh the memory, because it uses the same clock source.
This can lead into data loss and random system crashes.
This patch divides the PLL setting in two steps. First step is to re-program
the PLL and clock settings to values possible at a core supply of 1.25 V.
Second step is to increase the core power supply to 1.45 V and switch the
CPU clock to the specified 400 MHz.
Signed-off-by: Juergen Beisert <jbe@pengutronix.de>
---
arch/arm/boards/pcm038/Makefile | 2 +-
arch/arm/boards/pcm038/lowlevel.c | 7 ++++
arch/arm/boards/pcm038/pcm038.c | 65 ++++++++++++++++++++----------------
arch/arm/boards/pcm038/pll_init.S | 48 ---------------------------
4 files changed, 44 insertions(+), 78 deletions(-)
delete mode 100644 arch/arm/boards/pcm038/pll_init.S
diff --git a/arch/arm/boards/pcm038/Makefile b/arch/arm/boards/pcm038/Makefile
index a681dda..970804e 100644
--- a/arch/arm/boards/pcm038/Makefile
+++ b/arch/arm/boards/pcm038/Makefile
@@ -1,3 +1,3 @@
-obj-y += lowlevel.o pll_init.o
+obj-y += lowlevel.o
obj-y += pcm038.o
diff --git a/arch/arm/boards/pcm038/lowlevel.c b/arch/arm/boards/pcm038/lowlevel.c
index eb85e8f..b50e1c8 100644
--- a/arch/arm/boards/pcm038/lowlevel.c
+++ b/arch/arm/boards/pcm038/lowlevel.c
@@ -31,6 +31,8 @@
#include <asm/system.h>
#include <asm-generic/memory_layout.h>
+#include "pll.h"
+
#ifdef CONFIG_NAND_IMX_BOOT
static void __bare_init __naked insdram(void)
{
@@ -68,6 +70,11 @@ void __bare_init __naked board_init_lowlevel(void)
if (r > 0xa0000000 && r < 0xb0000000)
board_init_lowlevel_return();
+ /* re-program the PLL prior(!) starting the SDRAM controller */
+ MPCTL0 = MPCTL0_VAL;
+ SPCTL0 = SPCTL0_VAL;
+ CSCR = CSCR_VAL | CSCR_UPDATE_DIS | CSCR_MPLL_RESTART | CSCR_SPLL_RESTART;
+
/*
* DDR on CSD0
*/
diff --git a/arch/arm/boards/pcm038/pcm038.c b/arch/arm/boards/pcm038/pcm038.c
index fda3262..3a9b413 100644
--- a/arch/arm/boards/pcm038/pcm038.c
+++ b/arch/arm/boards/pcm038/pcm038.c
@@ -44,6 +44,8 @@
#include <mach/spi.h>
#include <mach/iomux-mx27.h>
+#include "pll.h"
+
static struct device_d cfi_dev = {
.id = -1,
.name = "cfi_flash",
@@ -379,11 +381,6 @@ static struct device_d pcm038_serial_device = {
static int pcm038_console_init(void)
{
- /* bring PLLs to reset default */
- MPCTL0 = 0x00211803;
- SPCTL0 = 0x1002700c;
- CSCR = 0x33fc1307;
-
register_device(&pcm038_serial_device);
return 0;
@@ -391,40 +388,50 @@ static int pcm038_console_init(void)
console_initcall(pcm038_console_init);
-extern void *pcm038_pll_init, *pcm038_pll_init_end;
-
-static int pcm038_power_init(void)
+/**
+ * The spctl0 register is a beast: Seems you can read it
+ * only one times without writing it again.
+ */
+static inline uint32_t get_pll_spctl10(void)
{
- int ret;
- void *vram = (void*)0xffff4c00;
- void (*pllfunc)(void) = vram;
+ uint32_t reg;
- printf("initialising PLLs: 0x%p 0x%p\n", &pcm038_pll_init);
+ reg = SPCTL0;
+ SPCTL0 = reg;
- memcpy(vram, &pcm038_pll_init, 0x100);
+ return reg;
+}
- console_flush();
+/**
+ * If the PLL settings are in place switch the CPU core frequency to the max. value
+ */
+static int pcm038_power_init(void)
+{
+ uint32_t spctl0;
+ int ret;
- ret = pmic_power();
- if (ret) {
- printf("Failed to initialize PMIC. Will continue with low CPU speed\n");
- return 0;
+ spctl0 = get_pll_spctl10();
+
+ /* PLL registers already set to their final values? */
+ if (spctl0 == SPCTL0_VAL && MPCTL0 == MPCTL0_VAL) {
+ console_flush();
+ ret = pmic_power();
+ if (ret == 0) {
+ /* wait for required power level to run the CPU at 400 MHz */
+ udelay(100000);
+ CSCR = CSCR_VAL_FINAL;
+ PCDR0 = 0x130410c3;
+ PCDR1 = 0x09030911;
+ /* Clocks have changed. Notify clients */
+ clock_notifier_call_chain();
+ } else {
+ printf("Failed to initialize PMIC. Will continue with low CPU speed\n");
+ }
}
- /* wait for good power level */
- udelay(100000);
-
- pllfunc();
-
/* clock gating enable */
GPCR = 0x00050f08;
- PCDR0 = 0x130410c3;
- PCDR1 = 0x09030911;
-
- /* Clocks have changed. Notify clients */
- clock_notifier_call_chain();
-
return 0;
}
diff --git a/arch/arm/boards/pcm038/pll_init.S b/arch/arm/boards/pcm038/pll_init.S
deleted file mode 100644
index 0c1ff13..0000000
--- a/arch/arm/boards/pcm038/pll_init.S
+++ /dev/null
@@ -1,48 +0,0 @@
-#include <config.h>
-#include <mach/imx-regs.h>
-#include <mach/imx-pll.h>
-#include <linux/linkage.h>
-
-#define writel(val, reg) \
- ldr r0, =reg; \
- ldr r1, =val; \
- str r1, [r0];
-
-#define CSCR_VAL CSCR_USB_DIV(3) | \
- CSCR_SD_CNT(3) | \
- CSCR_MSHC_SEL | \
- CSCR_H264_SEL | \
- CSCR_SSI1_SEL | \
- CSCR_SSI2_SEL | \
- CSCR_MCU_SEL | \
- CSCR_ARM_SRC_MPLL | \
- CSCR_SP_SEL | \
- CSCR_ARM_DIV(0) | \
- CSCR_FPM_EN | \
- CSCR_SPEN | \
- CSCR_MPEN | \
- CSCR_AHB_DIV(1)
-
-ENTRY(pcm038_pll_init)
-
- writel(IMX_PLL_PD(0) |
- IMX_PLL_MFD(51) |
- IMX_PLL_MFI(7) |
- IMX_PLL_MFN(35), MPCTL0) /* 399 MHz */
-
- writel(IMX_PLL_PD(1) |
- IMX_PLL_MFD(12) |
- IMX_PLL_MFI(9) |
- IMX_PLL_MFN(3), SPCTL0) /* SPLL = 2 * 26 * 4.61538 MHz = 240 MHz */
-
- writel(CSCR_VAL | CSCR_MPLL_RESTART | CSCR_SPLL_RESTART, CSCR)
-
- ldr r2, =16000
-1:
- subs r2, r2, #1
- nop
- bcs 1b
-
- mov pc, lr
-ENDPROC(pcm038_pll_init)
-
--
1.7.2.3
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply related
* Switch the i.MX27's PLL in a safe manner
From: Juergen Beisert @ 2010-10-08 8:45 UTC (permalink / raw)
To: barebox
This patch is required to switch the PLL of the i.MX27 at runtime without data
loss and random system crashes (but it is only required in this way if the CPU
core does not run at 1.45 V immediatly after reset).
jbe
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply
* Re: [fix-isi-udev PATCH 0/3] Improve udev with isi
From: Alexander Kanavin @ 2010-10-08 8:45 UTC (permalink / raw)
To: ofono
In-Reply-To: <1286480461.9665.558.camel@tucson.research.nokia.com>
[-- Attachment #1: Type: text/plain, Size: 558 bytes --]
On 07.10.2010 22:41, ext Aki Niemi wrote:
>> [fix-isi-udev PATCH 3/3] ofono.rules: assign isigen driver by USB ids
>
> This one was left dangling; let's see if we can come up with a better
> way to match the modems driven by cdc_phonet. (Although, admittedly this
> same approach is already used with some AT modems.)
I suppose you could match by usb interface class and subclass? (02 and 254
respectively - the first is standardized, but the second seems to be just
made up by Nokia at some point, so we better keep the vendor id too)
Alex
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.