aboutsummaryrefslogtreecommitdiff
path: root/drivers/media/platform/hisi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/platform/hisi')
-rw-r--r--drivers/media/platform/hisi/isp/Makefile10
-rw-r--r--drivers/media/platform/hisi/isp/isp-csiphy.c472
-rw-r--r--drivers/media/platform/hisi/isp/isp-csiphy.h149
-rw-r--r--drivers/media/platform/hisi/isp/isp-cvdr.c455
-rw-r--r--drivers/media/platform/hisi/isp/isp-cvdr.h951
-rw-r--r--drivers/media/platform/hisi/isp/isp-sr.c267
-rw-r--r--drivers/media/platform/hisi/isp/isp-sr.h114
-rw-r--r--drivers/media/platform/hisi/isp/isp.c709
-rw-r--r--drivers/media/platform/hisi/isp/isp.h159
9 files changed, 3286 insertions, 0 deletions
diff --git a/drivers/media/platform/hisi/isp/Makefile b/drivers/media/platform/hisi/isp/Makefile
new file mode 100644
index 000000000000..9fa39e3a4867
--- /dev/null
+++ b/drivers/media/platform/hisi/isp/Makefile
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0
+# Makefile for HISI ISP driver
+
+hisi-isp-objs += \
+ isp.o \
+ isp-csiphy.o \
+ isp-sr.o \
+ isp-cvdr.o \
+
+obj-$(CONFIG_VIDEO_HISI_ISP) += hisi-isp.o
diff --git a/drivers/media/platform/hisi/isp/isp-csiphy.c b/drivers/media/platform/hisi/isp/isp-csiphy.c
new file mode 100644
index 000000000000..f6c050fc0814
--- /dev/null
+++ b/drivers/media/platform/hisi/isp/isp-csiphy.c
@@ -0,0 +1,472 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * isp-csiphy.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 TSTCODE_SETREG8(reg_base, addr, value) \
+ do { \
+ isp_writel(reg_base, CSI2IF_PHY_TEST_CTRL1_REG,\
+ (1 << 16) | addr); \
+ isp_writel(reg_base, CSI2IF_PHY_TEST_CTRL0_REG, 2); \
+ isp_writel(reg_base, CSI2IF_PHY_TEST_CTRL0_REG, 0); \
+ isp_writel(reg_base, CSI2IF_PHY_TEST_CTRL1_REG, value); \
+ isp_writel(reg_base, CSI2IF_PHY_TEST_CTRL0_REG, 2); \
+ isp_writel(reg_base, CSI2IF_PHY_TEST_CTRL0_REG, 0); \
+ } while (0)
+
+#define TSTCODE_GETREG8(reg_base, addr, value)\
+ do { \
+ isp_writel(reg_base, CSI2IF_PHY_TEST_CTRL1_REG,\
+ (1 << 16) | addr); \
+ isp_writel(reg_base, CSI2IF_PHY_TEST_CTRL0_REG, 2); \
+ isp_writel(reg_base, CSI2IF_PHY_TEST_CTRL0_REG, 0); \
+ (value) = \
+ ((isp_readl(reg_base, CSI2IF_PHY_TEST_CTRL1_REG) >> 8) &\
+ (0x000000ff)); \
+ } while (0)
+
+#define ISP_CSIPHY_NAME "isp_csiphy"
+
+struct csiphy_format {
+ u32 code;
+ u8 bpp;
+};
+
+static const struct csiphy_format csiphy_formats_8x16[] = {
+ { MEDIA_BUS_FMT_UYVY8_2X8, 8 },
+ { MEDIA_BUS_FMT_VYUY8_2X8, 8 },
+ { MEDIA_BUS_FMT_YUYV8_2X8, 8 },
+ { MEDIA_BUS_FMT_YVYU8_2X8, 8 },
+ { MEDIA_BUS_FMT_SBGGR8_1X8, 8 },
+ { MEDIA_BUS_FMT_SGBRG8_1X8, 8 },
+ { MEDIA_BUS_FMT_SGRBG8_1X8, 8 },
+ { MEDIA_BUS_FMT_SRGGB8_1X8, 8 },
+ { MEDIA_BUS_FMT_SBGGR10_1X10, 10 },
+ { MEDIA_BUS_FMT_SGBRG10_1X10, 10 },
+ { MEDIA_BUS_FMT_SGRBG10_1X10, 10 },
+ { MEDIA_BUS_FMT_SRGGB10_1X10, 10 },
+ { MEDIA_BUS_FMT_SBGGR12_1X12, 12 },
+ { MEDIA_BUS_FMT_SGBRG12_1X12, 12 },
+ { MEDIA_BUS_FMT_SGRBG12_1X12, 12 },
+ { MEDIA_BUS_FMT_SRGGB12_1X12, 12 },
+ { MEDIA_BUS_FMT_Y10_1X10, 10 },
+};
+
+static const struct csiphy_format csiphy_formats_8x96[] = {
+ { MEDIA_BUS_FMT_UYVY8_2X8, 8 },
+ { MEDIA_BUS_FMT_VYUY8_2X8, 8 },
+ { MEDIA_BUS_FMT_YUYV8_2X8, 8 },
+ { MEDIA_BUS_FMT_YVYU8_2X8, 8 },
+ { MEDIA_BUS_FMT_SBGGR8_1X8, 8 },
+ { MEDIA_BUS_FMT_SGBRG8_1X8, 8 },
+ { MEDIA_BUS_FMT_SGRBG8_1X8, 8 },
+ { MEDIA_BUS_FMT_SRGGB8_1X8, 8 },
+ { MEDIA_BUS_FMT_SBGGR10_1X10, 10 },
+ { MEDIA_BUS_FMT_SGBRG10_1X10, 10 },
+ { MEDIA_BUS_FMT_SGRBG10_1X10, 10 },
+ { MEDIA_BUS_FMT_SRGGB10_1X10, 10 },
+ { MEDIA_BUS_FMT_SBGGR12_1X12, 12 },
+ { MEDIA_BUS_FMT_SGBRG12_1X12, 12 },
+ { MEDIA_BUS_FMT_SGRBG12_1X12, 12 },
+ { MEDIA_BUS_FMT_SRGGB12_1X12, 12 },
+ { MEDIA_BUS_FMT_SBGGR14_1X14, 14 },
+ { MEDIA_BUS_FMT_SGBRG14_1X14, 14 },
+ { MEDIA_BUS_FMT_SGRBG14_1X14, 14 },
+ { MEDIA_BUS_FMT_SRGGB14_1X14, 14 },
+ { MEDIA_BUS_FMT_Y10_1X10, 10 },
+};
+
+static int csi2if_dphy_init(char __iomem *base, unsigned char settle_time)
+{
+ unsigned char value = 0;
+
+ if (settle_time > 0) { /* configure settle time mannually */
+ TSTCODE_SETREG8(base, LANE0_SETTLE, settle_time);
+ TSTCODE_SETREG8(base, LANE1_SETTLE, settle_time);
+ TSTCODE_SETREG8(base, LANE2_SETTLE, settle_time);
+ TSTCODE_SETREG8(base, LANE3_SETTLE, settle_time);
+ TSTCODE_SETREG8(base, CFG_CLK_DETECT, 0x01);
+ } else { /* enable clock detect */
+ TSTCODE_SETREG8(base, LANE0_SETTLE, 0x01);
+ TSTCODE_SETREG8(base, LANE0_ADDITION, 0x05);
+ TSTCODE_SETREG8(base, LANE1_SETTLE, 0x01);
+ TSTCODE_SETREG8(base, LANE1_ADDITION, 0x05);
+ TSTCODE_SETREG8(base, LANE2_SETTLE, 0x01);
+ TSTCODE_SETREG8(base, LANE2_ADDITION, 0x05);
+ TSTCODE_SETREG8(base, LANE3_SETTLE, 0x01);
+ TSTCODE_SETREG8(base, LANE3_ADDITION, 0x05);
+ }
+
+ /* setup time and hold time for dphy v1.2 */
+ TSTCODE_SETREG8(base, LANE0_DESKEW_1, 0x0D);
+ TSTCODE_SETREG8(base, LANE1_DESKEW_1, 0x0D);
+ TSTCODE_SETREG8(base, LANE2_DESKEW_1, 0x0D);
+ TSTCODE_SETREG8(base, LANE3_DESKEW_1, 0x0D);
+ TSTCODE_SETREG8(base, LANE0_DESKEW_3, 0x03);
+ TSTCODE_SETREG8(base, LANE1_DESKEW_3, 0x03);
+ TSTCODE_SETREG8(base, LANE2_DESKEW_3, 0x03);
+ TSTCODE_SETREG8(base, LANE3_DESKEW_3, 0x03);
+
+ TSTCODE_SETREG8(base, CFG_CLK_ATTR, 0x50);
+
+ TSTCODE_GETREG8(base, LANE0_SETTLE, value);
+ pr_info("### LANE0_SETTLE = %d", value);
+
+ TSTCODE_GETREG8(base, LANE1_SETTLE, value);
+ pr_info("### LANE1_SETTLE = %d", value);
+
+ TSTCODE_GETREG8(base, LANE2_SETTLE, value);
+ pr_info("### LANE2_SETTLE = %d", value);
+
+ TSTCODE_GETREG8(base, LANE3_SETTLE, value);
+ pr_info("### LANE3_SETTLE = %d", value);
+
+ TSTCODE_GETREG8(base, CFG_CLK_DETECT, value);
+ pr_info("### CFG_CLK_DETECT = 0x%x", value);
+
+ TSTCODE_GETREG8(base, CFG_CLK_ATTR, value);
+ pr_info("### CFG_CLK_ATTR = 0x%x", value);
+
+ return 0;
+}
+
+int csi2if_enable(struct csiphy_device *csiphy, unsigned char num_lanes,
+ unsigned char settle_time)
+{
+ unsigned int phy_rx;
+ unsigned int phy_state;
+
+ if (num_lanes > 4 || 0 == num_lanes) {
+ dev_err(csiphy->isp->dev, "number of lanes %d out of range!!\n",
+ num_lanes);
+ return -EINVAL;
+ }
+
+ /* de-assert the shutdown signal*/
+ isp_writel(csiphy->base, CSI2IF_PHY_SHUTDOWNZ_REG, 0);
+ isp_writel(csiphy->base, CSI2IF_DPHY_RSTZ_REG, 0);
+ isp_writel(csiphy->base, CSI2IF_CSI2_RESETN_REG, 0);
+
+ isp_writel(csiphy->base, CSI2IF_PHY_TEST_CTRL0_REG, 1);
+ isp_writel(csiphy->base, CSI2IF_PHY_TEST_CTRL0_REG, 0);
+ mdelay(1);
+
+ isp_writel(csiphy->base, CSI2IF_PHY_SHUTDOWNZ_REG, 1);
+ isp_writel(csiphy->base, CSI2IF_N_LANES_REG, (num_lanes-1));
+
+ isp_writel(csiphy->base, CSI2IF_DPHY_RSTZ_REG, 1);
+ isp_writel(csiphy->base, CSI2IF_CSI2_RESETN_REG, 1);
+
+ /* Configure HUAWEI D-PHY */
+ if (csi2if_dphy_init(csiphy->base, settle_time) < 0)
+ return -1;
+
+ /* confirm the D-PHY is in right state */
+ phy_rx = isp_readl(csiphy->base, CSI2IF_PHY_RX_REG);
+ phy_state = isp_readl(csiphy->base, CSI2IF_PHY_STOPSTATE_REG);
+
+ if ((isp_readl_field(phy_state, CSI2IF_PHY_STOPSTATEDATA_0) == 0) &&
+ (isp_readl_field(phy_state, CSI2IF_PHY_STOPSTATECLK) == 0)) {
+
+ pr_info("### not all data and clock lanes in stop state!\n");
+ pr_info("phy_rx = 0x%x, phy_state = %x\n", phy_rx, phy_state);
+ }
+
+ if (isp_readl_field(phy_state, CSI2IF_PHY_RXCLKACTIVEHS) == 0)
+ pr_info("### D-PHY is not receiving a clock!\n");
+
+ mdelay(1);
+
+ phy_rx = isp_readl(csiphy->base, CSI2IF_PHY_RX_REG);
+ phy_state = isp_readl(csiphy->base, CSI2IF_PHY_STOPSTATE_REG);
+ pr_info("### D-PHY state: phy_rx = 0x%x, phy_state = 0x%x\n",
+ phy_rx, phy_state);
+
+ return 0;
+}
+
+int csi2if_disable(struct csiphy_device *csiphy)
+{
+ isp_writel(csiphy->base, CSI2IF_CSI2_RESETN_REG, 0);
+ isp_writel(csiphy->base, CSI2IF_PHY_SHUTDOWNZ_REG, 0);
+
+ return 0;
+}
+
+int isp_ispss_reset_all(struct isp *isp)
+{
+ isp_writel(isp->ispss_ctrl, 0x060, 0xFFFFFFFF);
+ isp_writel(isp->ispss_ctrl, 0x064, 0xFFFFFFFF);
+ isp_writel(isp->ispss_ctrl, 0x068, 0xFFFFFFFF);
+ isp_writel(isp->ispss_ctrl, 0x06C, 0xFFFFFFFF);
+ isp_writel(isp->ispss_ctrl, 0x070, 0xFFFFFFFF);
+ isp_writel(isp->ispss_ctrl, 0x074, 0xFFFFFFFF);
+ isp_writel(isp->ispss_ctrl, 0x078, 0xFFFFFFFF);
+ isp_writel(isp->ispss_ctrl, 0x374, 0x00000003);
+
+ mdelay(1);
+
+ isp_writel(isp->ispss_ctrl, 0x060, 0x00000000);
+ isp_writel(isp->ispss_ctrl, 0x064, 0x00000000);
+ isp_writel(isp->ispss_ctrl, 0x068, 0x00000000);
+ isp_writel(isp->ispss_ctrl, 0x06C, 0x00000000);
+ isp_writel(isp->ispss_ctrl, 0x070, 0x00000000);
+ isp_writel(isp->ispss_ctrl, 0x074, 0x00000000);
+ isp_writel(isp->ispss_ctrl, 0x078, 0x00000000);
+ isp_writel(isp->ispss_ctrl, 0x374, 0x00000000);
+
+ mdelay(1);
+
+ return 0;
+
+}
+
+void isp_ispss_clk_enable(struct isp *isp)
+{
+ /* enable all clock of isp sub-modules */
+ isp_writel(isp->ispss_ctrl, 0x010, 0xffffffff);
+ isp_writel(isp->ispss_ctrl, 0x014, 0xffffffff);
+ isp_writel(isp->ispss_ctrl, 0x018, 0xffffffff);
+ isp_writel(isp->ispss_ctrl, 0x01C, 0xffffffff);
+ isp_writel(isp->ispss_ctrl, 0x020, 0xffffffff);
+ isp_writel(isp->ispss_ctrl, 0x024, 0xffffffff);
+ isp_writel(isp->ispss_ctrl, 0x028, 0xffffffff);
+ isp_writel(isp->ispss_ctrl, 0x364, 0x00000003);
+}
+
+/*
+ *
+ * csiphy_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 csiphy_set_power(struct v4l2_subdev *sd, int on)
+{
+ struct csiphy_device *csiphy = v4l2_get_subdevdata(sd);
+ struct isp *isp = csiphy->isp;
+ int ret = 0;
+
+ ret = isp_enable_clocks(isp->clks, isp->dev);
+ if (ret < 0)
+ return ret;
+
+ isp_ispss_clk_enable(isp);
+ mdelay(100);
+
+ usleep_range(5000, 15000);
+
+ return ret;
+}
+
+/*
+ * csiphy_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 csiphy_set_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct csiphy_device *csiphy = v4l2_get_subdevdata(sd);
+ struct isp *isp = csiphy->isp;
+ int ret;
+
+ isp_ispss_reset_all(isp);
+ mdelay(100);
+
+ ret = csi2if_enable(csiphy, 2, 0);
+ if (ret < 0)
+ return ret;
+
+ isp_ispss_clear_irq_state(isp);
+
+ isp_ispss_enable_irq(isp);
+
+ pr_info("%s: %d\n", __func__, __LINE__);
+ return ret;
+}
+
+/*
+ * csiphy_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 csiphy_init_formats(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ struct v4l2_subdev_format format = {
+ .pad = ISP_CSIPHY_PAD_SINK,
+ .which = fh ? V4L2_SUBDEV_FORMAT_TRY :
+ V4L2_SUBDEV_FORMAT_ACTIVE,
+ .format = {
+ .code = MEDIA_BUS_FMT_UYVY8_2X8,
+ .width = 1920,
+ .height = 1080
+ }
+ };
+
+ return 0;
+}
+
+/*
+ * isp_csiphy_subdev_init - Initialize CSIPHY device structure and resources
+ * @csiphy: CSIPHY device
+ * @res: CSIPHY module resources table
+ * @id: CSIPHY module id
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+int isp_csiphy_subdev_init(struct isp *isp,
+ struct csiphy_device *csiphy,
+ const struct resources *res, u8 id)
+{
+ struct device *dev = isp->dev;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct resource *r;
+
+ csiphy->isp = isp;
+ csiphy->id = id;
+
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg);
+ csiphy->base = devm_ioremap_resource(dev, r);
+ if (IS_ERR(csiphy->base)) {
+ dev_err(dev, "could not map memory\n");
+ return PTR_ERR(csiphy->base);
+ }
+
+ return 0;
+}
+
+/*
+ * csiphy_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 csiphy_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 csiphy_device *csiphy;
+ struct sr_device *sr;
+
+ if (media_entity_remote_pad(local))
+ return -EBUSY;
+
+ sd = media_entity_to_v4l2_subdev(entity);
+ csiphy = v4l2_get_subdevdata(sd);
+
+ sd = media_entity_to_v4l2_subdev(remote->entity);
+ sr = v4l2_get_subdevdata(sd);
+ }
+
+ return 0;
+}
+
+static const struct v4l2_subdev_core_ops csiphy_core_ops = {
+ .s_power = csiphy_set_power,
+};
+
+static const struct v4l2_subdev_video_ops csiphy_video_ops = {
+ .s_stream = csiphy_set_stream,
+};
+
+static const struct v4l2_subdev_ops csiphy_v4l2_ops = {
+ .core = &csiphy_core_ops,
+ .video = &csiphy_video_ops,
+};
+
+static const struct v4l2_subdev_internal_ops csiphy_v4l2_internal_ops = {
+ .open = csiphy_init_formats,
+};
+
+static const struct media_entity_operations csiphy_media_ops = {
+ .link_setup = csiphy_link_setup,
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+/*
+ * isp_csiphy_register_entity - Register subdev node for CSIPHY module
+ * @csiphy: CSIPHY device
+ * @v4l2_dev: V4L2 device
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+int isp_csiphy_register_entity(struct csiphy_device *csiphy,
+ struct v4l2_device *v4l2_dev)
+{
+ struct v4l2_subdev *sd = &csiphy->subdev;
+ struct media_pad *pads = csiphy->pads;
+ struct device *dev = csiphy->isp->dev;
+ int ret;
+
+ v4l2_subdev_init(sd, &csiphy_v4l2_ops);
+ sd->internal_ops = &csiphy_v4l2_internal_ops;
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ snprintf(sd->name, ARRAY_SIZE(sd->name), "%s%d",
+ ISP_CSIPHY_NAME, csiphy->id);
+ v4l2_set_subdevdata(sd, csiphy);
+
+ ret = csiphy_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 = &csiphy_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_csiphy_unregister_entity - Unregister CSIPHY module subdev node
+ * @csiphy: CSIPHY device
+ */
+void isp_csiphy_unregister_entity(struct csiphy_device *csiphy)
+{
+ v4l2_device_unregister_subdev(&csiphy->subdev);
+ media_entity_cleanup(&csiphy->subdev.entity);
+}
diff --git a/drivers/media/platform/hisi/isp/isp-csiphy.h b/drivers/media/platform/hisi/isp/isp-csiphy.h
new file mode 100644
index 000000000000..2382ca2de585
--- /dev/null
+++ b/drivers/media/platform/hisi/isp/isp-csiphy.h
@@ -0,0 +1,149 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 Linaro Ltd.
+ */
+
+#ifndef HISI_ISP_CSIPHY_H
+#define HISI_ISP_CSIPHY_H
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <media/media-entity.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mediabus.h>
+#include <media/v4l2-subdev.h>
+
+#define ISP_CSIPHY_PAD_SINK 0
+#define ISP_CSIPHY_PAD_SRC 1
+#define ISP_CSIPHY_PADS_NUM 2
+
+/* CSI2IF Registers */
+#define CSI2IF_VERSION_REG 0x0
+#define CSI2IF_N_LANES_REG 0x4
+#define CSI2IF_CSI2_RESETN_REG 0x8
+#define CSI2IF_INT_ST_MAIN_REG 0xC
+#define CSI2IF_DATA_IDS_1_REG 0x10
+#define CSI2IF_PHY_SHUTDOWNZ_REG 0x40
+#define CSI2IF_DPHY_RSTZ_REG 0x44
+#define CSI2IF_PHY_RX_REG 0x48
+#define CSI2IF_PHY_STOPSTATE_REG 0x4C
+#define CSI2IF_PHY_TEST_CTRL0_REG 0x50
+#define CSI2IF_PHY_TEST_CTRL1_REG 0x54
+#define CSI2IF_PHY_CAL_REG 0xCC
+#define CSI2IF_INT_ST_PHY_FATAL_REG 0xE0
+#define CSI2IF_INT_MSK_PHY_FATAL_REG 0xE4
+#define CSI2IF_INT_FORCE_PHY_FATAL_REG 0xE8
+#define CSI2IF_INT_ST_PKT_FATAL_REG 0xF0
+#define CSI2IF_INT_MSK_PKT_FATAL_REG 0xF4
+#define CSI2IF_INT_FORCE_PKT_FATAL_REG 0xF8
+#define CSI2IF_INT_ST_FRAME_FATAL_REG 0x100
+#define CSI2IF_INT_MSK_FRAME_FATAL_REG 0x104
+#define CSI2IF_INT_FORCE_FRAME_FATAL_REG 0x108
+#define CSI2IF_INT_ST_PHY_REG 0x110
+#define CSI2IF_INT_MSK_PHY_REG 0x114
+#define CSI2IF_INT_FORCE_PHY_REG 0x118
+#define CSI2IF_INT_ST_PKT_REG 0x120
+#define CSI2IF_INT_MSK_PKT_REG 0x124
+#define CSI2IF_INT_FORCE_PKT_REG 0x128
+#define CSI2IF_INT_ST_LINE_REG 0x130
+#define CSI2IF_INT_MSK_LINE_REG 0x134
+#define CSI2IF_INT_FORCE_LINE_REG 0x138
+
+/* CSI2IF_PHY_STOPSTATE_REG Register bits */
+#define CSI2IF_PHY_STOPSTATEDATA_0_OFFSET 0
+#define CSI2IF_PHY_STOPSTATEDATA_0_LEN 1
+#define CSI2IF_PHY_STOPSTATECLK_OFFSET 16
+#define CSI2IF_PHY_STOPSTATECLK_LEN 1
+#define CSI2IF_PHY_RXCLKACTIVEHS_OFFSET 17
+#define CSI2IF_PHY_RXCLKACTIVEHS_LEN 1
+
+#define CSI_INDEX_CNT (3)
+
+#define CFG_CLK_ATTR (0x01)
+#define CFG_CLK_DETECT (0x0A)
+#define CFG_DESKEW_1 (0x0B)
+#define CFG_DESKEW_2 (0x0F)
+#define LANE0_SETTLE (0x30)
+#define LANE0_MISC (0x31)
+#define LANE0_ADDITION (0x32)
+#define LANE0_DESKEW_1 (0x3A)
+#define LANE0_DESKEW_2 (0x3B)
+#define LANE0_DESKEW_3 (0x3C)
+#define LANE1_SETTLE (0x40)
+#define LANE1_MISC (0x41)
+#define LANE1_ADDITION (0x42)
+#define LANE1_DESKEW_1 (0x4A)
+#define LANE1_DESKEW_2 (0x4B)
+#define LANE1_DESKEW_3 (0x4C)
+#define LANE2_SETTLE (0x50)
+#define LANE2_MISC (0x51)
+#define LANE2_ADDITION (0x52)
+#define LANE2_DESKEW_1 (0x5A)
+#define LANE2_DESKEW_2 (0x5B)
+#define LANE2_DESKEW_3 (0x5C)
+#define LANE3_SETTLE (0x60)
+#define LANE3_MISC (0x61)
+#define LANE3_ADDITION (0x62)
+#define LANE3_DESKEW_1 (0x6A)
+#define LANE3_DESKEW_2 (0x6B)
+#define LANE3_DESKEW_3 (0x6C)
+
+struct csiphy_lane {
+ u8 pos;
+ u8 pol;
+};
+
+struct csiphy_lanes_cfg {
+ int num_data;
+ struct csiphy_lane *data;
+ struct csiphy_lane clk;
+};
+
+struct csiphy_csi2_cfg {
+ struct csiphy_lanes_cfg lane_cfg;
+};
+
+struct csiphy_config {
+ u8 combo_mode;
+ u8 csid_id;
+ struct csiphy_csi2_cfg *csi2;
+};
+
+struct csiphy_device;
+
+struct csiphy_hw_ops {
+ void (*csi2_enable)(struct csiphy_device *csiphy,
+ struct csiphy_config *cfg);
+ void (*csi2_disable)(struct csiphy_device *csiphy,
+ struct csiphy_config *cfg);
+};
+
+struct csiphy_device {
+ struct isp *isp;
+ u8 id;
+ struct v4l2_subdev subdev;
+ struct media_pad pads[ISP_CSIPHY_PADS_NUM];
+ void __iomem *base;
+ u32 irq;
+ char irq_name[30];
+ struct isp_clock *clock;
+ int nclocks;
+ struct csiphy_config cfg;
+ struct v4l2_mbus_framefmt fmt[ISP_CSIPHY_PADS_NUM];
+ const struct csiphy_hw_ops *ops;
+ const struct csiphy_format *formats;
+ unsigned int nformats;
+};
+
+struct resources;
+
+int isp_csiphy_subdev_init(struct isp *isp,
+ struct csiphy_device *csiphy,
+ const struct resources *res, u8 id);
+
+int isp_csiphy_register_entity(struct csiphy_device *csiphy,
+ struct v4l2_device *v4l2_dev);
+
+void isp_csiphy_unregister_entity(struct csiphy_device *csiphy);
+
+#endif /* HISI_ISP_CSIPHY_H */
diff --git a/drivers/media/platform/hisi/isp/isp-cvdr.c b/drivers/media/platform/hisi/isp/isp-cvdr.c
new file mode 100644
index 000000000000..666dd016028f
--- /dev/null
+++ b/drivers/media/platform/hisi/isp/isp-cvdr.c
@@ -0,0 +1,455 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * isp-cvdr.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_CVDR_NAME "isp_cvdr"
+
+struct cvdr_opt_bw_t cvdr_vp_wr_bw[CVDR_VP_WR_NBR] = {
+ [W12_1] = {CVDR_SRT, ISP_CLK, ISP_CLK},
+ [W12_2] = {CVDR_SRT, ISP_CLK, ISP_CLK},
+ [W6_1] = {CVDR_SRT, 480, (float)DERATE*480*2},
+ [W6_2] = {CVDR_SRT, 480, (float)DERATE*480*2},
+ [W5_1_1] = {CVDR_SRT, 480, (float)DERATE*480},
+ [W5_1_2] = {CVDR_SRT, 480, (float)DERATE*480},
+ [W4_1_1] = {CVDR_SRT, 480, (float)DERATE*480},
+ [W4_1_2] = {CVDR_SRT, 480, (float)DERATE*480},
+ [W4_2_1] = {CVDR_SRT, 480, (float)DERATE*480},
+ [W4_2_2] = {CVDR_SRT, 480, (float)DERATE*480},
+ [W7_1] = {CVDR_SRT, 480, (float)DERATE*480},
+ [W13_1] = {CVDR_SRT, ISP_CLK, ISP_CLK},
+ [W13_2] = {CVDR_SRT, ISP_CLK, ISP_CLK},
+ [W1_1] = {CVDR_RT, 720, 720*2},
+ [W1_2] = {CVDR_RT, 720, 720*2},
+ [W14_1] = {CVDR_RT, 720, 720*2},
+ [W14_2] = {CVDR_RT, 720, 720*2},
+ [W11_1] = {CVDR_RT, 585, ISP_CLK},
+ [W11_2] = {CVDR_RT, 585, ISP_CLK},
+ [W2_3] = {CVDR_RT, 720, 720*2},
+ [W2_4] = {CVDR_RT, 720, 720*2},
+ [W2_5] = {CVDR_RT, 720, 720*2},
+ [W8_1] = {CVDR_SRT, ISP_CLK, ISP_CLK},
+ [W3_1] = {CVDR_RT, 480/4, 4*480/29},
+ [W2_2] = {CVDR_RT, 720, 720*2},
+ [W2_1] = {CVDR_RT, 720, 720*2},
+ [W15_1] = {CVDR_RT, 585, 374},
+ [W16_1] = {CVDR_RT, 585, 187},
+ [W16_2] = {CVDR_RT, 585, 187},
+ [W17_1] = {CVDR_RT, 585, ISP_CLK},
+ [W17_2] = {CVDR_RT, 585, ISP_CLK},
+ [W19_1] = {CVDR_RT, ISP_CLK, (float)DERATE*ISP_CLK*16/8},
+ [W19_2] = {CVDR_RT, ISP_CLK, (float)DERATE*ISP_CLK*16/8},
+ [W20_1] = {CVDR_RT, ISP_CLK, ISP_CLK},
+ [W20_2] = {CVDR_RT, ISP_CLK, ISP_CLK},
+};
+
+struct cvdr_opt_bw_t cvdr_vp_rd_bw[CVDR_VP_RD_NBR] = {
+ [R3_1] = {CVDR_SRT, ISP_CLK, ISP_CLK},
+ [R11_1] = {CVDR_SRT, ISP_CLK, ISP_CLK},
+ [R12_1] = {CVDR_SRT, ISP_CLK, ISP_CLK},
+ [R11_2] = {CVDR_SRT, ISP_CLK, ISP_CLK},
+ [R12_2] = {CVDR_SRT, ISP_CLK, ISP_CLK},
+ [R10_1] = {CVDR_RT, ISP_CLK, ISP_CLK},
+ [R10_2] = {CVDR_RT, ISP_CLK, ISP_CLK},
+ [R2_1] = {CVDR_RT, ISP_CLK, ISP_CLK*2},
+ [R8_1_1] = {CVDR_SRT, ISP_CLK, ISP_CLK*2*DERATE},
+ [R8_2_1] = {CVDR_SRT, ISP_CLK, ISP_CLK*2*DERATE},
+ [R8_1_2] = {CVDR_SRT, ISP_CLK, ISP_CLK*2*DERATE},
+ [R8_2_2] = {CVDR_SRT, ISP_CLK, ISP_CLK*2*DERATE},
+ [R13_1] = {CVDR_RT, ISP_CLK, ISP_CLK},
+ [R13_2] = {CVDR_RT, ISP_CLK, ISP_CLK},
+ [R5_1_4] = {CVDR_SRT, 240, (float)DERATE*2*240},
+ [R5_1_5] = {CVDR_SRT, 240, (float)DERATE*1.5*240},
+ [R5_1_6] = {CVDR_SRT, 240, (float)DERATE*1.5*240},
+};
+
+int cvdr_set_vp_wr_ready(char __iomem *base,
+ unsigned char port,
+ struct cvdr_wr_fmt_desc_t *desc,
+ struct cvdr_bw_cfg_t *bw)
+{
+ union U_VP_WR_CFG tmp_cfg;
+ union U_VP_WR_AXI_FS tmp_fs;
+ union U_VP_WR_AXI_LINE tmp_line;
+ union U_LIMITER_VP_WR tmp_limiter;
+ u32 reg_addr;
+
+ if (desc->fs_addr & 0xF) {
+ pr_err("failed\n");
+ return -1;
+ }
+
+ tmp_cfg.u32 = 0;
+ tmp_fs.u32 = 0;
+ tmp_line.u32 = 0;
+ tmp_limiter.u32 = 0;
+
+ if (!bw) {
+ pr_err("vdr_bw_cfg_t* bw NULL!\n");
+ return -1;
+ }
+
+ tmp_cfg.bits.vpwr_pixel_format = desc->pix_fmt;
+ tmp_cfg.bits.vpwr_pixel_expansion = desc->pix_expan;
+ tmp_cfg.bits.vpwr_last_page = desc->last_page;
+
+ tmp_fs.bits.vpwr_address_frame_start = desc->fs_addr >> 4;
+
+ tmp_line.bits.vpwr_line_stride = desc->line_stride;
+ tmp_line.bits.vpwr_line_wrap = desc->line_wrap;
+
+ tmp_limiter.bits.vpwr_access_limiter_0 = bw->bw_limiter0;
+ tmp_limiter.bits.vpwr_access_limiter_1 = bw->bw_limiter1;
+ tmp_limiter.bits.vpwr_access_limiter_2 = bw->bw_limiter2;
+ tmp_limiter.bits.vpwr_access_limiter_3 = bw->bw_limiter3;
+ tmp_limiter.bits.vpwr_access_limiter_reload = bw->bw_limiter_reload;
+
+ switch (port) {
+ /*VP_WR @CVDR_SRT&CMDLST TO CONFIG */
+ case W4_1_1:
+ case W4_1_2:
+ case W4_2_1:
+ case W4_2_2:
+ case W5_1_1:
+ case W5_1_2:
+ case W19_1:
+ case W19_2:
+ case W6_1:
+ case W6_2:
+ case W7_1:
+ case W3_1:
+ pr_err("not support yet\n");
+ break;
+
+ default:
+ reg_addr = CVDR_CVDR_LIMITER_VP_WR_0_REG +
+ ONE_REG_OFFSET * port;
+ isp_writel(base, reg_addr, tmp_limiter.u32);
+ reg_addr = CVDR_CVDR_VP_WR_CFG_0_REG +
+ VP_WR_REG_OFFSET * port;
+ isp_writel(base, reg_addr, tmp_cfg.u32);
+ reg_addr = CVDR_CVDR_VP_WR_AXI_LINE_0_REG +
+ VP_WR_REG_OFFSET * port;
+ isp_writel(base, reg_addr, tmp_line.u32);
+ reg_addr = CVDR_CVDR_VP_WR_AXI_FS_0_REG +
+ VP_WR_REG_OFFSET * port;
+ isp_writel(base, reg_addr, tmp_fs.u32);
+ break;
+ }
+
+ return 0;
+}
+
+void isp_cvdr_config(struct cvdr_device *cvdr, dma_addr_t hw_addr)
+{
+ struct cvdr_wr_fmt_desc_t cvdr_wr_fmt = {
+ .fs_addr = hw_addr,
+ .pix_fmt = DF_D32,
+ .pix_expan = 0,
+ .last_page = (1920 * 1080 * 2 + hw_addr) >> 15,
+ .line_stride = 1920*2/CVDR_ALIGN_BYTES - 1,
+ .line_wrap = 8000,
+ };
+ struct cvdr_bw_cfg_t cvdr_bw = {0xF, 0xF, 0xF, 0xF, 0xF};
+
+ cvdr_set_vp_wr_ready(cvdr->cvdr_rt, W2_4, &cvdr_wr_fmt, &cvdr_bw);
+}
+
+void isp_cvdr_init(struct cvdr_device *cvdr)
+{
+ unsigned int i;
+ unsigned int prefetch_bypass;
+ char __iomem *base;
+ unsigned int reg_val;
+
+ prefetch_bypass = 1;
+
+ for (i = 0; i < CVDR_VP_WR_NBR; ++i) {
+ base = ((cvdr_vp_wr_bw[i].srt == CVDR_SRT) ?
+ cvdr->cvdr_srt : cvdr->cvdr_rt);
+
+ reg_val = isp_readl(base, CVDR_SRT_VP_WR_IF_CFG_0_REG + 0x10 * i);
+ reg_val = (reg_val & 0x7FFFFFFF) | (prefetch_bypass << 31);
+ isp_writel(base, CVDR_SRT_VP_WR_IF_CFG_0_REG + 0x10 * i, reg_val);
+ }
+
+ for (i = 0; i < CVDR_VP_RD_NBR; ++i) {
+ base = ((cvdr_vp_rd_bw[i].srt == CVDR_SRT) ?
+ cvdr->cvdr_srt : cvdr->cvdr_rt);
+ reg_val = isp_readl(base, CVDR_SRT_VP_RD_IF_CFG_0_REG + 0x20 * i);
+ reg_val = (reg_val & 0x7FFFFFFF) | (prefetch_bypass << 31);
+ isp_writel(base, CVDR_SRT_VP_RD_IF_CFG_0_REG + 0x20 * i, reg_val);
+ }
+
+ /* CVDR RT*/
+ isp_writel(cvdr->cvdr_rt, CVDR_RT_CVDR_CFG_REG,
+ (1 << 0)
+ | (64 << 8)
+ | (11 << 16)
+ | (11 << 24)
+ );
+
+ /* CVDR SRT*/
+ isp_writel(cvdr->cvdr_srt, CVDR_SRT_CVDR_CFG_REG,
+ (1 << 0)
+ | (34 << 8)
+ | (19 << 16)
+ | (11 << 24)
+ );
+
+ isp_writel(cvdr->cvdr_rt, 0x00C, 0xf8765432);
+ isp_writel(cvdr->cvdr_rt, 0x010, 0xf8122334);
+
+ isp_writel(cvdr->cvdr_srt, 0x00C, 0xd0765432);
+ isp_writel(cvdr->cvdr_srt, 0x010, 0xd0122334);
+
+ isp_writel(cvdr->sub_ctrl, 0x190, 0x00026e10);
+ isp_writel(cvdr->sub_ctrl, 0x194, 0x0000021f);
+
+ isp_writel(cvdr->sub_ctrl, 0x198, 0x00027210);
+ isp_writel(cvdr->sub_ctrl, 0x19C, 0x0000024e);
+}
+
+/*
+ * cvdr_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 cvdr_set_power(struct v4l2_subdev *sd, int on)
+{
+
+ pr_info("%s: %d\n", __func__, __LINE__);
+ return 0;
+}
+
+/*
+ * cvdr_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 cvdr_set_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct cvdr_device *cvdr = v4l2_get_subdevdata(sd);
+ struct isp *isp = cvdr->isp;
+ int ret = 0;
+
+ enable_irq(cvdr->irq_vic1);
+ isp_cvdr_init(cvdr);
+ isp_cvdr_config(cvdr, isp->hw_addr);
+ pr_info("%s: %d\n", __func__, __LINE__);
+
+ return ret;
+}
+
+/*
+ * cvdr_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 cvdr_init_formats(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ return 0;
+}
+
+irqreturn_t isp_vic1_handler(int irq, void *dev)
+{
+ struct cvdr_device *cvdr = dev;
+ struct isp *isp = cvdr->isp;
+ unsigned int val = isp_clear_irq(isp, IRQ_MERGER_DEBUG_1);
+
+ if (val & (1 << IRQ_MERGER_SR_4_CVDR_RT_SOF_VPWR_23_OFFSET))
+ isp_cvdr_config(cvdr,
+ isp->hw_addr + frame_num2Offset(isp, isp->frame_num + 1));
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * isp_cvdr_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_cvdr_subdev_init(struct isp *isp,
+ struct cvdr_device *cvdr,
+ const struct resources *res)
+{
+ struct device *dev = isp->dev;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct resource *r;
+ int ret;
+
+ cvdr->isp = isp;
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res[0].reg);
+ cvdr->cvdr_rt = devm_ioremap_resource(dev, r);
+ if (IS_ERR(cvdr->cvdr_rt)) {
+ dev_err(dev, "could not map memory\n");
+ return PTR_ERR(cvdr->cvdr_rt);
+ }
+
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res[1].reg);
+ cvdr->cvdr_srt = devm_ioremap_resource(dev, r);
+ if (IS_ERR(cvdr->cvdr_srt)) {
+ dev_err(dev, "could not map memory\n");
+ return PTR_ERR(cvdr->cvdr_srt);
+ }
+
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res[2].reg);
+ cvdr->sub_ctrl = devm_ioremap_resource(dev, r);
+ if (IS_ERR(cvdr->sub_ctrl)) {
+ dev_err(dev, "could not map memory\n");
+ return PTR_ERR(cvdr->sub_ctrl);
+ }
+
+ ret = platform_get_irq_byname(pdev, "isp_vic1");
+ if (ret <= 0) {
+ dev_err(isp->dev, "No IRQ resource\n");
+ return -ENODEV;
+ }
+
+ cvdr->irq_vic1 = ret;
+
+ ret = devm_request_irq(&pdev->dev, cvdr->irq_vic1,
+ isp_vic1_handler, 0, "isp-vic1", cvdr);
+ if (ret)
+ return ret;
+
+ disable_irq(cvdr->irq_vic1);
+
+ return 0;
+}
+
+/*
+ * cvdr_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 cvdr_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 cvdr_device *cvdr;
+
+ if (media_entity_remote_pad(local))
+ return -EBUSY;
+
+ sd = media_entity_to_v4l2_subdev(entity);
+ cvdr = v4l2_get_subdevdata(sd);
+ }
+
+ return 0;
+}
+
+static const struct v4l2_subdev_core_ops cvdr_core_ops = {
+ .s_power = cvdr_set_power,
+};
+
+static const struct v4l2_subdev_video_ops cvdr_video_ops = {
+ .s_stream = cvdr_set_stream,
+};
+
+static const struct v4l2_subdev_ops cvdr_v4l2_ops = {
+ .core = &cvdr_core_ops,
+ .video = &cvdr_video_ops,
+};
+
+static const struct v4l2_subdev_internal_ops cvdr_v4l2_internal_ops = {
+ .open = cvdr_init_formats,
+};
+
+static const struct media_entity_operations cvdr_media_ops = {
+ .link_setup = cvdr_link_setup,
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+/*
+ * isp_cvdr_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_cvdr_register_entity(struct cvdr_device *cvdr,
+ struct v4l2_device *v4l2_dev)
+{
+ struct v4l2_subdev *sd = &cvdr->subdev;
+ struct media_pad *pads = cvdr->pads;
+ struct device *dev = cvdr->isp->dev;
+ int ret;
+
+ v4l2_subdev_init(sd, &cvdr_v4l2_ops);
+ sd->internal_ops = &cvdr_v4l2_internal_ops;
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ snprintf(sd->name, ARRAY_SIZE(sd->name), "%s",
+ ISP_CVDR_NAME);
+ v4l2_set_subdevdata(sd, cvdr);
+
+ ret = cvdr_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 = &cvdr_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_cvdr_unregister_entity - Unregister CSIPHY module subdev node
+ * @sr: CSIPHY device
+ */
+void isp_cvdr_unregister_entity(struct cvdr_device *cvdr)
+{
+ v4l2_device_unregister_subdev(&cvdr->subdev);
+ media_entity_cleanup(&cvdr->subdev.entity);
+}
diff --git a/drivers/media/platform/hisi/isp/isp-cvdr.h b/drivers/media/platform/hisi/isp/isp-cvdr.h
new file mode 100644
index 000000000000..8824a7c39ba1
--- /dev/null
+++ b/drivers/media/platform/hisi/isp/isp-cvdr.h
@@ -0,0 +1,951 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2016-2018 Linaro Ltd.
+ */
+
+#ifndef HISI_ISP_CVDR_H
+#define HISI_ISP_CVDR_H
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <media/media-entity.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mediabus.h>
+#include <media/v4l2-subdev.h>
+
+#define ISP_CVDR_PAD_SINK 0
+#define ISP_CVDR_PAD_SRC 1
+#define ISP_CVDR_PADS_NUM 1
+
+#define CVDR_SRT_CVDR_CFG_REG 0x0
+#define CVDR_RT_CVDR_CFG_REG 0x0
+#define CVDR_SRT_VP_WR_IF_CFG_0_REG 0x28
+#define CVDR_SRT_VP_RD_IF_CFG_0_REG 0x514
+
+#define CVDR_CVDR_CVDR_CFG_REG 0x0
+#define CVDR_CVDR_CVDR_DEBUG_EN_REG 0x4
+#define CVDR_CVDR_CVDR_DEBUG_REG 0x8
+#define CVDR_CVDR_CVDR_WR_QOS_CFG_REG 0xC
+#define CVDR_CVDR_CVDR_RD_QOS_CFG_REG 0x10
+#define CVDR_CVDR_OTHER_RO_REG 0x14
+#define CVDR_CVDR_OTHER_RW_REG 0x18
+#define CVDR_CVDR_VP_WR_CFG_0_REG 0x1C
+#define CVDR_CVDR_VP_WR_AXI_FS_0_REG 0x20
+#define CVDR_CVDR_VP_WR_AXI_LINE_0_REG 0x24
+#define CVDR_CVDR_VP_WR_IF_CFG_0_REG 0x28
+#define CVDR_CVDR_VP_WR_CFG_1_REG 0x2C
+#define CVDR_CVDR_VP_WR_AXI_FS_1_REG 0x30
+#define CVDR_CVDR_VP_WR_AXI_LINE_1_REG 0x34
+#define CVDR_CVDR_VP_WR_IF_CFG_1_REG 0x38
+#define CVDR_CVDR_VP_WR_CFG_2_REG 0x3C
+#define CVDR_CVDR_VP_WR_AXI_FS_2_REG 0x40
+#define CVDR_CVDR_VP_WR_AXI_LINE_2_REG 0x44
+#define CVDR_CVDR_VP_WR_IF_CFG_2_REG 0x48
+#define CVDR_CVDR_VP_WR_CFG_3_REG 0x4C
+#define CVDR_CVDR_VP_WR_AXI_FS_3_REG 0x50
+#define CVDR_CVDR_VP_WR_AXI_LINE_3_REG 0x54
+#define CVDR_CVDR_VP_WR_IF_CFG_3_REG 0x58
+#define CVDR_CVDR_VP_WR_CFG_4_REG 0x5C
+#define CVDR_CVDR_VP_WR_AXI_FS_4_REG 0x60
+#define CVDR_CVDR_VP_WR_AXI_LINE_4_REG 0x64
+#define CVDR_CVDR_VP_WR_IF_CFG_4_REG 0x68
+#define CVDR_CVDR_VP_WR_CFG_5_REG 0x6C
+#define CVDR_CVDR_VP_WR_AXI_FS_5_REG 0x70
+#define CVDR_CVDR_VP_WR_AXI_LINE_5_REG 0x74
+#define CVDR_CVDR_VP_WR_IF_CFG_5_REG 0x78
+#define CVDR_CVDR_VP_WR_CFG_8_REG 0x9C
+#define CVDR_CVDR_VP_WR_AXI_FS_8_REG 0xA0
+#define CVDR_CVDR_VP_WR_AXI_LINE_8_REG 0xA4
+#define CVDR_CVDR_VP_WR_IF_CFG_8_REG 0xA8
+#define CVDR_CVDR_VP_WR_CFG_9_REG 0xAC
+#define CVDR_CVDR_VP_WR_AXI_FS_9_REG 0xB0
+#define CVDR_CVDR_VP_WR_AXI_LINE_9_REG 0xB4
+#define CVDR_CVDR_VP_WR_IF_CFG_9_REG 0xB8
+#define CVDR_CVDR_VP_WR_CFG_10_REG 0xBC
+#define CVDR_CVDR_VP_WR_AXI_FS_10_REG 0xC0
+#define CVDR_CVDR_VP_WR_AXI_LINE_10_REG 0xC4
+#define CVDR_CVDR_VP_WR_IF_CFG_10_REG 0xC8
+#define CVDR_CVDR_VP_WR_CFG_11_REG 0xCC
+#define CVDR_CVDR_VP_WR_AXI_FS_11_REG 0xD0
+#define CVDR_CVDR_VP_WR_AXI_LINE_11_REG 0xD4
+#define CVDR_CVDR_VP_WR_IF_CFG_11_REG 0xD8
+#define CVDR_CVDR_VP_WR_CFG_12_REG 0xDC
+#define CVDR_CVDR_VP_WR_AXI_FS_12_REG 0xE0
+#define CVDR_CVDR_VP_WR_AXI_LINE_12_REG 0xE4
+#define CVDR_CVDR_VP_WR_IF_CFG_12_REG 0xE8
+#define CVDR_CVDR_VP_WR_CFG_14_REG 0xFC
+#define CVDR_CVDR_VP_WR_AXI_FS_14_REG 0x100
+#define CVDR_CVDR_VP_WR_AXI_LINE_14_REG 0x104
+#define CVDR_CVDR_VP_WR_IF_CFG_14_REG 0x108
+#define CVDR_CVDR_VP_WR_CFG_15_REG 0x10C
+#define CVDR_CVDR_VP_WR_AXI_FS_15_REG 0x110
+#define CVDR_CVDR_VP_WR_AXI_LINE_15_REG 0x114
+#define CVDR_CVDR_VP_WR_IF_CFG_15_REG 0x118
+#define CVDR_CVDR_VP_WR_CFG_16_REG 0x11C
+#define CVDR_CVDR_VP_WR_AXI_FS_16_REG 0x120
+#define CVDR_CVDR_VP_WR_AXI_LINE_16_REG 0x124
+#define CVDR_CVDR_VP_WR_IF_CFG_16_REG 0x128
+#define CVDR_CVDR_VP_WR_CFG_17_REG 0x12C
+#define CVDR_CVDR_VP_WR_AXI_FS_17_REG 0x130
+#define CVDR_CVDR_VP_WR_AXI_LINE_17_REG 0x134
+#define CVDR_CVDR_VP_WR_IF_CFG_17_REG 0x138
+#define CVDR_CVDR_VP_WR_CFG_18_REG 0x13C
+#define CVDR_CVDR_VP_WR_AXI_FS_18_REG 0x140
+#define CVDR_CVDR_VP_WR_AXI_LINE_18_REG 0x144
+#define CVDR_CVDR_VP_WR_IF_CFG_18_REG 0x148
+#define CVDR_CVDR_VP_WR_CFG_19_REG 0x14C
+#define CVDR_CVDR_VP_WR_AXI_FS_19_REG 0x150
+#define CVDR_CVDR_VP_WR_AXI_LINE_19_REG 0x154
+#define CVDR_CVDR_VP_WR_IF_CFG_19_REG 0x158
+#define CVDR_CVDR_VP_WR_CFG_20_REG 0x15C
+#define CVDR_CVDR_VP_WR_AXI_FS_20_REG 0x160
+#define CVDR_CVDR_VP_WR_AXI_LINE_20_REG 0x164
+#define CVDR_CVDR_VP_WR_IF_CFG_20_REG 0x168
+#define CVDR_CVDR_VP_WR_CFG_21_REG 0x16C
+#define CVDR_CVDR_VP_WR_AXI_FS_21_REG 0x170
+#define CVDR_CVDR_VP_WR_AXI_LINE_21_REG 0x174
+#define CVDR_CVDR_VP_WR_IF_CFG_21_REG 0x178
+#define CVDR_CVDR_VP_WR_CFG_22_REG 0x17C
+#define CVDR_CVDR_VP_WR_AXI_FS_22_REG 0x180
+#define CVDR_CVDR_VP_WR_AXI_LINE_22_REG 0x184
+#define CVDR_CVDR_VP_WR_IF_CFG_22_REG 0x188
+#define CVDR_CVDR_VP_WR_CFG_23_REG 0x18C
+#define CVDR_CVDR_VP_WR_AXI_FS_23_REG 0x190
+#define CVDR_CVDR_VP_WR_AXI_LINE_23_REG 0x194
+#define CVDR_CVDR_VP_WR_IF_CFG_23_REG 0x198
+#define CVDR_CVDR_VP_WR_CFG_24_REG 0x19C
+#define CVDR_CVDR_VP_WR_AXI_FS_24_REG 0x1A0
+#define CVDR_CVDR_VP_WR_AXI_LINE_24_REG 0x1A4
+#define CVDR_CVDR_VP_WR_IF_CFG_24_REG 0x1A8
+#define CVDR_CVDR_VP_WR_CFG_25_REG 0x1AC
+#define CVDR_CVDR_VP_WR_AXI_FS_25_REG 0x1B0
+#define CVDR_CVDR_VP_WR_AXI_LINE_25_REG 0x1B4
+#define CVDR_CVDR_VP_WR_IF_CFG_25_REG 0x1B8
+#define CVDR_CVDR_VP_WR_CFG_26_REG 0x1BC
+#define CVDR_CVDR_VP_WR_AXI_FS_26_REG 0x1C0
+#define CVDR_CVDR_VP_WR_AXI_LINE_26_REG 0x1C4
+#define CVDR_CVDR_VP_WR_IF_CFG_26_REG 0x1C8
+#define CVDR_CVDR_VP_WR_CFG_27_REG 0x1CC
+#define CVDR_CVDR_VP_WR_AXI_FS_27_REG 0x1D0
+#define CVDR_CVDR_VP_WR_AXI_LINE_27_REG 0x1D4
+#define CVDR_CVDR_VP_WR_IF_CFG_27_REG 0x1D8
+#define CVDR_CVDR_VP_WR_CFG_28_REG 0x1DC
+#define CVDR_CVDR_VP_WR_AXI_FS_28_REG 0x1E0
+#define CVDR_CVDR_VP_WR_AXI_LINE_28_REG 0x1E4
+#define CVDR_CVDR_VP_WR_IF_CFG_28_REG 0x1E8
+#define CVDR_CVDR_VP_WR_CFG_29_REG 0x1EC
+#define CVDR_CVDR_VP_WR_AXI_FS_29_REG 0x1F0
+#define CVDR_CVDR_VP_WR_AXI_LINE_29_REG 0x1F4
+#define CVDR_CVDR_VP_WR_IF_CFG_29_REG 0x1F8
+#define CVDR_CVDR_VP_WR_CFG_30_REG 0x1FC
+#define CVDR_CVDR_VP_WR_AXI_FS_30_REG 0x200
+#define CVDR_CVDR_VP_WR_AXI_LINE_30_REG 0x204
+#define CVDR_CVDR_VP_WR_IF_CFG_30_REG 0x208
+#define CVDR_CVDR_VP_WR_CFG_31_REG 0x20C
+#define CVDR_CVDR_VP_WR_AXI_FS_31_REG 0x210
+#define CVDR_CVDR_VP_WR_AXI_LINE_31_REG 0x214
+#define CVDR_CVDR_VP_WR_IF_CFG_31_REG 0x218
+#define CVDR_CVDR_VP_WR_CFG_32_REG 0x21C
+#define CVDR_CVDR_VP_WR_AXI_FS_32_REG 0x220
+#define CVDR_CVDR_VP_WR_AXI_LINE_32_REG 0x224
+#define CVDR_CVDR_VP_WR_IF_CFG_32_REG 0x228
+#define CVDR_CVDR_VP_WR_CFG_33_REG 0x22C
+#define CVDR_CVDR_VP_WR_AXI_FS_33_REG 0x230
+#define CVDR_CVDR_VP_WR_AXI_LINE_33_REG 0x234
+#define CVDR_CVDR_VP_WR_IF_CFG_33_REG 0x238
+#define CVDR_CVDR_VP_WR_CFG_34_REG 0x23C
+#define CVDR_CVDR_VP_WR_AXI_FS_34_REG 0x240
+#define CVDR_CVDR_VP_WR_AXI_LINE_34_REG 0x244
+#define CVDR_CVDR_VP_WR_IF_CFG_34_REG 0x248
+#define CVDR_CVDR_VP_WR_CFG_35_REG 0x24C
+#define CVDR_CVDR_VP_WR_AXI_FS_35_REG 0x250
+#define CVDR_CVDR_VP_WR_AXI_LINE_35_REG 0x254
+#define CVDR_CVDR_VP_WR_IF_CFG_35_REG 0x258
+#define CVDR_CVDR_VP_WR_CFG_36_REG 0x25C
+#define CVDR_CVDR_VP_WR_AXI_FS_36_REG 0x260
+#define CVDR_CVDR_VP_WR_AXI_LINE_36_REG 0x264
+#define CVDR_CVDR_VP_WR_IF_CFG_36_REG 0x268
+#define CVDR_CVDR_VP_WR_CFG_37_REG 0x26C
+#define CVDR_CVDR_VP_WR_AXI_FS_37_REG 0x270
+#define CVDR_CVDR_VP_WR_AXI_LINE_37_REG 0x274
+#define CVDR_CVDR_VP_WR_IF_CFG_37_REG 0x278
+#define CVDR_CVDR_LIMITER_VP_WR_0_REG 0x400
+
+#define CVDR_VP_RD_NBR (22)
+#define CVDR_VP_WR_NBR (38)
+#define CVDR_NR_WR_NBR (4)
+#define CVDR_NR_RD_NBR (8)
+
+#define ONE_REG_OFFSET (0x4)
+
+#define VP_WR_REG_OFFSET (0x10)
+
+#define ISP_CLK (480)
+#define DERATE (1.2)
+
+#define CVDR_ALIGN_BYTES (16)
+
+enum cvdr_pix_fmt_e {
+ DF_1PF8 = 0x0,
+ DF_1PF10 = 0x1,
+ DF_1PF12 = 0x2,
+ DF_1PF14 = 0x3,
+ DF_2PF8 = 0x4,
+ DF_2PF10 = 0x5,
+ DF_2PF12 = 0x6,
+ DF_2PF14 = 0x7,
+ DF_3PF8 = 0x8,
+ DF_3PF10 = 0x9,
+ DF_3PF12 = 0xA,
+ DF_3PF14 = 0xB,
+ DF_D32 = 0xC,
+ DF_D48 = 0xD,
+ DF_D64 = 0xE,
+ DF_FMT_INVALID,
+};
+
+enum vp_wr_id_e {
+ W12_1 = 0,
+ W12_2 = 1,
+ W6_1 = 2,
+ W6_2 = 3,
+ W5_1_1 = 4,
+ W5_1_2 = 5,
+ W4_1_1 = 8,
+ W4_1_2 = 9,
+ W4_2_1 = 10,
+ W4_2_2 = 11,
+ W7_1 = 12,
+ W13_1 = 14,
+ W13_2 = 15,
+ W1_1 = 16,
+ W1_2 = 17,
+ W14_1 = 18,
+ W14_2 = 19,
+ W11_1 = 20,
+ W11_2 = 21,
+ W2_3 = 22,
+ W2_4 = 23,
+ W2_5 = 24,
+ W8_1 = 25,
+ W3_1 = 26,
+ W2_2 = 27,
+ W2_1 = 28,
+ W15_1 = 29,
+ W16_1 = 30,
+ W16_2 = 31,
+ W17_1 = 32,
+ W17_2 = 33,
+ W19_1 = 34,
+ W19_2 = 35,
+ W20_1 = 36,
+ W20_2 = 37,
+};
+
+struct cvdr_wr_fmt_desc_t {
+ unsigned int fs_addr;
+ unsigned int last_page;
+
+ enum cvdr_pix_fmt_e pix_fmt;
+ unsigned char pix_expan;
+ unsigned short line_stride;
+ unsigned short line_wrap;
+};
+
+struct cvdr_bw_cfg_t {
+ unsigned char bw_limiter0;
+ unsigned char bw_limiter1;
+ unsigned char bw_limiter2;
+ unsigned char bw_limiter3;
+ unsigned char bw_limiter_reload;
+};
+
+struct cvdr_smmu_cfg_t {
+ unsigned char to_use;
+
+ unsigned int num;
+ unsigned int smr_nscfg;
+};
+
+struct cvdr_vp_wr_cfg_t {
+ unsigned char to_use;
+ unsigned char id;
+ struct cvdr_wr_fmt_desc_t fmt;
+ struct cvdr_bw_cfg_t bw;
+};
+
+struct cvdr_rd_fmt_desc_t {
+ unsigned int fs_addr;
+ unsigned int last_page;
+ enum cvdr_pix_fmt_e pix_fmt;
+ unsigned char pix_expan;
+ unsigned short allocated_du;
+ unsigned short line_size;
+ unsigned short hblank;
+ unsigned short frame_size;
+ unsigned short vblank;
+ unsigned short line_stride;
+ unsigned short line_wrap;
+};
+
+struct cvdr_vp_rd_cfg_t {
+ unsigned char to_use;
+ unsigned char id;
+ struct cvdr_rd_fmt_desc_t fmt;
+ struct cvdr_bw_cfg_t bw;
+};
+
+struct cvdr_nr_wr_cfg_t {
+ unsigned char to_use;
+ unsigned char nr_wr_stop_en_du_thr;
+ unsigned char nr_wr_stop_en_flux_ctrl;
+ unsigned char nr_wr_stop_en_pressure;
+ unsigned char nr_wr_stop_ok;
+ unsigned char nr_wr_stop;
+ unsigned char en;
+ struct cvdr_bw_cfg_t bw;
+};
+
+struct cvdr_nr_rd_cfg_t {
+ unsigned char to_use;
+ unsigned short allocated_du;
+ unsigned char nr_rd_stop_en_du_thr;
+ unsigned char nr_rd_stop_en_flux_ctrl;
+ unsigned char nr_rd_stop_en_pressure;
+ unsigned char nr_rd_stop_ok;
+ unsigned char nr_rd_stop;
+ unsigned char en;
+ struct cvdr_bw_cfg_t bw;
+};
+
+struct cfg_tab_cvdr_t {
+ struct cvdr_smmu_cfg_t smmu_nr_rd_cfg[CVDR_NR_RD_NBR];
+ struct cvdr_smmu_cfg_t smmu_vp_wr_cfg[CVDR_VP_WR_NBR];
+ struct cvdr_smmu_cfg_t smmu_vp_rd_cfg[CVDR_VP_RD_NBR];
+ struct cvdr_vp_wr_cfg_t vp_wr_cfg[CVDR_VP_WR_NBR];
+ struct cvdr_vp_rd_cfg_t vp_rd_cfg[CVDR_VP_RD_NBR];
+ struct cvdr_nr_wr_cfg_t nr_wr_cfg[CVDR_NR_WR_NBR];
+ struct cvdr_nr_rd_cfg_t nr_rd_cfg[CVDR_NR_RD_NBR];
+};
+
+struct cvdr_opt_bw_t {
+ unsigned int srt;
+ unsigned int pclk;
+ unsigned int throughput;
+};
+
+enum cvdr_dev_e {
+ CVDR_RT = 0,
+ CVDR_SRT = 1,
+};
+
+enum vp_rd_id_e {
+ R3_1 = 0,
+ R11_1 = 4,
+ R12_1 = 5,
+ R11_2 = 6,
+ R12_2 = 7,
+ R10_1 = 8,
+ R10_2 = 9,
+ R2_1 = 10,
+ R8_1_1 = 11,
+ R8_2_1 = 12,
+ R8_1_2 = 13,
+ R8_2_2 = 14,
+ R13_1 = 15,
+ R13_2 = 16,
+ R5_1_4 = 19,
+ R5_1_5 = 20,
+ R5_1_6 = 21,
+};
+
+/* Define the union U_CVDR_CFG */
+union U_CVDR_CFG {
+ /* Define the struct bits */
+ struct {
+ unsigned int axiwrite_du_threshold : 6; /* [5..0] */
+ unsigned int reserved_0 : 2; /* [7..6] */
+ unsigned int du_threshold_reached : 8; /* [15..8] */
+ unsigned int max_axiread_id : 5; /* [20..16] */
+ unsigned int reserved_1 : 3; /* [23..21] */
+ unsigned int max_axiwrite_id : 5; /* [28..24] */
+ unsigned int reserved_2 : 1; /* [29] */
+ unsigned int force_rd_clk_on : 1; /* [30] */
+ unsigned int force_wr_clk_on : 1; /* [31] */
+ } bits;
+
+ /* Define an unsigned member */
+ unsigned int u32;
+};
+
+/* Define the union U_CVDR_DEBUG_EN */
+union U_CVDR_DEBUG_EN {
+ /* Define the struct bits */
+ struct {
+ unsigned int wr_peak_en : 1;
+ unsigned int reserved_0 : 7;
+ unsigned int rd_peak_en : 1;
+ unsigned int reserved_1 : 23;
+ } bits;
+
+ /* Define an unsigned member */
+ unsigned int u32;
+};
+
+/* Define the union U_CVDR_DEBUG */
+union U_CVDR_DEBUG {
+ /* Define the struct bits */
+ struct {
+ unsigned int wr_peak : 8;
+ unsigned int rd_peak : 8;
+ unsigned int reserved_0 : 16;
+ } bits;
+
+ /* Define an unsigned member */
+ unsigned int u32;
+};
+
+/* Define the union U_CVDR_WR_QOS_CFG */
+union U_CVDR_WR_QOS_CFG {
+ /* Define the struct bits */
+ struct {
+ unsigned int wr_qos_threshold_01_stop : 4;
+ unsigned int wr_qos_threshold_01_start : 4;
+ unsigned int wr_qos_threshold_10_stop : 4;
+ unsigned int wr_qos_threshold_10_start : 4;
+ unsigned int wr_qos_threshold_11_stop : 4;
+ unsigned int wr_qos_threshold_11_start : 4;
+ unsigned int reserved_0 : 2;
+ unsigned int wr_qos_min : 2;
+ unsigned int wr_qos_max : 2;
+ unsigned int wr_qos_sr : 2;
+ } bits;
+
+ /* Define an unsigned member */
+ unsigned int u32;
+};
+
+/* Define the union U_CVDR_RD_QOS_CFG */
+union U_CVDR_RD_QOS_CFG {
+ /* Define the struct bits */
+ struct {
+ unsigned int rd_qos_threshold_01_stop : 4;
+ unsigned int rd_qos_threshold_01_start : 4;
+ unsigned int rd_qos_threshold_10_stop : 4;
+ unsigned int rd_qos_threshold_10_start : 4;
+ unsigned int rd_qos_threshold_11_stop : 4;
+ unsigned int rd_qos_threshold_11_start : 4;
+ unsigned int reserved_0 : 2;
+ unsigned int rd_qos_min : 2;
+ unsigned int rd_qos_max : 2;
+ unsigned int rd_qos_sr : 2;
+ } bits;
+
+ /* Define an unsigned member */
+ unsigned int u32;
+};
+
+/* Define the union U_OTHER_RO */
+union U_CVDR_OTHER_RO {
+ /* Define the struct bits */
+ struct {
+ unsigned int other_ro : 32;
+ } bits;
+
+ /* Define an unsigned member */
+ unsigned int u32;
+};
+
+/* Define the union U_OTHER_RW */
+union U_CVDR_OTHER_RW {
+ /* Define the struct bits */
+ struct {
+ unsigned int other_rw : 32;
+ } bits;
+
+ /* Define an unsigned member */
+ unsigned int u32;
+};
+
+
+/* Define the union U_VP_WR_CFG */
+union U_VP_WR_CFG {
+ /* Define the struct bits */
+ struct {
+ unsigned int vpwr_pixel_format : 4;
+ unsigned int vpwr_pixel_expansion : 1;
+ unsigned int reserved_0 : 10;
+ unsigned int vpwr_last_page : 17;
+ } bits;
+
+ /* Define an unsigned member */
+ unsigned int u32;
+};
+
+/* Define the union U_VP_WR_AXI_FS */
+union U_VP_WR_AXI_FS {
+ /* Define the struct bits */
+ struct {
+ unsigned int reserved_0 : 4;
+ unsigned int vpwr_address_frame_start : 28;
+ } bits;
+
+ /* Define an unsigned member */
+ unsigned int u32;
+};
+
+/* Define the union U_VP_WR_AXI_LINE */
+union U_VP_WR_AXI_LINE {
+ /* Define the struct bits */
+ struct {
+ unsigned int vpwr_line_stride : 10;
+ unsigned int reserved_0 : 5;
+ unsigned int vpwr_line_wrap : 14;
+ unsigned int reserved_1 : 3;
+ } bits;
+
+ /* Define an unsigned member */
+ unsigned int u32;
+};
+
+/* Define the union U_CVDR_RT_VP_WR_IF_CFG */
+union U_VP_WR_IF_CFG {
+ /* Define the struct bits */
+ struct {
+ unsigned int reserved_0 : 16;
+ unsigned int vp_wr_stop_enable_du_threshold_reached : 1;
+ unsigned int vp_wr_stop_enable_flux_ctrl : 1;
+ unsigned int vp_wr_stop_enable_pressure : 1;
+ unsigned int reserved_1 : 5;
+ unsigned int vp_wr_stop_ok : 1;
+ unsigned int vp_wr_stop : 1;
+ unsigned int reserved_2 : 5;
+ unsigned int vpwr_prefetch_bypass : 1;
+ } bits;
+
+ /* Define an unsigned member */
+ unsigned int u32;
+};
+
+
+/* Define the union U_LIMITER_VP_WR */
+union U_LIMITER_VP_WR {
+ /* Define the struct bits */
+ struct {
+ unsigned int vpwr_access_limiter_0 : 4;
+ unsigned int vpwr_access_limiter_1 : 4;
+ unsigned int vpwr_access_limiter_2 : 4;
+ unsigned int vpwr_access_limiter_3 : 4;
+ unsigned int reserved_0 : 8;
+ unsigned int vpwr_access_limiter_reload : 4;
+ unsigned int reserved_1 : 4;
+ } bits;
+
+ /* Define an unsigned member */
+ unsigned int u32;
+};
+
+/* Define the union U_VP_RD_CFG */
+union U_VP_RD_CFG {
+ /* Define the struct bits */
+ struct {
+ unsigned int vprd_pixel_format : 4;
+ unsigned int vprd_pixel_expansion : 1;
+ unsigned int vprd_allocated_du : 5;
+ unsigned int reserved_0 : 5;
+ unsigned int vprd_last_page : 17;
+ } bits;
+
+ /* Define an unsigned member */
+ unsigned int u32;
+
+};
+
+/* Define the union U_VP_RD_LWG */
+union U_VP_RD_LWG {
+ /* Define the struct bits */
+ struct {
+ unsigned int vprd_line_size : 13;
+ unsigned int reserved_0 : 3;
+ unsigned int vprd_horizontal_blanking : 8;
+ unsigned int reserved_1 : 8;
+ } bits;
+
+ /* Define an unsigned member */
+ unsigned int u32;
+};
+
+/* Define the union U_VP_RD_FHG */
+union U_VP_RD_FHG {
+ /* Define the struct bits */
+ struct {
+ unsigned int vprd_frame_size : 13;
+ unsigned int reserved_0 : 3;
+ unsigned int vprd_vertical_blanking : 8;
+ unsigned int reserved_1 : 8;
+ } bits;
+
+ /* Define an unsigned member */
+ unsigned int u32;
+};
+
+/* Define the union U_VP_RD_AXI_FS */
+union U_VP_RD_AXI_FS {
+ /* Define the struct bits */
+ struct {
+ unsigned int reserved_0 : 4;
+ unsigned int vprd_axi_frame_start : 28;
+ } bits;
+
+ /* Define an unsigned member */
+ unsigned int u32;
+};
+
+/* Define the union U_VP_RD_AXI_LINE */
+union U_VP_RD_AXI_LINE {
+ /* Define the struct bits */
+ struct {
+ unsigned int vprd_line_stride : 10;
+ unsigned int reserved_0 : 6;
+ unsigned int vprd_line_wrap : 13;
+ unsigned int reserved_1 : 3;
+ } bits;
+
+ /* Define an unsigned member */
+ unsigned int u32;
+};
+
+/* Define the union U_VP_RD_IF_CFG */
+union U_VP_RD_IF_CFG {
+ /* Define the struct bits */
+ struct {
+ unsigned int reserved_0 : 16;
+ unsigned int vp_rd_stop_enable_du_threshold_reached : 1;
+ unsigned int vp_rd_stop_enable_flux_ctrl : 1;
+ unsigned int vp_rd_stop_enable_pressure : 1;
+ unsigned int reserved_1 : 5;
+ unsigned int vp_rd_stop_ok : 1;
+ unsigned int vp_rd_stop : 1;
+ unsigned int reserved_2 : 5;
+ unsigned int vprd_prefetch_bypass : 1;
+ } bits;
+
+ /* Define an unsigned member */
+ unsigned int u32;
+};
+
+/* Define the union U_VP_RD_DEBUG */
+union U_VP_RD_DEBUG {
+ /* Define the struct bits */
+ struct {
+ unsigned int vp_rd_debug : 32;
+ } bits;
+
+ /* Define an unsigned member */
+ unsigned int u32;
+};
+
+/* Define the union U_LIMITER_VP_RD */
+union U_LIMITER_VP_RD {
+ /* Define the struct bits */
+ struct {
+ unsigned int vprd_access_limiter_0 : 4;
+ unsigned int vprd_access_limiter_1 : 4;
+ unsigned int vprd_access_limiter_2 : 4;
+ unsigned int vprd_access_limiter_3 : 4;
+ unsigned int reserved_0 : 8;
+ unsigned int vprd_access_limiter_reload : 4;
+ unsigned int reserved_1 : 4;
+ } bits;
+
+ /* Define an unsigned member */
+ unsigned int u32;
+};
+
+/* Define the union U_NR_WR_CFG */
+union U_NR_WR_CFG {
+ /* Define the struct bits */
+ struct {
+ unsigned int reserved_0 : 16;
+ unsigned int nr_wr_stop_enable_du_threshold_reached : 1;
+ unsigned int nr_wr_stop_enable_flux_ctrl : 1;
+ unsigned int nr_wr_stop_enable_pressure : 1;
+ unsigned int reserved_1 : 5;
+ unsigned int nr_wr_stop_ok : 1;
+ unsigned int nr_wr_stop : 1;
+ unsigned int reserved_2 : 5;
+ unsigned int nrwr_enable : 1;
+ } bits;
+
+ /* Define an unsigned member */
+ unsigned int u32;
+};
+
+/* Define the union U_NR_WR_DEBUG */
+union U_NR_WR_DEBUG {
+ /* Define the struct bits */
+ struct {
+ unsigned int nr_wr_debug : 32;
+ } bits;
+
+ /* Define an unsigned member */
+ unsigned int u32;
+};
+
+/* Define the union U_LIMITER_NR_WR */
+union U_LIMITER_NR_WR {
+ /* Define the struct bits */
+ struct {
+ unsigned int nrwr_access_limiter_0 : 4;
+ unsigned int nrwr_access_limiter_1 : 4;
+ unsigned int nrwr_access_limiter_2 : 4;
+ unsigned int nrwr_access_limiter_3 : 4;
+ unsigned int reserved_0 : 8;
+ unsigned int nrwr_access_limiter_reload : 4;
+ unsigned int reserved_1 : 4;
+ } bits;
+
+ /* Define an unsigned member */
+ unsigned int u32;
+};
+
+/* Define the union U_NR_RD_CFG */
+union U_NR_RD_CFG {
+ /* Define the struct bits */
+ struct {
+ unsigned int reserved_0 : 5;
+ unsigned int nrrd_allocated_du : 5;
+ unsigned int reserved_1 : 6;
+ unsigned int nr_rd_stop_enable_du_threshold_reached : 1;
+ unsigned int nr_rd_stop_enable_flux_ctrl : 1;
+ unsigned int nr_rd_stop_enable_pressure : 1;
+ unsigned int reserved_2 : 5;
+ unsigned int nr_rd_stop_ok : 1;
+ unsigned int nr_rd_stop : 1;
+ unsigned int reserved_3 : 5;
+ unsigned int nrrd_enable : 1;
+ } bits;
+
+ /* Define an unsigned member */
+ unsigned int u32;
+};
+
+/* Define the union U_NR_RD_DEBUG */
+union U_NR_RD_DEBUG {
+ /* Define the struct bits */
+ struct {
+ unsigned int nr_rd_debug : 32;
+ } bits;
+
+ /* Define an unsigned member */
+ unsigned int u32;
+};
+
+/* Define the union U_LIMITER_NR_RD */
+union U_LIMITER_NR_RD {
+ /* Define the struct bits */
+ struct {
+ unsigned int nrrd_access_limiter_0 : 4;
+ unsigned int nrrd_access_limiter_1 : 4;
+ unsigned int nrrd_access_limiter_2 : 4;
+ unsigned int nrrd_access_limiter_3 : 4;
+ unsigned int reserved_0 : 8;
+ unsigned int nrrd_access_limiter_reload : 4;
+ unsigned int reserved_1 : 4;
+ } bits;
+
+ /* Define an unsigned member */
+ unsigned int u32;
+};
+
+/* Define the union U_DEBUG */
+union U_DEBUG {
+ /* Define the struct bits */
+ struct {
+ unsigned int debug : 32 ; /* [31..0] */
+ } bits;
+
+ /* Define an unsigned member */
+ unsigned int u32;
+};
+
+/* Define the union U_AXI_CFG_NR_WR */
+union U_AXI_CFG_NR_WR {
+ /* Define the struct bits */
+ struct {
+ unsigned int nr_wr_mid : 6;
+ unsigned int reserved_0 : 26;
+ } bits;
+
+ /* Define an unsigned member */
+ unsigned int u32;
+};
+
+/* Define the union U_AXI_CFG_NR_RD */
+union U_AXI_CFG_NR_RD {
+ /* Define the struct bits */
+ struct {
+ unsigned int nr_rd_mid : 6;
+ unsigned int reserved_0 : 26;
+ } bits;
+
+ /* Define an unsigned member */
+ unsigned int u32;
+
+};
+
+/* Define the union U_AXI_CFG_VP_WR */
+union U_AXI_CFG_VP_WR {
+ /* Define the struct bits */
+ struct {
+ unsigned int vp_wr_mid : 6;
+ unsigned int reserved_0 : 26;
+ } bits;
+
+ /* Define an unsigned member */
+ unsigned int u32;
+
+};
+
+/* Define the union U_AXI_CFG_VP_RD */
+union U_AXI_CFG_VP_RD {
+ /* Define the struct bits */
+ struct {
+ unsigned int vp_rd_mid : 6;
+ unsigned int reserved_0 : 26;
+ } bits;
+
+ /* Define an unsigned member */
+ unsigned int u32;
+
+};
+
+/* Define the union U_SPARE */
+union U_SPARE {
+ /* Define the struct bits */
+ struct {
+ unsigned int spare : 32;
+ } bits;
+
+ /* Define an unsigned member */
+ unsigned int u32;
+
+};
+
+/* Define the union U_VP_WR_SMOOTHING */
+union U_VP_WR_SMOOTHING {
+ /* Define the struct bits */
+ struct {
+ unsigned int vpwr_smoothing_access_limiter_0 : 4;
+ unsigned int vpwr_smoothing_access_limiter_1 : 4;
+ unsigned int vpwr_smoothing_access_limiter_2 : 4;
+ unsigned int vpwr_smoothing_access_limiter_3 : 4;
+ unsigned int vpwr_smoothing_threshold : 7;
+ unsigned int reserved_0 : 9;
+ } bits;
+
+ /* Define an unsigned member */
+ unsigned int u32;
+
+};
+
+/* Define the union U_VP_WR_DEBUG */
+union U_VP_WR_DEBUG {
+ /* Define the struct bits */
+ struct {
+ unsigned int vp_wr_debug : 32;
+ } bits;
+
+ /* Define an unsigned member */
+ unsigned int u32;
+
+};
+
+struct S_VP_WR {
+ union U_VP_WR_CFG VP_WR_CFG;
+ union U_VP_WR_AXI_FS VP_WR_AXI_FS;
+ union U_VP_WR_AXI_LINE VP_WR_AXI_LINE;
+ union U_VP_WR_IF_CFG VP_WR_IF_CFG;
+};
+
+struct S_VP_RD {
+ union U_VP_RD_CFG VP_RD_CFG;
+ union U_VP_RD_LWG VP_RD_LWG;
+ union U_VP_RD_FHG VP_RD_FHG;
+ union U_VP_RD_AXI_FS VP_RD_AXI_FS;
+ union U_VP_RD_AXI_LINE VP_RD_AXI_LINE;
+ union U_VP_RD_IF_CFG VP_RD_IF_CFG;
+ unsigned int VP_RD_DEBUG;
+};
+
+struct S_NR_WR {
+ union U_NR_WR_CFG NR_WR_CFG;
+ union U_NR_WR_DEBUG NR_WR_DEBUG;
+ union U_LIMITER_NR_WR LIMITER_NR_WR;
+ unsigned int reserved_0;
+};
+
+struct S_NR_RD {
+ union U_NR_RD_CFG NR_RD_CFG;
+ union U_NR_RD_DEBUG NR_RD_DEBUG;
+ union U_LIMITER_NR_RD LIMITER_NR_RD;
+ unsigned int reserved_0;
+};
+
+/* Define the global struct */
+struct S_CVDR_REGS_TYPE {
+ union U_CVDR_CFG CVDR_CFG ; /* 0x0 */
+ union U_CVDR_DEBUG_EN CVDR_DEBUG_EN ; /* 0x4 */
+ union U_CVDR_DEBUG CVDR_DEBUG ; /* 0x8 */
+ union U_CVDR_WR_QOS_CFG CVDR_WR_QOS_CFG ; /* 0xc */
+ union U_CVDR_RD_QOS_CFG CVDR_RD_QOS_CFG ; /* 0x10 */
+ union U_CVDR_OTHER_RO CVDR_OTHER_RO ; /* 0x14 */
+ union U_CVDR_OTHER_RW CVDR_OTHER_RW ; /* 0x18 */
+ struct S_VP_WR VP_WR[38] ; /* 0x1c~0x278 */
+ unsigned int reserved_0[73] ; /* 0x27c~0x39c */
+ union U_LIMITER_VP_WR LIMITER_VP_WR[38] ; /* 0x400~0x494 */
+ unsigned int reserved_1[2] ; /* 0x498~0x49c */
+ struct S_VP_RD VP_RD[22] ; /* 0x500~0x7bc */
+ unsigned int reserved_2[48] ; /* 0x7c0~0x87c */
+ union U_LIMITER_VP_RD LIMITER_VP_RD[22] ; /* 0x880~0x8d4 */
+ unsigned int reserved_3[10] ; /* 0x8d8~0x8fc */
+ struct S_NR_WR NR_WR[4] ; /* 0x900~0x93c */
+ unsigned int reserved_4[48] ; /* 0x940~0x9fc */
+ struct S_NR_RD NR_RD[8] ; /* 0xa00~0xa7c */
+ unsigned int reserved_5[32] ; /* 0xa80~0xafc */
+ union U_DEBUG DEBUG[16] ; /* 0xb00~0xb3c */
+ unsigned int reserved_6[48] ; /* 0xb40~0xbfc */
+ union U_AXI_CFG_NR_WR AXI_CFG_NR_WR[4] ; /* 0xc00~0xc0c */
+ unsigned int reserved_7[12] ; /* 0xc10~0xc3c */
+ union U_AXI_CFG_NR_RD AXI_CFG_NR_RD[8] ; /* 0xc40~0xc5c */
+ unsigned int reserved_8[8] ; /* 0xc60~0xc7c */
+ union U_AXI_CFG_VP_WR AXI_CFG_VP_WR[38] ; /* 0xc80~0xd14 */
+ unsigned int reserved_9[26] ; /* 0xd18~0xd7c */
+ union U_AXI_CFG_VP_RD AXI_CFG_VP_RD[22] ; /* 0xd80~0xdd4 */
+ unsigned int reserved_10[10] ; /* 0xdd8~0xdfc */
+ union U_SPARE SPARE[4] ; /* 0xe00~0xe0c */
+ union U_VP_WR_SMOOTHING VP_WR_SMOOTHING[20] ; /* 0xe10~0xe5c */
+ unsigned int reserved_11[40] ; /* 0xe60~0xefc */
+ union U_VP_WR_DEBUG VP_WR_DEBUG[38] ; /* 0xf00~0xf94 */
+};
+
+struct cvdr_device {
+ struct isp *isp;
+ struct v4l2_subdev subdev;
+ struct media_pad pads[ISP_CVDR_PADS_NUM];
+ void __iomem *cvdr_rt;
+ void __iomem *cvdr_srt;
+ void __iomem *sub_ctrl;
+ unsigned int irq_vic1;
+};
+
+int isp_cvdr_subdev_init(struct isp *isp,
+ struct cvdr_device *cvdr,
+ const struct resources *res);
+
+int isp_cvdr_register_entity(struct cvdr_device *cvdr,
+ struct v4l2_device *v4l2_dev);
+
+void isp_cvdr_unregister_entity(struct cvdr_device *cvdr);
+
+#endif /* HISI_ISP_CVDR_H */
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);
+}
diff --git a/drivers/media/platform/hisi/isp/isp-sr.h b/drivers/media/platform/hisi/isp/isp-sr.h
new file mode 100644
index 000000000000..aa5e23a259a8
--- /dev/null
+++ b/drivers/media/platform/hisi/isp/isp-sr.h
@@ -0,0 +1,114 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2016-2018 Linaro Ltd.
+ */
+
+#ifndef HISI_ISP_SR_H
+#define HISI_ISP_SR_H
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <media/media-entity.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mediabus.h>
+#include <media/v4l2-subdev.h>
+
+#define ISP_SR_PAD_SINK 0
+#define ISP_SR_PAD_SRC 1
+#define ISP_SR_PADS_NUM 1
+
+#define STREAM_ROUTER_CSIFILTER_A_REG 0x0
+#define STREAM_ROUTER_CSIFILTER_B_REG 0x4
+#define STREAM_ROUTER_CSIFILTER_C_REG 0x8
+#define STREAM_ROUTER_CSIFILTER_GO_REG 0xC
+#define STREAM_ROUTER_PRESSURE_START_REG 0x10
+#define STREAM_ROUTER_PRESSURE_STOP_REG 0x14
+#define STREAM_ROUTER_ID_ROUTER_0_REG 0x18
+#define STREAM_ROUTER_ID_ROUTER_1_REG 0x1C
+#define STREAM_ROUTER_REFORMAT_0_REG 0x20
+#define STREAM_ROUTER_REFORMAT_1_REG 0x28
+#define STREAM_ROUTER_REFORMAT_2_REG 0x30
+#define STREAM_ROUTER_REFORMAT_3_REG 0x38
+#define STREAM_ROUTER_REFORMAT_4_REG 0x40
+#define STREAM_ROUTER_REFORMAT_5_REG 0x48
+#define STREAM_ROUTER_REFORMAT_6_REG 0x50
+#define STREAM_ROUTER_REFORMAT_7_REG 0x58
+#define STREAM_ROUTER_REFORMAT_MINSPACE_0_REG 0x24
+#define STREAM_ROUTER_REFORMAT_MINSPACE_1_REG 0x2C
+#define STREAM_ROUTER_REFORMAT_MINSPACE_2_REG 0x34
+#define STREAM_ROUTER_REFORMAT_MINSPACE_3_REG 0x3C
+#define STREAM_ROUTER_REFORMAT_MINSPACE_4_REG 0x44
+#define STREAM_ROUTER_REFORMAT_MINSPACE_5_REG 0x4C
+#define STREAM_ROUTER_REFORMAT_MINSPACE_6_REG 0x54
+#define STREAM_ROUTER_REFORMAT_MINSPACE_7_REG 0x5C
+#define STREAM_ROUTER_EOL_CNT_REG 0x60
+#define STREAM_ROUTER_DPCM_0_REG 0x78
+#define STREAM_ROUTER_DPCM_1_REG 0x7C
+#define STREAM_ROUTER_DPCM_2_REG 0x80
+#define STREAM_ROUTER_VP_ROUTER_0_REG 0x90
+#define STREAM_ROUTER_VP_ROUTER_1_REG 0x94
+#define STREAM_ROUTER_VP_ROUTER_2_REG 0x98
+#define STREAM_ROUTER_VP_ROUTER_3_REG 0x9C
+#define STREAM_ROUTER_PIXFRAG_CONVERT_REG 0xA0
+
+/* Define the union U_ID_ROUTER_1 */
+union U_ID_ROUTER_1 {
+ /* Define the struct bits */
+ struct {
+ unsigned int reserved_0 : 16 ; /* [15..0] */
+ unsigned int idr_input_stream_6 : 4 ; /* [19..16] */
+ unsigned int idr_enable_6 : 1 ; /* [20] */
+ unsigned int reserved_1 : 3 ; /* [23..21] */
+ unsigned int idr_input_stream_7 : 4 ; /* [27..24] */
+ unsigned int idr_enable_7 : 1 ; /* [28] */
+ unsigned int reserved_2 : 3 ; /* [31..29] */
+ } bits;
+
+ /* Define an unsigned member */
+ unsigned int u32;
+
+};
+
+/* Define the union U_REFORMAT */
+union U_REFORMAT {
+ /* Define the struct bits */
+ struct {
+ unsigned int reformat_num_lines : 13 ; /* [12..0] */
+ unsigned int reformat_pixel_reorder : 3 ; /* [15..13] */
+ unsigned int reformat_num_pixels : 13 ; /* [28..16] */
+ unsigned int reserved_0 : 2 ; /* [30..29] */
+ unsigned int reformat_enable : 1 ; /* [31] */
+ } bits;
+
+ /* Define an unsigned member */
+ unsigned int u32;
+};
+
+#define STREAM_ROUTER_REFORMAT_MINSPACE_REG(x) \
+ (STREAM_ROUTER_REFORMAT_MINSPACE_0_REG +\
+ (x)*(STREAM_ROUTER_REFORMAT_MINSPACE_1_REG -\
+ STREAM_ROUTER_REFORMAT_MINSPACE_0_REG))
+
+#define STREAM_ROUTER_REFORMAT_REG(x) \
+ (STREAM_ROUTER_REFORMAT_0_REG +\
+ (x)*(STREAM_ROUTER_REFORMAT_1_REG -\
+ STREAM_ROUTER_REFORMAT_0_REG))
+
+struct sr_device {
+ struct isp *isp;
+ struct v4l2_subdev subdev;
+ struct media_pad pads[ISP_SR_PADS_NUM];
+ void __iomem *base;
+ unsigned int irq_frproc0;
+};
+
+int isp_sr_subdev_init(struct isp *isp,
+ struct sr_device *sr,
+ const struct resources *res);
+
+int isp_sr_register_entity(struct sr_device *sr,
+ struct v4l2_device *v4l2_dev);
+
+void isp_sr_unregister_entity(struct sr_device *sr);
+
+#endif /* HISI_ISP_SR_H */
diff --git a/drivers/media/platform/hisi/isp/isp.c b/drivers/media/platform/hisi/isp/isp.c
new file mode 100644
index 000000000000..e57806c801a9
--- /dev/null
+++ b/drivers/media/platform/hisi/isp/isp.c
@@ -0,0 +1,709 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * isp.c
+ *
+ * Copyright (C) 2018 Linaro Ltd.
+ */
+
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/media-bus-format.h>
+#include <linux/media.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/pm_runtime.h>
+#include <linux/pm_domain.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+
+#include <media/media-device.h>
+#include <media/v4l2-async.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mc.h>
+#include <media/v4l2-fwnode.h>
+
+#include "isp.h"
+
+#define DOVDD_VOLTAGE 1800000
+#define ISP_CLK_FREQ 24000000
+
+const struct resources isp_res[] = {
+ {
+ .reg = "ispss_ctrl",
+ },
+ {
+ .reg = "smmu_ctrl",
+ },
+ {
+ .reg = "irq_merger2",
+ },
+};
+
+const struct resources csiphy_res[] = {
+ {
+ .reg = "csi0",
+ },
+ {
+ .reg = "csi1",
+ },
+};
+
+const struct resources sr_res[] = {
+ {
+ .reg = "sr",
+ },
+};
+
+const struct resources cvdr_res[] = {
+ {
+ .reg = "cvdr_rt",
+ },
+ {
+ .reg = "cvdr_srt",
+ },
+ {
+ .reg = "sub_ctrl",
+ },
+};
+
+void isp_writel(void __iomem *base , u32 reg, u32 value)
+{
+ writel(value, base + reg);
+}
+
+u32 isp_readl(void __iomem *base , u32 reg)
+{
+ return readl(base + reg);
+}
+
+u32 isp_clear_irq(struct isp *isp, enum IRQ_MERGER_TYPE irq)
+{
+ u32 val;
+
+ val = isp_readl(isp->irq_merger2, irq + IRQ_MERGER_FUNC_RIS);
+ isp_writel(isp->irq_merger2, irq+IRQ_MERGER_FUNC_ICR, val);
+
+ return val;
+}
+
+int frame_num2Offset(struct isp *isp, int frame_num)
+{
+ return (isp->frame_size * (frame_num % isp->frame_count));
+}
+
+void isp_config_smmu_bypass(struct isp *isp)
+{
+ isp_writel(isp->smmu_ctrl, 0x0, 0x1);
+}
+
+void isp_ispss_enable_irq(struct isp *isp)
+{
+ isp_writel(isp->irq_merger2, IRQ_MERGER_IMSC_DEBUG1, 0xFFFFFFFF);
+ isp_writel(isp->irq_merger2, IRQ_MERGER_IMSC_FRPROC0, 0xFFFFFFFF);
+}
+
+void isp_ispss_clear_irq_state(struct isp *isp)
+{
+ isp_writel(isp->irq_merger2, IRQ_MERGER_ICR_DEBUG0, 0xFFFFFFFF);
+ isp_writel(isp->irq_merger2, IRQ_MERGER_ICR_DEBUG1, 0xFFFFFFFF);
+ isp_writel(isp->irq_merger2, IRQ_MERGER_ICR_DEBUG2, 0xFFFFFFFF);
+ isp_writel(isp->irq_merger2, IRQ_MERGER_ICR_DEBUG3, 0xFFFFFFFF);
+ isp_writel(isp->irq_merger2, IRQ_MERGER_ICR_ERROR0, 0xFFFFFFFF);
+ isp_writel(isp->irq_merger2, IRQ_MERGER_ICR_ERROR1, 0xFFFFFFFF);
+ isp_writel(isp->irq_merger2, IRQ_MERGER_ICR_FRPROC0, 0xFFFFFFFF);
+ isp_writel(isp->irq_merger2, IRQ_MERGER_ICR_FRPROC1, 0xFFFFFFFF);
+ isp_writel(isp->irq_merger2, IRQ_MERGER_ICR_FRPROC2, 0xFFFFFFFF);
+}
+
+/*
+ * isp_enable_clocks - Enable multiple clocks
+ * @nclocks: Number of clocks in clock array
+ * @clock: Clock array
+ * @dev: Device
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+int isp_enable_clocks(struct isp_clock *clks, struct device *dev)
+{
+ int ret;
+ int i;
+
+ for (i = 0; i < ISP_NUM_CLKS; i++) {
+ ret = clk_prepare_enable(clks[i].clk);
+ if (ret) {
+ dev_err(dev, "clock enable failed: %d\n", ret);
+ goto error;
+ }
+ }
+
+ return 0;
+
+error:
+ for (i--; i >= 0; i--)
+ clk_disable_unprepare(clks[i].clk);
+
+ return ret;
+}
+
+/*
+ * isp_disable_clocks - Disable multiple clocks
+ * @nclocks: Number of clocks in clock array
+ * @clock: Clock array
+ */
+void isp_disable_clocks(struct isp_clock *clks)
+{
+ int i;
+
+ for (i = ISP_NUM_CLKS - 1; i >= 0; i--)
+ clk_disable_unprepare(clks[i].clk);
+}
+
+/*
+ * isp_find_sensor - Find a linked media entity which represents a sensor
+ * @entity: Media entity to start searching from
+ *
+ * Return a pointer to sensor media entity or NULL if not found
+ */
+static struct media_entity *isp_find_sensor(struct media_entity *entity)
+{
+ struct media_pad *pad;
+
+ while (1) {
+ pad = &entity->pads[0];
+ if (!(pad->flags & MEDIA_PAD_FL_SINK))
+ return NULL;
+
+ pad = media_entity_remote_pad(pad);
+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
+ return NULL;
+
+ entity = pad->entity;
+
+ if (entity->function == MEDIA_ENT_F_CAM_SENSOR)
+ return entity;
+ }
+}
+
+/*
+ * isp_get_pixel_clock - Get pixel clock rate from sensor
+ * @entity: Media entity in the current pipeline
+ * @pixel_clock: Received pixel clock value
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+int isp_get_pixel_clock(struct media_entity *entity, u32 *pixel_clock)
+{
+ struct media_entity *sensor;
+ struct v4l2_subdev *subdev;
+ struct v4l2_ctrl *ctrl;
+
+ sensor = isp_find_sensor(entity);
+ if (!sensor)
+ return -ENODEV;
+
+ subdev = media_entity_to_v4l2_subdev(sensor);
+
+ ctrl = v4l2_ctrl_find(subdev->ctrl_handler, V4L2_CID_PIXEL_RATE);
+
+ if (!ctrl)
+ return -EINVAL;
+
+ *pixel_clock = v4l2_ctrl_g_ctrl_int64(ctrl);
+
+ return 0;
+}
+
+/*
+ * isp_of_parse_endpoint_node - Parse port endpoint node
+ * @dev: Device
+ * @node: Device node to be parsed
+ * @csd: Parsed data from port endpoint node
+ *
+ * Return 0 on success or a negative error code on failure
+ */
+static int isp_of_parse_endpoint_node(struct device *dev,
+ struct device_node *node,
+ struct isp_async_subdev *csd)
+{
+ struct csiphy_lanes_cfg *lncfg = &csd->interface.csi2.lane_cfg;
+ struct v4l2_fwnode_bus_mipi_csi2 *mipi_csi2;
+ struct v4l2_fwnode_endpoint vep = { { 0 } };
+ unsigned int i;
+
+ v4l2_fwnode_endpoint_parse(of_fwnode_handle(node), &vep);
+
+ csd->interface.csiphy_id = vep.base.port;
+
+ mipi_csi2 = &vep.bus.mipi_csi2;
+ lncfg->clk.pos = mipi_csi2->clock_lane;
+ lncfg->clk.pol = mipi_csi2->lane_polarities[0];
+ lncfg->num_data = mipi_csi2->num_data_lanes;
+
+ lncfg->data = devm_kcalloc(dev,
+ lncfg->num_data, sizeof(*lncfg->data),
+ GFP_KERNEL);
+ if (!lncfg->data)
+ return -ENOMEM;
+
+ for (i = 0; i < lncfg->num_data; i++) {
+ lncfg->data[i].pos = mipi_csi2->data_lanes[i];
+ lncfg->data[i].pol = mipi_csi2->lane_polarities[i + 1];
+ }
+
+ return 0;
+}
+
+/*
+ * isp_of_parse_ports - Parse ports node
+ * @dev: Device
+ * @notifier: v4l2_device notifier data
+ *
+ * Return number of "port" nodes found in "ports" node
+ */
+static int isp_of_parse_ports(struct isp *isp)
+{
+ struct device *dev = isp->dev;
+ struct device_node *node = NULL;
+ struct device_node *remote = NULL;
+ int ret, num_subdevs = 0;
+
+ for_each_endpoint_of_node(dev->of_node, node) {
+ struct isp_async_subdev *csd;
+ struct v4l2_async_subdev *asd;
+
+ if (!of_device_is_available(node))
+ continue;
+
+ remote = of_graph_get_remote_port_parent(node);
+ if (!remote) {
+ dev_err(dev, "Cannot get remote parent\n");
+ ret = -EINVAL;
+ goto err_cleanup;
+ }
+
+ asd = v4l2_async_notifier_add_fwnode_subdev(
+ &isp->notifier, of_fwnode_handle(remote),
+ sizeof(*csd));
+ if (IS_ERR(asd)) {
+ ret = PTR_ERR(asd);
+ of_node_put(remote);
+ goto err_cleanup;
+ }
+
+ csd = container_of(asd, struct isp_async_subdev, asd);
+
+ ret = isp_of_parse_endpoint_node(dev, node, csd);
+ if (ret < 0)
+ goto err_cleanup;
+
+ num_subdevs++;
+ }
+
+ return num_subdevs;
+
+err_cleanup:
+ v4l2_async_notifier_cleanup(&isp->notifier);
+ of_node_put(node);
+ return ret;
+}
+
+/*
+ * isp_init_subdevices - Initialize subdev structures and resources
+ *
+ * Return 0 on success or a negative error code on failure
+ */
+static int isp_init_subdevices(struct isp *isp)
+{
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < isp->csiphy_num; i++) {
+ ret = isp_csiphy_subdev_init(isp, &isp->csiphy[i],
+ &csiphy_res[i], i);
+ if (ret < 0) {
+ dev_err(isp->dev,
+ "Failed to init csiphy%d sub-device: %d\n",
+ i, ret);
+ return ret;
+ }
+ }
+
+ ret = isp_sr_subdev_init(isp, isp->sr, sr_res);
+ if (ret < 0) {
+ dev_err(isp->dev, "Failed to init SR sub-device: %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = isp_cvdr_subdev_init(isp, isp->cvdr, cvdr_res);
+ if (ret < 0) {
+ dev_err(isp->dev, "Failed to init CVDR sub-device: %d\n",
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+/*
+ * isp_register_entities - Register subdev nodes and create links
+ *
+ * Return 0 on success or a negative error code on failure
+ */
+static int isp_register_entities(struct isp *isp)
+{
+ int i;
+ int ret;
+
+ for (i = 0; i < isp->csiphy_num; i++) {
+ ret = isp_csiphy_register_entity(&isp->csiphy[i],
+ &isp->v4l2_dev);
+ if (ret < 0) {
+ dev_err(isp->dev,
+ "Failed to register csiphy%d entity: %d\n",
+ i, ret);
+ goto err_reg_csiphy;
+ }
+ }
+
+ ret = isp_sr_register_entity(isp->sr, &isp->v4l2_dev);
+ if (ret < 0) {
+ dev_err(isp->dev, "Failed to register sr entity: %d\n",
+ ret);
+ goto err_reg_sr;
+ }
+
+ ret = isp_cvdr_register_entity(isp->cvdr, &isp->v4l2_dev);
+ if (ret < 0) {
+ dev_err(isp->dev, "Failed to register cvdr entity: %d\n",
+ ret);
+ goto err_reg_sr;
+ }
+
+ for (i = 0; i < isp->csiphy_num; i++) {
+ ret = media_create_pad_link(
+ &isp->csiphy[i].subdev.entity,
+ ISP_CSIPHY_PAD_SRC,
+ &isp->sr->subdev.entity,
+ ISP_SR_PAD_SINK,
+ 0);
+ if (ret < 0) {
+ dev_err(isp->dev,
+ "Failed to link %s->%s entities: %d\n",
+ isp->csiphy[i].subdev.entity.name,
+ isp->sr->subdev.entity.name,
+ ret);
+ goto err_reg_sr;
+ }
+ }
+
+ ret = media_create_pad_link(&isp->sr->subdev.entity,
+ ISP_SR_PAD_SRC,
+ &isp->cvdr->subdev.entity,
+ ISP_CVDR_PAD_SINK,
+ 0);
+ if (ret < 0) {
+ dev_err(isp->dev, "Failed to link %s->%s entities: %d\n",
+ isp->sr->subdev.entity.name,
+ isp->cvdr->subdev.entity.name,
+ ret);
+ goto err_reg_sr;
+ }
+
+ return 0;
+
+err_reg_sr:
+ isp_sr_unregister_entity(isp->sr);
+
+ i = isp->csiphy_num;
+err_reg_csiphy:
+ for (i--; i >= 0; i--)
+ isp_csiphy_unregister_entity(&isp->csiphy[i]);
+
+ return ret;
+}
+
+static void isp_unregister_entities(struct isp *isp)
+{
+ unsigned int i;
+
+ for (i = 0; i < isp->csiphy_num; i++)
+ isp_csiphy_unregister_entity(&isp->csiphy[i]);
+ isp_sr_unregister_entity(isp->sr);
+ isp_cvdr_unregister_entity(isp->cvdr);
+}
+
+static int isp_subdev_notifier_bound(struct v4l2_async_notifier *async,
+ struct v4l2_subdev *subdev,
+ struct v4l2_async_subdev *asd)
+{
+ struct isp *isp = container_of(async, struct isp, notifier);
+ struct isp_async_subdev *csd =
+ container_of(asd, struct isp_async_subdev, asd);
+ u8 id = csd->interface.csiphy_id;
+ struct csiphy_device *csiphy = &isp->csiphy[id];
+
+ csiphy->cfg.csi2 = &csd->interface.csi2;
+ subdev->host_priv = csiphy;
+
+ return 0;
+}
+
+static int isp_subdev_notifier_complete(struct v4l2_async_notifier *async)
+{
+ struct isp *isp = container_of(async, struct isp, notifier);
+ struct v4l2_device *v4l2_dev = &isp->v4l2_dev;
+ struct v4l2_subdev *sd;
+ int ret;
+
+ list_for_each_entry(sd, &v4l2_dev->subdevs, list) {
+ if (sd->host_priv) {
+ struct media_entity *sensor = &sd->entity;
+ struct csiphy_device *csiphy =
+ (struct csiphy_device *) sd->host_priv;
+ struct media_entity *input = &csiphy->subdev.entity;
+ unsigned int i;
+
+ for (i = 0; i < sensor->num_pads; i++) {
+ if (sensor->pads[i].flags & MEDIA_PAD_FL_SOURCE)
+ break;
+ }
+ if (i == sensor->num_pads) {
+ dev_err(isp->dev,
+ "No source pad in external entity\n");
+ return -EINVAL;
+ }
+
+ ret = media_create_pad_link(sensor, i,
+ input, ISP_CSIPHY_PAD_SINK,
+ MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED);
+ if (ret < 0) {
+ dev_err(isp->dev,
+ "Failed to link %s->%s entities: %d\n",
+ sensor->name, input->name, ret);
+ return ret;
+ }
+ }
+ }
+
+ ret = v4l2_device_register_subdev_nodes(&isp->v4l2_dev);
+ if (ret < 0)
+ return ret;
+
+ return media_device_register(&isp->media_dev);
+}
+
+static const struct v4l2_async_notifier_operations isp_subdev_notifier_ops = {
+ .bound = isp_subdev_notifier_bound,
+ .complete = isp_subdev_notifier_complete,
+};
+
+static const struct media_device_ops isp_media_ops = {
+ .link_notify = v4l2_pipeline_link_notify,
+};
+
+/*
+ * isp_probe - Probe ISP platform device
+ * @pdev: Pointer to ISP platform device
+ *
+ * Return 0 on success or a negative error code on failure
+ */
+static int isp_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct isp *isp;
+ struct resource *r;
+ int num_subdevs, ret, i;
+
+ isp = devm_kzalloc(dev, sizeof(*isp), GFP_KERNEL);
+ if (!isp)
+ return -ENOMEM;
+
+ isp->dev = dev;
+ platform_set_drvdata(pdev, isp);
+
+ isp->csiphy_num = 2;
+ isp->csiphy = devm_kcalloc(dev, isp->csiphy_num,
+ sizeof(*isp->csiphy), GFP_KERNEL);
+ if (!isp->csiphy)
+ return -ENOMEM;
+
+ isp->sr = devm_kzalloc(dev, sizeof(*isp->sr), GFP_KERNEL);
+ if (!isp->sr)
+ return -ENOMEM;
+
+ isp->cvdr = devm_kzalloc(dev, sizeof(*isp->cvdr), GFP_KERNEL);
+ if (!isp->cvdr)
+ return -ENOMEM;
+
+ v4l2_async_notifier_init(&isp->notifier);
+ pr_info("%s: %d\n", __func__, __LINE__);
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, isp_res[0].reg);
+ isp->ispss_ctrl = devm_ioremap_resource(dev, r);
+ if (IS_ERR(isp->ispss_ctrl)) {
+ dev_err(dev, "could not map ispss_ctrl memory\n");
+ ret = PTR_ERR(isp->ispss_ctrl);
+ goto err_cleanup;
+ }
+
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, isp_res[1].reg);
+ isp->smmu_ctrl = devm_ioremap_resource(dev, r);
+ if (IS_ERR(isp->smmu_ctrl)) {
+ dev_err(dev, "could not map smmu_ctrl memory\n");
+ ret = PTR_ERR(isp->smmu_ctrl);
+ goto err_cleanup;
+ }
+
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, isp_res[2].reg);
+ isp->irq_merger2 = devm_ioremap_resource(dev, r);
+ if (IS_ERR(isp->irq_merger2)) {
+ dev_err(dev, "could not map irq_merger2 memory\n");
+ ret = PTR_ERR(isp->irq_merger2);
+ goto err_cleanup;
+ }
+
+ pr_info("%s: %d\n", __func__, __LINE__);
+ isp->clks[0].name = "isp_snclk0";
+ isp->clks[0].freq = ISP_CLK_FREQ;
+ isp->clks[1].name = "isp_snclk1";
+ isp->clks[1].freq = ISP_CLK_FREQ;
+
+ for (i = 0; i < ISP_NUM_CLKS; i++) {
+ isp->clks[i].clk = devm_clk_get(&pdev->dev, isp->clks[i].name);
+ if (IS_ERR(isp->clks[i].clk)) {
+ dev_err(isp->dev, "could not get clock: %s\n",
+ isp->clks[i].name);
+ ret = -EINVAL;
+ goto err_cleanup;
+ }
+
+ clk_set_rate(isp->clks[i].clk, isp->clks[i].freq);
+ }
+
+ pr_info("%s: %d\n", __func__, __LINE__);
+ ret = of_property_read_u32(dev->of_node, "pool-size", &isp->pool_size);
+ if (ret < 0)
+ goto err_cleanup;
+
+ pr_info("%s: %d\n", __func__, __LINE__);
+ isp->virt_addr = dma_alloc_coherent(dev, isp->pool_size,
+ &(isp->hw_addr), GFP_KERNEL);
+ if (!isp->virt_addr) {
+ pr_err("dma_alloc_coherent (ISP) alloc err!\n");
+ ret = -ENOMEM;
+ goto err_cleanup;
+ }
+
+ pr_info("%s: %d\n", __func__, __LINE__);
+ memset(isp->virt_addr, 0, isp->pool_size);
+
+ num_subdevs = isp_of_parse_ports(isp);
+ if (num_subdevs < 0) {
+ ret = num_subdevs;
+ goto err_cleanup;
+ }
+
+ pr_info("%s: %d\n", __func__, __LINE__);
+ ret = isp_init_subdevices(isp);
+ if (ret < 0)
+ goto err_cleanup;
+
+ pr_info("%s: %d\n", __func__, __LINE__);
+ isp->media_dev.dev = isp->dev;
+ strscpy(isp->media_dev.model, "HiSilicon ISP",
+ sizeof(isp->media_dev.model));
+ isp->media_dev.ops = &isp_media_ops;
+ media_device_init(&isp->media_dev);
+
+ pr_info("%s: %d\n", __func__, __LINE__);
+ /* FIXME: Get these from userspace */
+ isp->frame_size = 0x3F4800;
+ isp->frame_count = 4;
+ isp->frame_num = 0;
+ isp->v4l2_dev.mdev = &isp->media_dev;
+ ret = v4l2_device_register(isp->dev, &isp->v4l2_dev);
+ if (ret < 0) {
+ dev_err(dev, "Failed to register V4L2 device: %d\n", ret);
+ goto err_cleanup;
+ }
+
+ pr_info("%s: %d\n", __func__, __LINE__);
+ ret = isp_register_entities(isp);
+ if (ret < 0)
+ goto err_register_entities;
+
+ pr_info("%s: %d\n", __func__, __LINE__);
+ if (num_subdevs) {
+ isp->notifier.ops = &isp_subdev_notifier_ops;
+
+ ret = v4l2_async_notifier_register(&isp->v4l2_dev,
+ &isp->notifier);
+ if (ret) {
+ dev_err(dev,
+ "Failed to register async subdev nodes: %d\n",
+ ret);
+ goto err_register_subdevs;
+ }
+ } else {
+ ret = v4l2_device_register_subdev_nodes(&isp->v4l2_dev);
+ if (ret < 0) {
+ dev_err(dev, "Failed to register subdev nodes: %d\n",
+ ret);
+ goto err_register_subdevs;
+ }
+
+ ret = media_device_register(&isp->media_dev);
+ if (ret < 0) {
+ dev_err(dev, "Failed to register media device: %d\n",
+ ret);
+ goto err_register_subdevs;
+ }
+ }
+
+ pr_info("**********ISP registered*******\n");
+ return 0;
+
+err_register_subdevs:
+ isp_unregister_entities(isp);
+err_register_entities:
+ v4l2_device_unregister(&isp->v4l2_dev);
+err_cleanup:
+ v4l2_async_notifier_cleanup(&isp->notifier);
+
+ return ret;
+}
+
+void isp_delete(struct isp *isp)
+{
+ v4l2_device_unregister(&isp->v4l2_dev);
+ media_device_unregister(&isp->media_dev);
+ media_device_cleanup(&isp->media_dev);
+}
+
+static int isp_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static const struct of_device_id isp_dt_match[] = {
+ { .compatible = "hisilicon,hisi-isp" },
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, isp_dt_match);
+
+static struct platform_driver hisi_isp_driver = {
+ .probe = isp_probe,
+ .remove = isp_remove,
+ .driver = {
+ .name = "hisi-isp",
+ .of_match_table = isp_dt_match,
+ },
+};
+
+module_platform_driver(hisi_isp_driver);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/hisi/isp/isp.h b/drivers/media/platform/hisi/isp/isp.h
new file mode 100644
index 000000000000..dc9aa590d615
--- /dev/null
+++ b/drivers/media/platform/hisi/isp/isp.h
@@ -0,0 +1,159 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 Linaro Ltd.
+ */
+
+#ifndef HISI_ISP_H
+#define HISI_ISP_H
+
+#include <linux/regulator/consumer.h>
+
+#include "isp-csiphy.h"
+#include "isp-sr.h"
+#include "isp-cvdr.h"
+
+#define MASK0(name) ((1<<(name##_LEN))-1)
+#define MASK1(name) (((1<<(name##_LEN))-1) << (name##_OFFSET))
+
+/* operation on the field of a variable */
+#define isp_readl_field(reg, name) \
+ (((reg) >> (name##_OFFSET)) & MASK0(name))
+
+#define isp_writel_field(reg, name, val) \
+ (reg = ((reg) & ~MASK1(name)) | \
+ (((val) & MASK0(name)) << (name##_OFFSET)))
+
+#define ISP_NUM_CLKS 2
+
+enum IRQ_MERGER_TYPE {
+ IRQ_MERGER_DEBUG_0 = 0x0,
+ IRQ_MERGER_DEBUG_1 = 0x20,
+ IRQ_MERGER_DEBUG_2 = 0x40,
+ IRQ_MERGER_DEBUG_3 = 0x60,
+ IRQ_MERGER_DEBUG_4 = 0x80,
+ IRQ_MERGER_ERROR_0 = 0xA0,
+ IRQ_MERGER_ERROR_1 = 0xC0,
+ IRQ_MERGER_FRPROC_0 = 0xE0,
+ IRQ_MERGER_FRPROC_1 = 0x100,
+ IRQ_MERGER_FRPROC_2 = 0x120,
+ IRQ_MERGER_COMBINED = 0x140,
+ IRQ_MERGER_IRQ_MAX = 0xFF,
+};
+
+enum IRQ_MERGER_FUNC_TYPE {
+ IRQ_MERGER_FUNC_IMS = 0x0,
+ IRQ_MERGER_FUNC_RIS = 0x4,
+ IRQ_MERGER_FUNC_MIS = 0x8,
+ IRQ_MERGER_FUNC_ICR = 0xC,
+ IRQ_MERGER_FUNC_ISR = 0x10,
+ IRQ_MERGER_FUNC_NO = 0x1F,
+};
+
+#define IRQ_MERGER_IMSC_DEBUG0 \
+ (IRQ_MERGER_DEBUG_0)
+#define IRQ_MERGER_IMSC_DEBUG1 \
+ (IRQ_MERGER_DEBUG_1)
+#define IRQ_MERGER_IMSC_DEBUG2 \
+ (IRQ_MERGER_DEBUG_2)
+#define IRQ_MERGER_IMSC_DEBUG3 \
+ (IRQ_MERGER_DEBUG_3)
+#define IRQ_MERGER_IMSC_ERROR0 \
+ (IRQ_MERGER_ERROR_0)
+#define IRQ_MERGER_IMSC_ERROR1 \
+ (IRQ_MERGER_ERROR_1)
+#define IRQ_MERGER_IMSC_FRPROC0 \
+ (IRQ_MERGER_FRPROC_0)
+#define IRQ_MERGER_IMSC_FRPROC1 \
+ (IRQ_MERGER_FRPROC_1)
+#define IRQ_MERGER_IMSC_FRPROC2 \
+ (IRQ_MERGER_FRPROC_2)
+
+#define IRQ_MERGER_ICR_DEBUG0 \
+ (IRQ_MERGER_DEBUG_0 + IRQ_MERGER_FUNC_ICR)
+#define IRQ_MERGER_ICR_DEBUG1 \
+ (IRQ_MERGER_DEBUG_1 + IRQ_MERGER_FUNC_ICR)
+#define IRQ_MERGER_ICR_DEBUG2 \
+ (IRQ_MERGER_DEBUG_2 + IRQ_MERGER_FUNC_ICR)
+#define IRQ_MERGER_ICR_DEBUG3 \
+ (IRQ_MERGER_DEBUG_3 + IRQ_MERGER_FUNC_ICR)
+#define IRQ_MERGER_ICR_ERROR0 \
+ (IRQ_MERGER_ERROR_0 + IRQ_MERGER_FUNC_ICR)
+#define IRQ_MERGER_ICR_ERROR1 \
+ (IRQ_MERGER_ERROR_1 + IRQ_MERGER_FUNC_ICR)
+#define IRQ_MERGER_ICR_FRPROC0 \
+ (IRQ_MERGER_FRPROC_0 + IRQ_MERGER_FUNC_ICR)
+#define IRQ_MERGER_ICR_FRPROC1 \
+ (IRQ_MERGER_FRPROC_1 + IRQ_MERGER_FUNC_ICR)
+#define IRQ_MERGER_ICR_FRPROC2 \
+ (IRQ_MERGER_FRPROC_2 + IRQ_MERGER_FUNC_ICR)
+
+#define IRQ_MERGER_SR_4_CVDR_RT_SOF_VPWR_23_OFFSET 17
+#define IRQ_MERGER_SR_4_CVDR_RT_EOF_VPWR_23_OFFSET 21
+
+#define YUV_DT_420_8BITS 0x18
+#define YUV_DT_420_10BITS 0x19
+#define YUV_DT_LEGACY_420_8BITS 0x1A
+#define YUV_DT_420_8BITS_C 0x1C
+#define YUV_DT_420_10BITS_C 0x1D
+#define YUV_DT_422_8BITS 0x1E
+#define YUV_DT_422_10BITS 0x1F
+
+#define RAW_DT_RAW6 0x28
+#define RAW_DT_RAW7 0x29
+#define RAW_DT_RAW8 0x2A
+#define RAW_DT_RAW10 0x2B
+#define RAW_DT_RAW12 0x2C
+#define RAW_DT_RAW14 0x2D
+
+struct resources {
+ char *reg;
+};
+
+struct isp_clock {
+ struct clk *clk;
+ const char *name;
+ u32 freq;
+};
+
+struct isp {
+ void __iomem *ispss_ctrl;
+ void __iomem *smmu_ctrl;
+ void __iomem *irq_merger2;
+ struct v4l2_device v4l2_dev;
+ struct v4l2_async_notifier notifier;
+ struct media_device media_dev;
+ struct device *dev;
+ struct csiphy_device *csiphy;
+ struct sr_device *sr;
+ struct cvdr_device *cvdr;
+ struct isp_clock clks[ISP_NUM_CLKS];
+ void *virt_addr;
+ dma_addr_t hw_addr;
+ int csiphy_num;
+ unsigned int pool_size;
+ unsigned int frame_size;
+ unsigned int frame_count;
+ unsigned int frame_num;
+};
+
+struct isp_camera_interface {
+ u8 csiphy_id;
+ struct csiphy_csi2_cfg csi2;
+};
+
+struct isp_async_subdev {
+ struct v4l2_async_subdev asd; /* must be first */
+ struct isp_camera_interface interface;
+};
+
+void isp_writel(void __iomem *base , u32 reg, u32 value);
+u32 isp_readl(void __iomem *base , u32 reg);
+int isp_enable_clocks(struct isp_clock *clks, struct device *dev);
+void isp_disable_clocks(struct isp_clock *clks);
+void isp_ispss_clear_irq_state(struct isp *isp);
+void isp_ispss_enable_irq(struct isp *isp);
+u32 isp_clear_irq(struct isp *isp, enum IRQ_MERGER_TYPE irq);
+int frame_num2Offset(struct isp *isp, int frame_num);
+void isp_config_smmu_bypass(struct isp *isp);
+
+#endif /* HISI_ISP_H */