From 1543e317f1da31b75942316931e8f491a8920811 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Thu, 04 Jan 2024 10:08:02 +0000
Subject: [PATCH] disable FB
---
kernel/drivers/media/platform/marvell-ccic/mcam-core.c | 372 +++++++++++++++++++++++++++++++++--------------------
1 files changed, 232 insertions(+), 140 deletions(-)
diff --git a/kernel/drivers/media/platform/marvell-ccic/mcam-core.c b/kernel/drivers/media/platform/marvell-ccic/mcam-core.c
index eeee15f..e56c5e5 100644
--- a/kernel/drivers/media/platform/marvell-ccic/mcam-core.c
+++ b/kernel/drivers/media/platform/marvell-ccic/mcam-core.c
@@ -4,6 +4,7 @@
* so it needs platform-specific support outside of the core.
*
* Copyright 2011 Jonathan Corbet corbet@lwn.net
+ * Copyright 2018 Lubomir Rintel <lkundrak@v3.sk>
*/
#include <linux/kernel.h>
#include <linux/module.h>
@@ -21,12 +22,13 @@
#include <linux/vmalloc.h>
#include <linux/io.h>
#include <linux/clk.h>
+#include <linux/clk-provider.h>
#include <linux/videodev2.h>
+#include <linux/pm_runtime.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-event.h>
-#include <media/i2c/ov7670.h>
#include <media/videobuf2-vmalloc.h>
#include <media/videobuf2-dma-contig.h>
#include <media/videobuf2-dma-sg.h>
@@ -93,57 +95,52 @@
#define sensor_call(cam, o, f, args...) \
v4l2_subdev_call(cam->sensor, o, f, ##args)
+#define notifier_to_mcam(notifier) \
+ container_of(notifier, struct mcam_camera, notifier)
+
static struct mcam_format_struct {
- __u8 *desc;
__u32 pixelformat;
int bpp; /* Bytes per pixel */
bool planar;
u32 mbus_code;
} mcam_formats[] = {
{
- .desc = "YUYV 4:2:2",
.pixelformat = V4L2_PIX_FMT_YUYV,
.mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
.bpp = 2,
.planar = false,
},
{
- .desc = "YVYU 4:2:2",
.pixelformat = V4L2_PIX_FMT_YVYU,
.mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
.bpp = 2,
.planar = false,
},
{
- .desc = "YUV 4:2:0 PLANAR",
.pixelformat = V4L2_PIX_FMT_YUV420,
.mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
.bpp = 1,
.planar = true,
},
{
- .desc = "YVU 4:2:0 PLANAR",
.pixelformat = V4L2_PIX_FMT_YVU420,
.mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
.bpp = 1,
.planar = true,
},
{
- .desc = "XRGB 444",
.pixelformat = V4L2_PIX_FMT_XRGB444,
.mbus_code = MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE,
.bpp = 2,
.planar = false,
},
{
- .desc = "RGB 565",
.pixelformat = V4L2_PIX_FMT_RGB565,
.mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE,
.bpp = 2,
.planar = false,
},
{
- .desc = "Raw RGB Bayer",
.pixelformat = V4L2_PIX_FMT_SBGGR8,
.mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8,
.bpp = 1,
@@ -281,6 +278,8 @@
static void mcam_enable_mipi(struct mcam_camera *mcam)
{
/* Using MIPI mode and enable MIPI */
+ if (mcam->calc_dphy)
+ mcam->calc_dphy(mcam);
cam_dbg(mcam, "camera: DPHY3=0x%x, DPHY5=0x%x, DPHY6=0x%x\n",
mcam->dphy[0], mcam->dphy[1], mcam->dphy[2]);
mcam_reg_write(mcam, REG_CSI2_DPHY3, mcam->dphy[0]);
@@ -300,9 +299,6 @@
*/
mcam_reg_write(mcam, REG_CSI2_CTRL0,
CSI2_C0_MIPI_EN | CSI2_C0_ACT_LANE(mcam->lane));
- mcam_reg_write(mcam, REG_CLKCTRL,
- (mcam->mclk_src << 29) | mcam->mclk_div);
-
mcam->mipi_enabled = true;
}
}
@@ -393,7 +389,7 @@
dma_free_coherent(cam->dev, cam->dma_buf_size,
cam->dma_bufs[0], cam->dma_handles[0]);
cam->nbufs = 0;
- /* fall-through */
+ fallthrough;
case 0:
cam_err(cam, "Insufficient DMA buffers, cannot operate\n");
return -ENOMEM;
@@ -443,9 +439,9 @@
/*
* Copy data out to user space in the vmalloc case
*/
-static void mcam_frame_tasklet(unsigned long data)
+static void mcam_frame_tasklet(struct tasklet_struct *t)
{
- struct mcam_camera *cam = (struct mcam_camera *) data;
+ struct mcam_camera *cam = from_tasklet(cam, t, s_tasklet);
int i;
unsigned long flags;
struct mcam_vb_buffer *buf;
@@ -792,12 +788,6 @@
* Make sure it knows we want to use hsync/vsync.
*/
mcam_reg_write_mask(cam, REG_CTRL0, C0_SIF_HVSYNC, C0_SIFM_MASK);
- /*
- * This field controls the generation of EOF(DVP only)
- */
- if (cam->bus_type != V4L2_MBUS_CSI2)
- mcam_reg_set_bit(cam, REG_CTRL0,
- C0_EOF_VSYNC | C0_VEDGE_CTRL);
}
@@ -832,31 +822,6 @@
{
mcam_reg_clear_bit(cam, REG_IRQMASK, FRAMEIRQS);
}
-
-
-
-static void mcam_ctlr_init(struct mcam_camera *cam)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&cam->dev_lock, flags);
- /*
- * Make sure it's not powered down.
- */
- mcam_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN);
- /*
- * Turn off the enable bit. It sure should be off anyway,
- * but it's good to be sure.
- */
- mcam_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE);
- /*
- * Clock the sensor appropriately. Controller clock should
- * be 48MHz, sensor "typical" value is half that.
- */
- mcam_reg_write_mask(cam, REG_CLKCTRL, 2, CLK_DIV_MASK);
- spin_unlock_irqrestore(&cam->dev_lock, flags);
-}
-
/*
* Stop the controller, and don't return until we're really sure that no
@@ -901,14 +866,15 @@
int ret;
spin_lock_irqsave(&cam->dev_lock, flags);
- ret = cam->plat_power_up(cam);
- if (ret) {
- spin_unlock_irqrestore(&cam->dev_lock, flags);
- return ret;
+ if (cam->plat_power_up) {
+ ret = cam->plat_power_up(cam);
+ if (ret) {
+ spin_unlock_irqrestore(&cam->dev_lock, flags);
+ return ret;
+ }
}
mcam_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN);
spin_unlock_irqrestore(&cam->dev_lock, flags);
- msleep(5); /* Just to be sure */
return 0;
}
@@ -923,9 +889,81 @@
* power down routine.
*/
mcam_reg_set_bit(cam, REG_CTRL1, C1_PWRDWN);
- cam->plat_power_down(cam);
+ if (cam->plat_power_down)
+ cam->plat_power_down(cam);
spin_unlock_irqrestore(&cam->dev_lock, flags);
}
+
+/* ---------------------------------------------------------------------- */
+/*
+ * Master sensor clock.
+ */
+static int mclk_prepare(struct clk_hw *hw)
+{
+ struct mcam_camera *cam = container_of(hw, struct mcam_camera, mclk_hw);
+
+ clk_prepare(cam->clk[0]);
+ return 0;
+}
+
+static void mclk_unprepare(struct clk_hw *hw)
+{
+ struct mcam_camera *cam = container_of(hw, struct mcam_camera, mclk_hw);
+
+ clk_unprepare(cam->clk[0]);
+}
+
+static int mclk_enable(struct clk_hw *hw)
+{
+ struct mcam_camera *cam = container_of(hw, struct mcam_camera, mclk_hw);
+ int mclk_src;
+ int mclk_div;
+ int ret;
+
+ /*
+ * Clock the sensor appropriately. Controller clock should
+ * be 48MHz, sensor "typical" value is half that.
+ */
+ if (cam->bus_type == V4L2_MBUS_CSI2_DPHY) {
+ mclk_src = cam->mclk_src;
+ mclk_div = cam->mclk_div;
+ } else {
+ mclk_src = 3;
+ mclk_div = 2;
+ }
+
+ ret = pm_runtime_resume_and_get(cam->dev);
+ if (ret < 0)
+ return ret;
+ clk_enable(cam->clk[0]);
+ mcam_reg_write(cam, REG_CLKCTRL, (mclk_src << 29) | mclk_div);
+ mcam_ctlr_power_up(cam);
+
+ return 0;
+}
+
+static void mclk_disable(struct clk_hw *hw)
+{
+ struct mcam_camera *cam = container_of(hw, struct mcam_camera, mclk_hw);
+
+ mcam_ctlr_power_down(cam);
+ clk_disable(cam->clk[0]);
+ pm_runtime_put(cam->dev);
+}
+
+static unsigned long mclk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ return 48000000;
+}
+
+static const struct clk_ops mclk_ops = {
+ .prepare = mclk_prepare,
+ .unprepare = mclk_unprepare,
+ .enable = mclk_enable,
+ .disable = mclk_disable,
+ .recalc_rate = mclk_recalc_rate,
+};
/* -------------------------------------------------------------------- */
/*
@@ -951,7 +989,6 @@
ret = __mcam_cam_reset(cam);
/* Get/set parameters? */
cam->state = S_IDLE;
- mcam_ctlr_power_down(cam);
return ret;
}
@@ -1017,14 +1054,7 @@
spin_lock_irqsave(&cam->dev_lock, flags);
clear_bit(CF_DMA_ACTIVE, &cam->flags);
mcam_reset_buffers(cam);
- /*
- * Update CSI2_DPHY value
- */
- if (cam->calc_dphy)
- cam->calc_dphy(cam);
- cam_dbg(cam, "camera: DPHY sets: dphy3=0x%x, dphy5=0x%x, dphy6=0x%x\n",
- cam->dphy[0], cam->dphy[1], cam->dphy[2]);
- if (cam->bus_type == V4L2_MBUS_CSI2)
+ if (cam->bus_type == V4L2_MBUS_CSI2_DPHY)
mcam_enable_mipi(cam);
else
mcam_disable_mipi(cam);
@@ -1161,12 +1191,6 @@
return;
mcam_ctlr_stop_dma(cam);
/*
- * Reset the CCIC PHY after stopping streaming,
- * otherwise, the CCIC may be unstable.
- */
- if (cam->ctlr_reset)
- cam->ctlr_reset(cam);
- /*
* VB2 reclaims the buffers, so we need to forget
* about them.
*/
@@ -1281,8 +1305,7 @@
break;
case B_vmalloc:
#ifdef MCAM_MODE_VMALLOC
- tasklet_init(&cam->s_tasklet, mcam_frame_tasklet,
- (unsigned long) cam);
+ tasklet_setup(&cam->s_tasklet, mcam_frame_tasklet);
vq->ops = &mcam_vb2_ops;
vq->mem_ops = &vb2_vmalloc_memops;
cam->dma_setup = mcam_ctlr_dma_vmalloc;
@@ -1304,12 +1327,9 @@
{
struct mcam_camera *cam = video_drvdata(file);
- strcpy(cap->driver, "marvell_ccic");
- strcpy(cap->card, "marvell_ccic");
- strlcpy(cap->bus_info, cam->bus_info, sizeof(cap->bus_info));
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+ strscpy(cap->driver, "marvell_ccic", sizeof(cap->driver));
+ strscpy(cap->card, "marvell_ccic", sizeof(cap->card));
+ strscpy(cap->bus_info, cam->bus_info, sizeof(cap->bus_info));
return 0;
}
@@ -1319,8 +1339,6 @@
{
if (fmt->index >= N_MCAM_FMTS)
return -EINVAL;
- strlcpy(fmt->description, mcam_formats[fmt->index].desc,
- sizeof(fmt->description));
fmt->pixelformat = mcam_formats[fmt->index].pixelformat;
return 0;
}
@@ -1422,7 +1440,7 @@
return -EINVAL;
input->type = V4L2_INPUT_TYPE_CAMERA;
- strcpy(input->name, "Camera");
+ strscpy(input->name, "Camera", sizeof(input->name));
return 0;
}
@@ -1593,8 +1611,11 @@
if (ret)
goto out;
if (v4l2_fh_is_singular_file(filp)) {
- ret = mcam_ctlr_power_up(cam);
+ ret = sensor_call(cam, core, s_power, 1);
if (ret)
+ goto out;
+ ret = pm_runtime_resume_and_get(cam->dev);
+ if (ret < 0)
goto out;
__mcam_cam_reset(cam);
mcam_set_config_needed(cam, 1);
@@ -1617,7 +1638,8 @@
_vb2_fop_release(filp, NULL);
if (last_open) {
mcam_disable_mipi(cam);
- mcam_ctlr_power_down(cam);
+ sensor_call(cam, core, s_power, 0);
+ pm_runtime_put(cam->dev);
if (cam->buffer_mode == B_vmalloc && alloc_bufs_at_read)
mcam_free_dma_bufs(cam);
}
@@ -1646,6 +1668,8 @@
.fops = &mcam_v4l_fops,
.ioctl_ops = &mcam_v4l_ioctl_ops,
.release = video_device_release_empty,
+ .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING,
};
/* ---------------------------------------------------------------------- */
@@ -1727,23 +1751,95 @@
/*
* Registration and such.
*/
-static struct ov7670_config sensor_cfg = {
- /*
- * Exclude QCIF mode, because it only captures a tiny portion
- * of the sensor FOV
- */
- .min_width = 320,
- .min_height = 240,
-};
+static int mccic_notify_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *subdev, struct v4l2_async_subdev *asd)
+{
+ struct mcam_camera *cam = notifier_to_mcam(notifier);
+ int ret;
+
+ mutex_lock(&cam->s_mutex);
+ if (cam->sensor) {
+ cam_err(cam, "sensor already bound\n");
+ ret = -EBUSY;
+ goto out;
+ }
+
+ v4l2_set_subdev_hostdata(subdev, cam);
+ cam->sensor = subdev;
+
+ ret = mcam_cam_init(cam);
+ if (ret) {
+ cam->sensor = NULL;
+ goto out;
+ }
+
+ ret = mcam_setup_vb2(cam);
+ if (ret) {
+ cam->sensor = NULL;
+ goto out;
+ }
+
+ cam->vdev = mcam_v4l_template;
+ cam->vdev.v4l2_dev = &cam->v4l2_dev;
+ cam->vdev.lock = &cam->s_mutex;
+ cam->vdev.queue = &cam->vb_queue;
+ video_set_drvdata(&cam->vdev, cam);
+ ret = video_register_device(&cam->vdev, VFL_TYPE_VIDEO, -1);
+ if (ret) {
+ cam->sensor = NULL;
+ goto out;
+ }
+
+ cam_dbg(cam, "sensor %s bound\n", subdev->name);
+out:
+ mutex_unlock(&cam->s_mutex);
+ return ret;
+}
+
+static void mccic_notify_unbind(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *subdev, struct v4l2_async_subdev *asd)
+{
+ struct mcam_camera *cam = notifier_to_mcam(notifier);
+
+ mutex_lock(&cam->s_mutex);
+ if (cam->sensor != subdev) {
+ cam_err(cam, "sensor %s not bound\n", subdev->name);
+ goto out;
+ }
+
+ video_unregister_device(&cam->vdev);
+ cam->sensor = NULL;
+ cam_dbg(cam, "sensor %s unbound\n", subdev->name);
+
+out:
+ mutex_unlock(&cam->s_mutex);
+}
+
+static int mccic_notify_complete(struct v4l2_async_notifier *notifier)
+{
+ struct mcam_camera *cam = notifier_to_mcam(notifier);
+ int ret;
+
+ /*
+ * Get the v4l2 setup done.
+ */
+ ret = v4l2_ctrl_handler_init(&cam->ctrl_handler, 10);
+ if (!ret)
+ cam->v4l2_dev.ctrl_handler = &cam->ctrl_handler;
+
+ return ret;
+}
+
+static const struct v4l2_async_notifier_operations mccic_notify_ops = {
+ .bound = mccic_notify_bound,
+ .unbind = mccic_notify_unbind,
+ .complete = mccic_notify_complete,
+};
int mccic_register(struct mcam_camera *cam)
{
- struct i2c_board_info ov7670_info = {
- .type = "ov7670",
- .addr = 0x42 >> 1,
- .platform_data = &sensor_cfg,
- };
+ struct clk_init_data mclk_init = { };
int ret;
/*
@@ -1756,64 +1852,62 @@
printk(KERN_ERR "marvell-cam: Cafe can't do S/G I/O, attempting vmalloc mode instead\n");
cam->buffer_mode = B_vmalloc;
}
+
if (!mcam_buffer_mode_supported(cam->buffer_mode)) {
printk(KERN_ERR "marvell-cam: buffer mode %d unsupported\n",
cam->buffer_mode);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
+
/*
* Register with V4L
*/
ret = v4l2_device_register(cam->dev, &cam->v4l2_dev);
if (ret)
- return ret;
+ goto out;
mutex_init(&cam->s_mutex);
cam->state = S_NOTREADY;
mcam_set_config_needed(cam, 1);
cam->pix_format = mcam_def_pix_format;
cam->mbus_code = mcam_def_mbus_code;
- mcam_ctlr_init(cam);
/*
- * Get the v4l2 setup done.
+ * Register sensor notifier.
*/
- ret = v4l2_ctrl_handler_init(&cam->ctrl_handler, 10);
- if (ret)
- goto out_unregister;
- cam->v4l2_dev.ctrl_handler = &cam->ctrl_handler;
-
- /*
- * Try to find the sensor.
- */
- sensor_cfg.clock_speed = cam->clock_speed;
- sensor_cfg.use_smbus = cam->use_smbus;
- cam->sensor_addr = ov7670_info.addr;
- cam->sensor = v4l2_i2c_new_subdev_board(&cam->v4l2_dev,
- cam->i2c_adapter, &ov7670_info, NULL);
- if (cam->sensor == NULL) {
- ret = -ENODEV;
- goto out_unregister;
+ v4l2_async_notifier_init(&cam->notifier);
+ ret = v4l2_async_notifier_add_subdev(&cam->notifier, &cam->asd);
+ if (ret) {
+ cam_warn(cam, "failed to add subdev to a notifier");
+ goto out;
}
- ret = mcam_cam_init(cam);
- if (ret)
- goto out_unregister;
+ cam->notifier.ops = &mccic_notify_ops;
+ ret = v4l2_async_notifier_register(&cam->v4l2_dev, &cam->notifier);
+ if (ret < 0) {
+ cam_warn(cam, "failed to register a sensor notifier");
+ goto out;
+ }
- ret = mcam_setup_vb2(cam);
- if (ret)
- goto out_unregister;
+ /*
+ * Register sensor master clock.
+ */
+ mclk_init.parent_names = NULL;
+ mclk_init.num_parents = 0;
+ mclk_init.ops = &mclk_ops;
+ mclk_init.name = "mclk";
- mutex_lock(&cam->s_mutex);
- cam->vdev = mcam_v4l_template;
- cam->vdev.v4l2_dev = &cam->v4l2_dev;
- cam->vdev.lock = &cam->s_mutex;
- cam->vdev.queue = &cam->vb_queue;
- video_set_drvdata(&cam->vdev, cam);
- ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1);
- if (ret) {
- mutex_unlock(&cam->s_mutex);
- goto out_unregister;
+ of_property_read_string(cam->dev->of_node, "clock-output-names",
+ &mclk_init.name);
+
+ cam->mclk_hw.init = &mclk_init;
+
+ cam->mclk = devm_clk_register(cam->dev, &cam->mclk_hw);
+ if (IS_ERR(cam->mclk)) {
+ ret = PTR_ERR(cam->mclk);
+ dev_err(cam->dev, "can't register clock\n");
+ goto out;
}
/*
@@ -1824,12 +1918,12 @@
cam_warn(cam, "Unable to alloc DMA buffers at load will try again later.");
}
- mutex_unlock(&cam->s_mutex);
return 0;
-out_unregister:
- v4l2_ctrl_handler_free(&cam->ctrl_handler);
+out:
+ v4l2_async_notifier_unregister(&cam->notifier);
v4l2_device_unregister(&cam->v4l2_dev);
+ v4l2_async_notifier_cleanup(&cam->notifier);
return ret;
}
EXPORT_SYMBOL_GPL(mccic_register);
@@ -1844,21 +1938,20 @@
*/
if (!list_empty(&cam->vdev.fh_list)) {
cam_warn(cam, "Removing a device with users!\n");
- mcam_ctlr_power_down(cam);
+ sensor_call(cam, core, s_power, 0);
}
if (cam->buffer_mode == B_vmalloc)
mcam_free_dma_bufs(cam);
- video_unregister_device(&cam->vdev);
v4l2_ctrl_handler_free(&cam->ctrl_handler);
+ v4l2_async_notifier_unregister(&cam->notifier);
v4l2_device_unregister(&cam->v4l2_dev);
+ v4l2_async_notifier_cleanup(&cam->notifier);
}
EXPORT_SYMBOL_GPL(mccic_shutdown);
/*
* Power management
*/
-#ifdef CONFIG_PM
-
void mccic_suspend(struct mcam_camera *cam)
{
mutex_lock(&cam->s_mutex);
@@ -1866,7 +1959,7 @@
enum mcam_state cstate = cam->state;
mcam_ctlr_stop_dma(cam);
- mcam_ctlr_power_down(cam);
+ sensor_call(cam, core, s_power, 0);
cam->state = cstate;
}
mutex_unlock(&cam->s_mutex);
@@ -1879,14 +1972,14 @@
mutex_lock(&cam->s_mutex);
if (!list_empty(&cam->vdev.fh_list)) {
- ret = mcam_ctlr_power_up(cam);
+ ret = sensor_call(cam, core, s_power, 1);
if (ret) {
mutex_unlock(&cam->s_mutex);
return ret;
}
__mcam_cam_reset(cam);
} else {
- mcam_ctlr_power_down(cam);
+ sensor_call(cam, core, s_power, 0);
}
mutex_unlock(&cam->s_mutex);
@@ -1903,7 +1996,6 @@
return ret;
}
EXPORT_SYMBOL_GPL(mccic_resume);
-#endif /* CONFIG_PM */
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
--
Gitblit v1.6.2