aboutsummaryrefslogtreecommitdiff
path: root/drivers/media/platform/hisi/isp/isp-sr.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/platform/hisi/isp/isp-sr.c')
-rw-r--r--drivers/media/platform/hisi/isp/isp-sr.c267
1 files changed, 267 insertions, 0 deletions
diff --git a/drivers/media/platform/hisi/isp/isp-sr.c b/drivers/media/platform/hisi/isp/isp-sr.c
new file mode 100644
index 000000000000..14f1ac4d4cef
--- /dev/null
+++ b/drivers/media/platform/hisi/isp/isp-sr.c
@@ -0,0 +1,267 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * isp-sr.c
+ *
+ * Copyright (C) 2018 Linaro Ltd.
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <media/media-entity.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+
+#include "isp.h"
+
+#define ISP_SR_NAME "isp_sr"
+
+void isp_sr_config(struct sr_device *sr)
+{
+ int data_type = 1;
+ union U_ID_ROUTER_1 reg1;
+ union U_REFORMAT reg;
+
+ isp_writel(sr->base, STREAM_ROUTER_CSIFILTER_A_REG,
+ (0 << 6) | (YUV_DT_422_8BITS << 0));
+
+ reg1.u32 = isp_readl(sr->base, STREAM_ROUTER_ID_ROUTER_1_REG);
+ reg1.bits.idr_enable_6 = 1;
+ reg1.bits.idr_input_stream_6 = (0 << 2) | (0 << 0);
+ isp_writel(sr->base, STREAM_ROUTER_ID_ROUTER_1_REG, reg1.u32);
+
+ reg.u32 = 0;
+ reg.bits.reformat_enable = 1;
+ reg.bits.reformat_num_pixels = 1920 * 2 - 1;
+ reg.bits.reformat_num_lines = 1080 - 1;
+ reg.bits.reformat_pixel_reorder = data_type;
+
+ isp_writel(sr->base, STREAM_ROUTER_REFORMAT_REG(6), reg.u32);
+ isp_writel(sr->base, STREAM_ROUTER_REFORMAT_MINSPACE_REG(6), (0x1F << 0));
+}
+
+void isp_sr_go(struct sr_device *sr, unsigned int go_bit)
+{
+ isp_writel(sr->base, STREAM_ROUTER_CSIFILTER_GO_REG, go_bit);
+}
+
+/*
+ * sr_set_power - Power on/off CSIPHY module
+ * @sd: CSIPHY V4L2 subdevice
+ * @on: Requested power state
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+static int sr_set_power(struct v4l2_subdev *sd, int on)
+{
+
+ pr_info("%s: %d\n", __func__, __LINE__);
+ return 0;
+}
+
+/*
+ * sr_set_stream - Enable/disable streaming on CSIPHY module
+ * @sd: CSIPHY V4L2 subdevice
+ * @enable: Requested streaming state
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+static int sr_set_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct sr_device *sr = v4l2_get_subdevdata(sd);
+ int ret = 0;
+
+ enable_irq(sr->irq_frproc0);
+ isp_config_smmu_bypass(sr->isp);
+ isp_sr_config(sr);
+ isp_sr_go(sr, 0);
+
+ pr_info("%s: %d\n", __func__, __LINE__);
+
+ return ret;
+}
+
+/*
+ * sr_init_formats - Initialize formats on all pads
+ * @sd: CSIPHY V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ *
+ * Initialize all pad formats with default values.
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+static int sr_init_formats(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ return 0;
+}
+
+irqreturn_t isp_frproc0_handler(int irq, void *dev)
+{
+ struct sr_device *sr = dev;
+ struct isp *isp = sr->isp;
+ unsigned int val = isp_clear_irq(sr->isp, IRQ_MERGER_FRPROC_0);
+
+ if (val & (1 << IRQ_MERGER_SR_4_CVDR_RT_EOF_VPWR_23_OFFSET)) {
+ // FIXME: Use CSI index
+ isp_sr_go(sr, (1 << 0));
+ isp->frame_num++;
+ }
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * isp_sr_subdev_init - Initialize CSIPHY device structure and resources
+ * @sr: CSIPHY device
+ * @res: CSIPHY module resources table
+ * @id: CSIPHY module id
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+int isp_sr_subdev_init(struct isp *isp,
+ struct sr_device *sr,
+ const struct resources *res)
+{
+ struct device *dev = isp->dev;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct resource *r;
+ int ret;
+
+ sr->isp = isp;
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg);
+ sr->base = devm_ioremap_resource(dev, r);
+ if (IS_ERR(sr->base)) {
+ dev_err(dev, "could not map memory\n");
+ return PTR_ERR(sr->base);
+ }
+
+ ret = platform_get_irq_byname(pdev, "isp_frproc0");
+ if (ret <= 0) {
+ dev_err(isp->dev, "No IRQ resource\n");
+ return -ENODEV;
+ }
+
+ sr->irq_frproc0 = ret;
+
+ ret = devm_request_irq(&pdev->dev, sr->irq_frproc0,
+ isp_frproc0_handler, 0, "isp-frproc0", sr);
+ if (ret)
+ return ret;
+
+ disable_irq(sr->irq_frproc0);
+
+ return 0;
+}
+
+/*
+ * sr_link_setup - Setup CSIPHY connections
+ * @entity: Pointer to media entity structure
+ * @local: Pointer to local pad
+ * @remote: Pointer to remote pad
+ * @flags: Link flags
+ *
+ * Rreturn 0 on success
+ */
+static int sr_link_setup(struct media_entity *entity,
+ const struct media_pad *local,
+ const struct media_pad *remote, u32 flags)
+{
+ if ((local->flags & MEDIA_PAD_FL_SOURCE) &&
+ (flags & MEDIA_LNK_FL_ENABLED)) {
+ struct v4l2_subdev *sd;
+ struct sr_device *sr;
+
+ if (media_entity_remote_pad(local))
+ return -EBUSY;
+
+ sd = media_entity_to_v4l2_subdev(entity);
+ sr = v4l2_get_subdevdata(sd);
+ }
+
+ return 0;
+}
+
+static const struct v4l2_subdev_core_ops sr_core_ops = {
+ .s_power = sr_set_power,
+};
+
+static const struct v4l2_subdev_video_ops sr_video_ops = {
+ .s_stream = sr_set_stream,
+};
+
+static const struct v4l2_subdev_ops sr_v4l2_ops = {
+ .core = &sr_core_ops,
+ .video = &sr_video_ops,
+};
+
+static const struct v4l2_subdev_internal_ops sr_v4l2_internal_ops = {
+ .open = sr_init_formats,
+};
+
+static const struct media_entity_operations sr_media_ops = {
+ .link_setup = sr_link_setup,
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+/*
+ * isp_sr_register_entity - Register subdev node for CSIPHY module
+ * @sr: CSIPHY device
+ * @v4l2_dev: V4L2 device
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+int isp_sr_register_entity(struct sr_device *sr,
+ struct v4l2_device *v4l2_dev)
+{
+ struct v4l2_subdev *sd = &sr->subdev;
+ struct media_pad *pads = sr->pads;
+ struct device *dev = sr->isp->dev;
+ int ret;
+
+ v4l2_subdev_init(sd, &sr_v4l2_ops);
+ sd->internal_ops = &sr_v4l2_internal_ops;
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ snprintf(sd->name, ARRAY_SIZE(sd->name), "%s",
+ ISP_SR_NAME);
+ v4l2_set_subdevdata(sd, sr);
+
+ ret = sr_init_formats(sd, NULL);
+ if (ret < 0) {
+ dev_err(dev, "Failed to init format: %d\n", ret);
+ return ret;
+ }
+
+ pads[ISP_CSIPHY_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ pads[ISP_CSIPHY_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE;
+
+ sd->entity.function = MEDIA_ENT_F_IO_V4L;
+ sd->entity.ops = &sr_media_ops;
+ ret = media_entity_pads_init(&sd->entity, ISP_CSIPHY_PADS_NUM, pads);
+ if (ret < 0) {
+ dev_err(dev, "Failed to init media entity: %d\n", ret);
+ return ret;
+ }
+
+ ret = v4l2_device_register_subdev(v4l2_dev, sd);
+ if (ret < 0) {
+ dev_err(dev, "Failed to register subdev: %d\n", ret);
+ media_entity_cleanup(&sd->entity);
+ }
+
+ return ret;
+}
+
+/*
+ * isp_sr_unregister_entity - Unregister CSIPHY module subdev node
+ * @sr: CSIPHY device
+ */
+void isp_sr_unregister_entity(struct sr_device *sr)
+{
+ v4l2_device_unregister_subdev(&sr->subdev);
+ media_entity_cleanup(&sr->subdev.entity);
+}