linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/5]  platform: dwc: Add of DesignWare MIPI CSI-2 Host
@ 2018-09-14 22:48 Luis Oliveira
  2018-09-14 22:48 ` [PATCH 1/5] media: platform: Add DesignWare MIPI CSI2 Host placeholder Luis Oliveira
                   ` (4 more replies)
  0 siblings, 5 replies; 10+ messages in thread
From: Luis Oliveira @ 2018-09-14 22:48 UTC (permalink / raw)
  To: linux-media, linux-kernel
  Cc: all-jpinto-org-pt02, Luis Oliveira, Mauro Carvalho Chehab,
	Luis Oliveira, Hans Verkuil, Geert Uytterhoeven,
	Laurent Pinchart, Arnd Bergmann, Jacob Chen, Neil Armstrong,
	Keiichi Watanabe, Kate Stewart, Philipp Zabel, Todor Tomov

This adds support for Synopsys MIPI CSI-2 Host and MIPI D-PHY.
The patch series include support for initialization/configuration of the
DW MIPI CSI-2 controller and DW MIPI D-PHY and both include a reference
platform driver.

This will enable future SoCs to use this standard approach and possibly
create a more clean environment.

This series also documents the dt-bindings needed for the platform
drivers.

This was applied in: https://git.linuxtv.org/media_tree.git

Luis Oliveira (5):
  media: platform: Add DesignWare MIPI CSI2 Host placeholder
  Documentation: dt-bindings: Document the Synopsys MIPI DPHY Rx
    bindings
  media: platform: dwc: Add DW MIPI DPHY core and platform
  Documentation: dt-bindings: Document bindings for DW MIPI CSI-2 Host
  media: platform: dwc: Add MIPI CSI-2 controller driver

 .../devicetree/bindings/media/snps,dw-csi-plat.txt |  74 +++
 .../devicetree/bindings/phy/snps,dphy-rx.txt       |  36 ++
 MAINTAINERS                                        |  10 +
 drivers/media/platform/Kconfig                     |   1 +
 drivers/media/platform/Makefile                    |   3 +
 drivers/media/platform/dwc/Kconfig                 |  42 ++
 drivers/media/platform/dwc/Makefile                |   4 +
 drivers/media/platform/dwc/dw-csi-plat.c           | 508 ++++++++++++++++++
 drivers/media/platform/dwc/dw-csi-plat.h           |  76 +++
 drivers/media/platform/dwc/dw-dphy-plat.c          | 365 +++++++++++++
 drivers/media/platform/dwc/dw-dphy-rx.c            | 592 +++++++++++++++++++++
 drivers/media/platform/dwc/dw-dphy-rx.h            | 176 ++++++
 drivers/media/platform/dwc/dw-mipi-csi.c           | 491 +++++++++++++++++
 drivers/media/platform/dwc/dw-mipi-csi.h           | 202 +++++++
 include/media/dwc/dw-mipi-csi-pltfrm.h             | 101 ++++
 15 files changed, 2681 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/media/snps,dw-csi-plat.txt
 create mode 100644 Documentation/devicetree/bindings/phy/snps,dphy-rx.txt
 create mode 100644 drivers/media/platform/dwc/Kconfig
 create mode 100644 drivers/media/platform/dwc/Makefile
 create mode 100644 drivers/media/platform/dwc/dw-csi-plat.c
 create mode 100644 drivers/media/platform/dwc/dw-csi-plat.h
 create mode 100644 drivers/media/platform/dwc/dw-dphy-plat.c
 create mode 100644 drivers/media/platform/dwc/dw-dphy-rx.c
 create mode 100644 drivers/media/platform/dwc/dw-dphy-rx.h
 create mode 100644 drivers/media/platform/dwc/dw-mipi-csi.c
 create mode 100644 drivers/media/platform/dwc/dw-mipi-csi.h
 create mode 100644 include/media/dwc/dw-mipi-csi-pltfrm.h

-- 
2.9.3


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 1/5] media: platform: Add DesignWare MIPI CSI2 Host placeholder
  2018-09-14 22:48 [PATCH 0/5] platform: dwc: Add of DesignWare MIPI CSI-2 Host Luis Oliveira
@ 2018-09-14 22:48 ` Luis Oliveira
  2018-09-15 12:16   ` kbuild test robot
  2018-09-15 12:34   ` kbuild test robot
  2018-09-14 22:48 ` [PATCH 2/5] Documentation: dt-bindings: Document the Synopsys MIPI DPHY Rx bindings Luis Oliveira
                   ` (3 subsequent siblings)
  4 siblings, 2 replies; 10+ messages in thread
From: Luis Oliveira @ 2018-09-14 22:48 UTC (permalink / raw)
  To: linux-media, linux-kernel
  Cc: all-jpinto-org-pt02, Luis Oliveira, Mauro Carvalho Chehab,
	Luis Oliveira, Hans Verkuil, Geert Uytterhoeven,
	Laurent Pinchart, Arnd Bergmann, Jacob Chen, Neil Armstrong,
	Keiichi Watanabe, Kate Stewart, Philipp Zabel, Todor Tomov

This patch has the intention of make the patchseries more clear by creating
a dwc folder and a Kconfig variable that sets dependencies.

Signed-off-by: Luis Oliveira <lolivei@synopsys.com>
---
 drivers/media/platform/Kconfig     |  1 +
 drivers/media/platform/Makefile    |  3 +++
 drivers/media/platform/dwc/Kconfig | 19 +++++++++++++++++++
 3 files changed, 23 insertions(+)
 create mode 100644 drivers/media/platform/dwc/Kconfig

diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index f627587..f627a27 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -137,6 +137,7 @@ source "drivers/media/platform/am437x/Kconfig"
 source "drivers/media/platform/xilinx/Kconfig"
 source "drivers/media/platform/rcar-vin/Kconfig"
 source "drivers/media/platform/atmel/Kconfig"
+source "drivers/media/platform/dwc/Kconfig"
 
 config VIDEO_TI_CAL
 	tristate "TI CAL (Camera Adaptation Layer) driver"
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index 6ab6200..def2f33 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -98,3 +98,6 @@ obj-$(CONFIG_VIDEO_QCOM_VENUS)		+= qcom/venus/
 obj-y					+= meson/
 
 obj-y					+= cros-ec-cec/
+
+obj-y					+= dwc/
+
diff --git a/drivers/media/platform/dwc/Kconfig b/drivers/media/platform/dwc/Kconfig
new file mode 100644
index 0000000..6b1e985
--- /dev/null
+++ b/drivers/media/platform/dwc/Kconfig
@@ -0,0 +1,19 @@
+#
+#  Synopsys DWC Platform drivers
+#	Most drivers here are currently for MIPI CSI-2 and MIPI DPHY support
+
+config DWC_MIPI_CSI2_HOST
+	bool "Synopsys Designware CSI-2 Host Controller and DPHY-RX support"
+	select VIDEO_DEV
+	select VIDEO_V4L2
+	select VIDEO_V4L2_SUBDEV_API
+	select VIDEOBUF2_VMALLOC
+	select VIDEOBUF2_DMA_CONTIG
+	select GENERIC_PHY
+	select VIDEO_OV5647
+	help
+   	 This selects the CSI-2 host controller support.
+	 If you have a controller with this interface, say Y
+
+	  If unsure, say N.
+
-- 
2.9.3


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/5] Documentation: dt-bindings: Document the Synopsys MIPI DPHY Rx bindings
  2018-09-14 22:48 [PATCH 0/5] platform: dwc: Add of DesignWare MIPI CSI-2 Host Luis Oliveira
  2018-09-14 22:48 ` [PATCH 1/5] media: platform: Add DesignWare MIPI CSI2 Host placeholder Luis Oliveira
@ 2018-09-14 22:48 ` Luis Oliveira
  2018-09-14 22:48 ` [PATCH 3/5] media: platform: dwc: Add DW MIPI DPHY core and platform Luis Oliveira
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 10+ messages in thread
From: Luis Oliveira @ 2018-09-14 22:48 UTC (permalink / raw)
  To: linux-media, linux-kernel
  Cc: all-jpinto-org-pt02, Luis Oliveira, Luis Oliveira, Rob Herring,
	Mark Rutland, Mauro Carvalho Chehab, Hans Verkuil,
	Geert Uytterhoeven, Laurent Pinchart, Arnd Bergmann, Jacob Chen,
	Neil Armstrong, Keiichi Watanabe, Kate Stewart, Philipp Zabel,
	Todor Tomov, devicetree

Add device-tree bindings documentation for SNPS DesignWare MIPI D-PHY in
RX mode.

Signed-off-by: Luis Oliveira <lolivei@synopsys.com>
---
 .../devicetree/bindings/phy/snps,dphy-rx.txt       | 36 ++++++++++++++++++++++
 1 file changed, 36 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/phy/snps,dphy-rx.txt

diff --git a/Documentation/devicetree/bindings/phy/snps,dphy-rx.txt b/Documentation/devicetree/bindings/phy/snps,dphy-rx.txt
new file mode 100644
index 0000000..4f22a43
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/snps,dphy-rx.txt
@@ -0,0 +1,36 @@
+Synopsys DesignWare MIPI Rx D-PHY block details
+
+Description
+-----------
+
+The Synopsys MIPI D-PHY controller supports MIPI-DPHY in receiver mode.
+Please refer to phy-bindings.txt for more information.
+
+Required properties:
+- compatible		: Shall be "snps,dphy-rx".
+- #phy-cells		: Must be 1.
+- snps,dphy-frequency	: Output frequency of the D-PHY.
+- snps,dphy-te-len	: Size of the communication interface (8 bits->8 or 12bits->12).
+- reg			: Physical base address and size of the device memory mapped
+		 	  registers;
+
+Optional properties:
+- snps,compat-mode	: Compatibility mode control
+
+The per-board settings:
+- gpios 		: Synopsys testchip used as reference uses this to change setup
+  		  	  configurations.
+
+Example:
+
+	mipi_dphy_rx1: dphy@3040 {
+		compatible = "snps,dphy-rx";
+		#phy-cells = <1>;
+		snps,dphy-frequency = <300000>;
+		snps,dphy-te-len = <12>;
+		snps,compat-mode = <1>;
+		reg = < 0x03040 0x20
+			0x08000 0x100
+			0x09000 0x100>;
+	};
+
-- 
2.9.3


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 3/5] media: platform: dwc: Add DW MIPI DPHY core and platform
  2018-09-14 22:48 [PATCH 0/5] platform: dwc: Add of DesignWare MIPI CSI-2 Host Luis Oliveira
  2018-09-14 22:48 ` [PATCH 1/5] media: platform: Add DesignWare MIPI CSI2 Host placeholder Luis Oliveira
  2018-09-14 22:48 ` [PATCH 2/5] Documentation: dt-bindings: Document the Synopsys MIPI DPHY Rx bindings Luis Oliveira
@ 2018-09-14 22:48 ` Luis Oliveira
  2018-09-15  9:23   ` kbuild test robot
  2018-09-14 22:48 ` [PATCH 4/5] Documentation: dt-bindings: Document bindings for DW MIPI CSI-2 Host Luis Oliveira
  2018-09-14 22:48 ` [PATCH 5/5] media: platform: dwc: Add MIPI CSI-2 controller driver Luis Oliveira
  4 siblings, 1 reply; 10+ messages in thread
From: Luis Oliveira @ 2018-09-14 22:48 UTC (permalink / raw)
  To: linux-media, linux-kernel
  Cc: all-jpinto-org-pt02, Luis Oliveira, Mauro Carvalho Chehab,
	Luis Oliveira, Hans Verkuil, Geert Uytterhoeven,
	Laurent Pinchart, Arnd Bergmann, Jacob Chen, Neil Armstrong,
	Keiichi Watanabe, Kate Stewart, Philipp Zabel, Todor Tomov

Add of Synopsys MIPI D-PHY in RX mode support.
Separated in the implementation are platform dependent probing functions.

Signed-off-by: Luis Oliveira <lolivei@synopsys.com>
---
 drivers/media/platform/dwc/Kconfig        |  12 +
 drivers/media/platform/dwc/Makefile       |   2 +
 drivers/media/platform/dwc/dw-dphy-plat.c | 365 ++++++++++++++++++
 drivers/media/platform/dwc/dw-dphy-rx.c   | 592 ++++++++++++++++++++++++++++++
 drivers/media/platform/dwc/dw-dphy-rx.h   | 176 +++++++++
 5 files changed, 1147 insertions(+)
 create mode 100644 drivers/media/platform/dwc/Makefile
 create mode 100644 drivers/media/platform/dwc/dw-dphy-plat.c
 create mode 100644 drivers/media/platform/dwc/dw-dphy-rx.c
 create mode 100644 drivers/media/platform/dwc/dw-dphy-rx.h

diff --git a/drivers/media/platform/dwc/Kconfig b/drivers/media/platform/dwc/Kconfig
index 6b1e985..6d1a712 100644
--- a/drivers/media/platform/dwc/Kconfig
+++ b/drivers/media/platform/dwc/Kconfig
@@ -17,3 +17,15 @@ config DWC_MIPI_CSI2_HOST
 
 	  If unsure, say N.
 
+if DWC_MIPI_CSI2_HOST
+
+config DWC_MIPI_TC_DPHY_G128
+	tristate "DesignWare platform support using a G128 Test Chip"
+	depends on DWC_MIPI_CSI2_HOST
+	help
+	 Synopsys Test Chip is a MIPI D-PHY for prototyping purposes.
+
+	 If unsure, say N.
+
+endif # DWC_MIPI_CSI2_HOST
+
diff --git a/drivers/media/platform/dwc/Makefile b/drivers/media/platform/dwc/Makefile
new file mode 100644
index 0000000..8be6f68
--- /dev/null
+++ b/drivers/media/platform/dwc/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_DWC_MIPI_TC_DPHY_G128)	+= dw-dphy-platfrm.o
+dw-dphy-platfrm-objs	:= dw-dphy-plat.o dw-dphy-rx.o
diff --git a/drivers/media/platform/dwc/dw-dphy-plat.c b/drivers/media/platform/dwc/dw-dphy-plat.c
new file mode 100644
index 0000000..b1810ad
--- /dev/null
+++ b/drivers/media/platform/dwc/dw-dphy-plat.c
@@ -0,0 +1,365 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * dw-dphy-plat.c
+ *
+ * Copyright(c) 2018-present, Synopsys, Inc. and/or its affiliates.
+ * Luis Oliveira <Luis.Oliveira@synopsys.com>
+ *
+ */
+
+#include "dw-dphy-rx.h"
+
+static struct phy *dw_dphy_xlate(struct device *dev,
+			struct of_phandle_args *args)
+{
+	struct dw_dphy_rx *dphy = dev_get_drvdata(dev);
+
+	return dphy->phy;
+}
+
+static ssize_t dphy_reset_show(struct device *dev,
+			struct device_attribute *attr,
+			char *buf)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct dw_dphy_rx *dphy = platform_get_drvdata(pdev);
+	char buffer[15];
+
+	dw_dphy_write(dphy, R_CSI2_DPHY_RSTZ, 0);
+	usleep_range(100, 200);
+	dw_dphy_write(dphy, R_CSI2_DPHY_RSTZ, 1);
+
+	return strlcpy(buf, buffer, PAGE_SIZE);
+}
+
+static ssize_t dphy_freq_store(struct device *dev,
+			struct device_attribute *attr,
+			const char *buf,
+			size_t count)
+{
+	int ret;
+	unsigned long freq;
+
+	struct platform_device *pdev = to_platform_device(dev);
+	struct dw_dphy_rx *dphy = platform_get_drvdata(pdev);
+
+	ret = kstrtoul(buf, 10, &freq);
+	if (ret < 0)
+		return ret;
+
+	if (freq > 2500) {
+		dev_info(dev, "Freq must be under 2500 Mhz\n");
+		return count;
+	}
+	if (freq < 80) {
+		dev_info(dev, "Freq must be over 80 Mhz\n");
+		return count;
+	}
+
+	dev_info(dev, "Data Rate %lu Mbps\n", freq);
+	dphy->dphy_freq = freq * 1000;
+
+	return count;
+
+}
+
+static ssize_t dphy_freq_show(struct device *dev,
+			struct device_attribute *attr,
+			char *buf)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct dw_dphy_rx *dphy = platform_get_drvdata(pdev);
+	char buffer[15];
+
+	snprintf(buffer, 15, "Freq %d\n", dphy->dphy_freq / 1000);
+
+	return strlcpy(buf, buffer, PAGE_SIZE);
+}
+
+static ssize_t dphy_addr_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf,
+		size_t count)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct dw_dphy_rx *dphy = platform_get_drvdata(pdev);
+	unsigned long val;
+	int ret;
+	u8 addr, payload;
+
+	ret = kstrtoul(buf, 32, &val);
+	if (ret < 0)
+		return ret;
+
+	payload = (u16)val;
+	addr = (u16)(val >> 16);
+
+	dev_info(dev, "addr 0x%lX\n", val);
+	dev_info(dev, "payload: 0x%X\n", addr);
+
+	dev_info(dev,
+		"Addr [0x%x] -> 0x%x\n", (unsigned int)addr,
+		dw_dphy_te_read(dphy, addr));
+
+	return count;
+}
+
+static ssize_t idelay_show(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct dw_dphy_rx *dphy = platform_get_drvdata(pdev);
+	char buffer[15];
+
+	snprintf(buffer, 15, "idelay %d\n", dw_dphy_if_get_idelay(dphy));
+
+	return strlcpy(buf, buffer, PAGE_SIZE);
+}
+
+static ssize_t idelay_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf,
+		size_t count)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct dw_dphy_rx *dphy = platform_get_drvdata(pdev);
+	int ret;
+	unsigned long val;
+	u8 lane, delay;
+
+	ret = kstrtoul(buf, 16, &val);
+	if (ret < 0)
+		return ret;
+
+	lane = (u8)val;
+	delay = (u8)(val >> 8);
+
+	dev_dbg(dev, "Lanes %u\n", lane);
+	dev_dbg(dev, "Delay %u\n", delay);
+
+	dw_dphy_if_set_idelay_lane(dphy, delay, lane);
+
+	return count;
+}
+
+static ssize_t len_config_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	int ret;
+	unsigned long length;
+
+	struct platform_device *pdev = to_platform_device(dev);
+	struct dw_dphy_rx *dphy = platform_get_drvdata(pdev);
+
+	ret = kstrtoul(buf, 10, &length);
+	if (ret < 0)
+		return ret;
+
+	if (length == BIT8)
+		pr_info("Configured for 8-bit interface\n");
+	else if (length == BIT12)
+		pr_info("Configured for 12-bit interface\n");
+	else
+		return count;
+
+	dphy->dphy_te_len = length;
+
+	return count;
+
+}
+
+static ssize_t len_config_show(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct dw_dphy_rx *dphy = platform_get_drvdata(pdev);
+	char buffer[20];
+
+	snprintf(buffer, 20, "Length %d\n", dphy->dphy_te_len);
+
+	return strlcpy(buf, buffer, PAGE_SIZE);
+}
+
+static ssize_t dw_dphy_g118_settle_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf,
+		size_t count)
+{
+	int ret;
+	unsigned long lp_time;
+
+	struct platform_device *pdev = to_platform_device(dev);
+	struct dw_dphy_rx *dphy = platform_get_drvdata(pdev);
+
+	ret = kstrtoul(buf, 10, &lp_time);
+	if (ret < 0)
+		return ret;
+
+	if ((lp_time > 1) && (lp_time < 10000))
+		dphy->lp_time = lp_time;
+	else {
+		pr_info("Invalid Value configuring for 1000 ns\n");
+		dphy->lp_time = 1000;
+	}
+
+	dphy->lp_time = lp_time;
+
+	return count;
+
+}
+
+static ssize_t dw_dphy_g118_settle_show(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct dw_dphy_rx *dphy = platform_get_drvdata(pdev);
+	char buffer[10];
+
+	snprintf(buffer, 10, "Settle %d ns\n", dphy->lp_time);
+
+	return strlcpy(buf, buffer, PAGE_SIZE);
+}
+
+static DEVICE_ATTR_RO(dphy_reset);
+static DEVICE_ATTR_RW(dphy_freq);
+static DEVICE_ATTR_WO(dphy_addr);
+static DEVICE_ATTR_RW(idelay);
+static DEVICE_ATTR_RW(len_config);
+static DEVICE_ATTR_RW(dw_dphy_g118_settle);
+
+static struct phy_ops dw_dphy_ops = {
+	.init = dw_dphy_init,
+	.reset = dw_dphy_reset,
+	.power_on = dw_dphy_power_on,
+	.power_off = dw_dphy_power_off,
+	.owner = THIS_MODULE,
+};
+
+static int dw_dphy_rx_probe(struct platform_device *pdev)
+{
+	struct dw_dphy_rx *dphy;
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	struct phy_provider *phy_provider;
+	struct phy *phy;
+
+	dphy = devm_kzalloc(dev, sizeof(*dphy), GFP_KERNEL);
+	if (!dphy)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	dphy->base_address = devm_ioremap(dev, res->start, resource_size(res));
+	if (IS_ERR(dphy->base_address)) {
+		dev_err(dev, "error requesting base address\n");
+		return PTR_ERR(dphy->base_address);
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	dphy->dphy1_if_addr = devm_ioremap_resource(dev, res);
+	if (IS_ERR(dphy->dphy1_if_addr)) {
+		dev_err(dev, "error requesting dphy 1 if regbank\n");
+		return PTR_ERR(dphy->dphy1_if_addr);
+	}
+
+	dphy->max_lanes =
+		dw_dphy_if_read_msk(dphy, DPHYID, DPHY_ID_LANE_SUPPORT, 4);
+
+	dphy->dphy_gen = dw_dphy_if_read_msk(dphy, DPHYID, DPHY_ID_GEN, 4);
+	dev_info(dev, "DPHY GEN %s with maximum %s lanes\n",
+			dphy->dphy_gen == GEN3 ? "3" : "2",
+			dphy->max_lanes == CTRL_8_LANES ? "8" : "4");
+
+	if (dphy->max_lanes == CTRL_8_LANES) {
+		res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+		dphy->dphy2_if_addr =
+			devm_ioremap(dev, res->start, resource_size(res));
+
+		if (IS_ERR(dphy->dphy2_if_addr)) {
+			dev_err(dev, "error requesting dphy 2 if regbank\n");
+			return PTR_ERR(dphy->dphy2_if_addr);
+		}
+
+		dphy->config_gpio = of_get_gpio(dev->of_node, 0);
+		if (!gpio_is_valid(dphy->config_gpio)) {
+			dev_err(dev, "failed to parse config gpio\n");
+			return dphy->config_gpio;
+		}
+	}
+
+	if (of_property_read_u32(dev->of_node,
+			"snps,dphy-frequency",
+			&dphy->dphy_freq)) {
+		dev_err(dev, "failed to find dphy frequency\n");
+		return -EINVAL;
+	}
+
+	if (of_property_read_u32(dev->of_node,
+			"snps,dphy-te-len",
+			&dphy->dphy_te_len)) {
+		dev_err(dev, "failed to find dphy te length\n");
+		return -EINVAL;
+	}
+
+	if (of_property_read_u32(dev->of_node,
+			"snps,compat-mode",
+			&dphy->compat_mode)) {
+		dev_err(dev, "failed to find compat mode\n");
+		return -EINVAL;
+	}
+
+	dev_set_drvdata(dev, dphy);
+	spin_lock_init(&dphy->slock);
+
+	phy = devm_phy_create(dev, NULL, &dw_dphy_ops);
+	if (IS_ERR(phy)) {
+		dev_err(dev, "failed to create PHY\n");
+		return PTR_ERR(phy);
+	}
+
+	dphy->phy = phy;
+	phy_set_drvdata(phy, dphy);
+
+	phy_provider = devm_of_phy_provider_register(dev, dw_dphy_xlate);
+	if (IS_ERR(phy_provider)) {
+		dev_err(dev, "error getting phy provider\n");
+		return PTR_ERR(phy_provider);
+	}
+
+	dphy->lp_time = 1000; /* 1000 ns */
+	dphy->lanes_config = dw_dphy_setup_config(dphy);
+	dev_dbg(dev, "rx-dphy created\n");
+
+	device_create_file(&pdev->dev, &dev_attr_dphy_reset);
+	device_create_file(&pdev->dev, &dev_attr_dphy_freq);
+	device_create_file(&pdev->dev, &dev_attr_dphy_addr);
+	device_create_file(&pdev->dev, &dev_attr_idelay);
+	device_create_file(&pdev->dev, &dev_attr_len_config);
+	device_create_file(&pdev->dev, &dev_attr_dw_dphy_g118_settle);
+
+	return 0;
+}
+
+static const struct of_device_id dw_dphy_rx_of_match[] = {
+	{ .compatible = "snps,dphy-rx" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, dw_dphy_rx_of_match);
+
+static struct platform_driver dw_dphy_rx_driver = {
+	.probe	= dw_dphy_rx_probe,
+	.driver = {
+		.of_match_table	= dw_dphy_rx_of_match,
+		.name  = "snps-dphy-rx",
+		.owner = THIS_MODULE,
+	}
+};
+module_platform_driver(dw_dphy_rx_driver);
+
+MODULE_DESCRIPTION("SNPS MIPI DPHY Rx driver");
+MODULE_AUTHOR("Luis Oliveira <lolivei@synopsys.com>");
+MODULE_LICENSE("GPL v2");
+
diff --git a/drivers/media/platform/dwc/dw-dphy-rx.c b/drivers/media/platform/dwc/dw-dphy-rx.c
new file mode 100644
index 0000000..f5c6719
--- /dev/null
+++ b/drivers/media/platform/dwc/dw-dphy-rx.c
@@ -0,0 +1,592 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Synopsys MIPI D-PHY driver
+ *
+ * Copyright (c) 2018 Synopsys, Inc. and/or its affiliates.
+ * Author: Luis Oliveira <Luis.Oliveira@synopsys.com>
+ *
+ */
+
+#include "dw-dphy-rx.h"
+
+struct range_dphy_gen2 {
+	u64 freq;
+	u8 hsfregrange;
+};
+
+struct range_dphy_gen2 range_gen2[] = {
+	{  80, 0x00}, {  90, 0x10}, { 100, 0x20},
+	{ 110, 0x30}, { 120, 0x01}, { 130, 0x11},
+	{ 140, 0x21}, { 150, 0x31}, { 160, 0x02},
+	{ 170, 0x12}, { 180, 0x22}, { 190, 0x32},
+	{ 205, 0x03}, { 220, 0x13}, { 235, 0x23},
+	{ 250, 0x33}, { 275, 0x04}, { 300, 0x14},
+	{ 325, 0x05}, { 350, 0x15}, { 400, 0x25},
+	{ 450, 0x06}, { 500, 0x16}, { 550, 0x07},
+	{ 600, 0x17}, { 650, 0x08}, { 700, 0x18},
+	{ 750, 0x09}, { 800, 0x19}, { 850, 0x29},
+	{ 900, 0x39}, { 950, 0x0A}, {1000, 0x1A},
+	{1050, 0x2A}, {1100, 0x3A}, {1150, 0x0B},
+	{1200, 0x1B}, {1250, 0x2B}, {1300, 0x3B},
+	{1350, 0x0C}, {1400, 0x1C}, {1450, 0x2C},
+	{1500, 0x3C}, {1550, 0x0D}, {1600, 0x1D},
+	{1650, 0x2D}, {1700, 0x0E}, {1750, 0x1E},
+	{1800, 0x2E}, {1850, 0x3E}, {1900, 0x0F},
+	{1950, 0x1F}, {2000, 0x2F},
+};
+
+struct range_dphy_gen3 {
+	u64 freq;
+	u8 hsfregrange;
+	u32 osc_freq_target;
+};
+
+struct range_dphy_gen3 range_gen3[] = {
+
+	{  80, 0x00, 0x1B6}, {  90, 0x10, 0x1B6}, { 100, 0x20, 0x1B6},
+	{ 110, 0x30, 0x1B6}, { 120, 0x01, 0x1B6}, { 130, 0x11, 0x1B6},
+	{ 140, 0x21, 0x1B6}, { 150, 0x31, 0x1B6}, { 160, 0x02, 0x1B6},
+	{ 170, 0x12, 0x1B6}, { 180, 0x22, 0x1B6}, { 190, 0x32, 0x1B6},
+	{ 205, 0x03, 0x1B6}, { 220, 0x13, 0x1B6}, { 235, 0x23, 0x1B6},
+	{ 250, 0x33, 0x1B6}, { 275, 0x04, 0x1B6}, { 300, 0x14, 0x1B6},
+	{ 325, 0x25, 0x1B6}, { 350, 0x35, 0x1B6}, { 400, 0x05, 0x1B6},
+	{ 450, 0x16, 0x1B6}, { 500, 0x26, 0x1B6}, { 550, 0x37, 0x1B6},
+	{ 600, 0x07, 0x1B6}, { 650, 0x18, 0x1B6}, { 700, 0x28, 0x1B6},
+	{ 750, 0x39, 0x1B6}, { 800, 0x09, 0x1B6}, { 850, 0x19, 0x1B6},
+	{ 900, 0x29, 0x1B6}, { 950, 0x3A, 0x1B6}, {1000, 0x0A, 0x1B6},
+	{1050, 0x1A, 0x1B6}, {1100, 0x2A, 0x1B6}, {1150, 0x3B, 0x1B6},
+	{1200, 0x0B, 0x1B6}, {1250, 0x1B, 0x1B6}, {1300, 0x2B, 0x1B6},
+	{1350, 0x3C, 0x1B6}, {1400, 0x0C, 0x1B6}, {1450, 0x1C, 0x1B6},
+	{1500, 0x2C, 0x1B6}, {1550, 0x3D, 0x10F}, {1600, 0x0D, 0x118},
+	{1650, 0x1D, 0x121}, {1700, 0x2E, 0x12A}, {1750, 0x3E, 0x132},
+	{1800, 0x0E, 0x13B}, {1850, 0x1E, 0x144}, {1900, 0x2F, 0x14D},
+	{1950, 0x3F, 0x155}, {2000, 0x0F, 0x15E}, {2050, 0x40, 0x167},
+	{2100, 0x41, 0x170}, {2150, 0x42, 0x178}, {2200, 0x43, 0x181},
+	{2250, 0x44, 0x18A}, {2300, 0x45, 0x193}, {2350, 0x46, 0x19B},
+	{2400, 0x47, 0x1A4}, {2450, 0x48, 0x1AD}, {2500, 0x49, 0x1B6}
+};
+
+u8 dw_dphy_setup_config(struct dw_dphy_rx *dphy)
+{
+	u8 ret;
+	int setup_config;
+
+	if (dphy->max_lanes == CTRL_4_LANES)
+		return CTRL_4_LANES;
+
+	ret = gpio_request(dphy->config_gpio, "config");
+	if (ret < 0) {
+		pr_err("could not acquire config gpio (err=%d)\n", ret);
+		return ret;
+	}
+
+	setup_config = gpio_get_value(dphy->config_gpio);
+	pr_debug("CONFIG %s\n", setup_config == CTRL_8_LANES ? "8L" : "4+4L");
+	gpio_free(dphy->config_gpio);
+
+	return setup_config;
+}
+void dw_dphy_if_write(struct dw_dphy_rx *dphy, u32 address, u32 data)
+{
+	iowrite32(data, dphy->dphy1_if_addr + address);
+
+	if (dphy->lanes_config == CTRL_4_LANES)
+		return;
+
+	iowrite32(data, dphy->dphy2_if_addr + address);
+}
+
+u32 dw_dphy_if_read(struct dw_dphy_rx *dphy, u64 address)
+{
+	u32 if1, if2;
+
+	if1 = ioread32(dphy->dphy1_if_addr + address);
+
+	if (dphy->lanes_config == CTRL_4_LANES)
+		goto end;
+
+	if (dphy->lanes_config == DPHYID)
+		goto end;
+
+	if2 = ioread32(dphy->dphy2_if_addr + address);
+
+	if (if1 != if2)
+		pr_err("Values read different for each interface\n");
+
+end:
+	return if1;
+}
+
+void dw_dphy_write(struct dw_dphy_rx *dphy, u32 address, u32 data)
+{
+	iowrite32(data, dphy->base_address + address);
+
+	if (dphy->lanes_config == CTRL_4_LANES)
+		return;
+
+	if (address == R_CSI2_DPHY_TST_CTRL0)
+		iowrite32(data, dphy->base_address + R_CSI2_DPHY2_TST_CTRL0);
+	else if (address == R_CSI2_DPHY_TST_CTRL1)
+		iowrite32(data, dphy->base_address + R_CSI2_DPHY2_TST_CTRL1);
+}
+
+u32 dw_dphy_read(struct dw_dphy_rx *dphy, u64 address)
+{
+	u32 dphy1, dphy2;
+
+	dphy1 = ioread32(dphy->base_address + address);
+
+	if (dphy->lanes_config == CTRL_4_LANES)
+		goto end;
+
+	if (address == R_CSI2_DPHY_TST_CTRL0)
+		dphy2 = ioread32(dphy->base_address + R_CSI2_DPHY2_TST_CTRL0);
+	else if (address == R_CSI2_DPHY_TST_CTRL1)
+		dphy2 = ioread32(dphy->base_address + R_CSI2_DPHY2_TST_CTRL1);
+
+	if (dphy1 != dphy2)
+		pr_err("Values read different for each dphy\n");
+
+end:
+	return dphy1;
+}
+
+void dw_dphy_write_msk(struct dw_dphy_rx *dev,
+		u64 address, u64 data, u8 shift, u8 width)
+{
+	u32 mask = (1 << width) - 1;
+	u32 temp = dw_dphy_read(dev, address);
+
+	temp &= ~(mask << shift);
+	temp |= (data & mask) << shift;
+	dw_dphy_write(dev, address, temp);
+}
+
+static void dw_dphy_te_12b_write(struct dw_dphy_rx *dphy, u16 addr, u8 data)
+{
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL1, 0, PHY_TESTEN, 1);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL0, 0, PHY_TESTCLK, 1);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL1, 1, PHY_TESTEN, 1);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL0, 1, PHY_TESTCLK, 1);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL1, 0x00, PHY_TESTDIN, 8);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL0, 0, PHY_TESTCLK, 1);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL1, 0, PHY_TESTEN, 1);
+	dw_dphy_write_msk(dphy,
+		R_CSI2_DPHY_TST_CTRL1, (u8) (addr >> 8), PHY_TESTDIN, 8);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL0, 1, PHY_TESTCLK, 1);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL0, 0, PHY_TESTCLK, 1);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL1, 1, PHY_TESTEN, 1);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL0, 1, PHY_TESTCLK, 1);
+	dw_dphy_write_msk(dphy,
+		R_CSI2_DPHY_TST_CTRL1, (u8) addr, PHY_TESTDIN, 8);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL0, 0, PHY_TESTCLK, 1);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL1, 0, PHY_TESTEN, 1);
+	dw_dphy_write_msk(dphy,
+		R_CSI2_DPHY_TST_CTRL1, (u8) data, PHY_TESTDIN, 8);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL0, 1, PHY_TESTCLK, 1);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL0, 0, PHY_TESTCLK, 1);
+}
+
+static void dw_dphy_te_8b_write(struct dw_dphy_rx *dphy, u8 addr, u8 data)
+{
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL0, 1, PHY_TESTCLK, 1);
+	dw_dphy_write(dphy, R_CSI2_DPHY_TST_CTRL1, addr);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL1, 1, PHY_TESTEN, 1);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL0, 0, PHY_TESTCLK, 1);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL1, 0, PHY_TESTEN, 1);
+	dw_dphy_write(dphy, R_CSI2_DPHY_TST_CTRL1, data);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL0, 1, PHY_TESTCLK, 1);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL0, 0, PHY_TESTCLK, 1);
+}
+
+static void dw_dphy_te_write(struct dw_dphy_rx *dphy, u16 addr, u8 data)
+{
+
+	if (dphy->dphy_te_len == BIT12)
+		dw_dphy_te_12b_write(dphy, addr, data);
+	else
+		dw_dphy_te_8b_write(dphy, addr, data);
+}
+
+static int dw_dphy_te_12b_read(struct dw_dphy_rx *dphy, u32 addr)
+{
+	u8 ret;
+
+	dw_dphy_write(dphy, R_CSI2_DPHY_SHUTDOWNZ, 0);
+	dw_dphy_write(dphy, R_CSI2_DPHY_RSTZ, 0);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL0, 0, PHY_TESTCLK, 1);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL1, 0, PHY_TESTEN, 1);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL1, 1, PHY_TESTEN, 1);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL0, 1, PHY_TESTCLK, 1);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL1, 0x00, PHY_TESTDIN, 8);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL0, 0, PHY_TESTCLK, 1);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL1, 0, PHY_TESTEN, 1);
+	dw_dphy_write_msk(dphy,
+		R_CSI2_DPHY_TST_CTRL1, (u8) (addr >> 8), PHY_TESTDIN, 8);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL0, 1, PHY_TESTCLK, 1);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL0, 0, PHY_TESTCLK, 1);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL1, 1, PHY_TESTEN, 1);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL0, 1, PHY_TESTCLK, 1);
+	dw_dphy_write_msk(dphy,
+		R_CSI2_DPHY_TST_CTRL1, (u8) addr, PHY_TESTDIN, 8);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL0, 0, PHY_TESTCLK, 1);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL1, 0x00, 0, PHY_TESTDIN);
+	ret = dw_dphy_read_msk(dphy, R_CSI2_DPHY_TST_CTRL1, PHY_TESTDOUT, 8);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL1, 0, PHY_TESTEN, 1);
+	dw_dphy_write(dphy, R_CSI2_DPHY_RSTZ, 1);
+	dw_dphy_write(dphy, R_CSI2_DPHY_SHUTDOWNZ, 1);
+
+	return ret;
+}
+
+static int dw_dphy_te_8b_read(struct dw_dphy_rx *dphy, u32 addr)
+{
+	u8 ret;
+
+	dw_dphy_write(dphy, R_CSI2_DPHY_SHUTDOWNZ, 0);
+	dw_dphy_write(dphy, R_CSI2_DPHY_RSTZ, 0);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL1, 1, PHY_TESTEN, 1);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL0, 1, PHY_TESTCLK, 1);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL1, addr, PHY_TESTDIN, 8);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL0, 0, PHY_TESTCLK, 1);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL1, 0, PHY_TESTEN, 1);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL1, 0, PHY_TESTDIN, 8);
+	ret = dw_dphy_read_msk(dphy, R_CSI2_DPHY_TST_CTRL1, PHY_TESTDOUT, 8);
+	dw_dphy_write(dphy, R_CSI2_DPHY_RSTZ, 1);
+	dw_dphy_write(dphy, R_CSI2_DPHY_SHUTDOWNZ, 1);
+
+	return ret;
+}
+
+int dw_dphy_te_read(struct dw_dphy_rx *dphy, u32 addr)
+{
+	int ret;
+
+	if (dphy->dphy_te_len == BIT12)
+		ret = dw_dphy_te_12b_read(dphy, addr);
+	else
+		ret = dw_dphy_te_8b_read(dphy, addr);
+
+	return ret;
+}
+
+static void dw_dphy_if_init(struct dw_dphy_rx *dphy)
+{
+	dw_dphy_if_write(dphy, DPHYGLUEIFTESTER, RESET);
+	dw_dphy_if_write(dphy, DPHYGLUEIFTESTER, TX_PHY);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL0, 1, PHY_TESTCLR, 1);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL0, 0, PHY_TESTCLR, 1);
+	dw_dphy_if_write(dphy, DPHYZCALCTRL, 0);
+	dw_dphy_if_write(dphy, DPHYZCALCTRL, 1);
+	dw_dphy_if_write(dphy, DPHYGLUEIFTESTER, RESET);
+	dw_dphy_if_write(dphy, DPHYGLUEIFTESTER, GLUELOGIC);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL0, 1, PHY_TESTCLR, 1);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL0, 0, PHY_TESTCLR, 1);
+	dw_dphy_if_write(dphy, DPHYZCALCTRL, 0);
+	dw_dphy_if_write(dphy, DPHYZCALCTRL, 1);
+	dw_dphy_if_write(dphy, DPHYGLUEIFTESTER, RESET);
+	dw_dphy_if_write(dphy, DPHYGLUEIFTESTER, RX_PHY);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL0, 1, PHY_TESTCLR, 1);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL0, 0, PHY_TESTCLR, 1);
+	dw_dphy_if_write(dphy, DPHYZCALCTRL, 0);
+	dw_dphy_if_write(dphy, DPHYZCALCTRL, 1);
+}
+
+static void dw_dphy_gen3_12bit_tc_power_up(struct dw_dphy_rx *dphy)
+{
+	dw_dphy_if_write(dphy, DPHYGLUEIFTESTER, RESET);
+	dw_dphy_if_write(dphy, DPHYGLUEIFTESTER, GLUELOGIC);
+	dw_dphy_te_write(dphy, CFGCLKFREQRANGE_TX, 0x1C);
+
+	/* CLKSEL | UPDATEPLL | SHADOW_CLEAR | SHADOW_CTRL | FORCEPLL */
+	dw_dphy_te_write(dphy, BYPASS, 0x3F);
+
+	/* IO_DS3 | IO_DS2 | IO_DS1 | IO_DS0 */
+	if (dphy->dphy_freq > 1500)
+		dw_dphy_te_write(dphy, IO_DS, 0x0F);
+
+	dw_dphy_if_write(dphy, DPHYGLUEIFTESTER, RESET);
+	dw_dphy_if_write(dphy, DPHYGLUEIFTESTER, RX_PHY);
+}
+
+static void dw_dphy_gen3_8bit_tc_power_up(struct dw_dphy_rx *dphy)
+{
+	u32 input_freq = dphy->dphy_freq / 1000;
+
+	dw_dphy_if_write(dphy, DPHYGLUEIFTESTER, RESET);
+	dw_dphy_if_write(dphy, DPHYGLUEIFTESTER, GLUELOGIC);
+	dw_dphy_te_write(dphy, CFGCLKFREQRANGE_RX, 0x1C);
+	dw_dphy_if_write(dphy, DPHYGLUEIFTESTER, RESET);
+	dw_dphy_if_write(dphy, DPHYGLUEIFTESTER, RX_PHY);
+	dw_dphy_te_write(dphy, OSC_FREQ_TARGET_RX0_MSB, 0x03);
+	dw_dphy_te_write(dphy, OSC_FREQ_TARGET_RX0_LSB, 0x02);
+	dw_dphy_te_write(dphy, OSC_FREQ_TARGET_RX1_MSB, 0x03);
+	dw_dphy_te_write(dphy, OSC_FREQ_TARGET_RX1_LSB, 0x02);
+	dw_dphy_te_write(dphy, OSC_FREQ_TARGET_RX2_MSB, 0x03);
+	dw_dphy_te_write(dphy, OSC_FREQ_TARGET_RX2_LSB, 0x02);
+	dw_dphy_te_write(dphy, OSC_FREQ_TARGET_RX3_MSB, 0x03);
+	dw_dphy_te_write(dphy, OSC_FREQ_TARGET_RX3_LSB, 0x02);
+	dw_dphy_te_write(dphy, BANDGAP_CTRL, 0x80);
+
+	if (input_freq < 2000)
+		dw_dphy_te_write(dphy, HS_RX_CTRL_LANE0, 0xC0);
+
+	if (input_freq < 1000) {
+		dw_dphy_te_write(dphy, HS_RX_CTRL_LANE1, 0xC0);
+		dw_dphy_te_write(dphy, HS_RX_CTRL_LANE2, 0xC0);
+		dw_dphy_te_write(dphy, HS_RX_CTRL_LANE3, 0xC0);
+	}
+}
+
+int dw_dphy_g118_settle(struct dw_dphy_rx *dphy)
+{
+	u32 input_freq, total_settle, settle_time, byte_clk, lp_time;
+
+	lp_time = dphy->lp_time;
+	input_freq = dphy->dphy_freq / 1000;
+
+	settle_time = (8 * (1000000/(input_freq))) + 115000;
+	byte_clk = (8000000/(input_freq));
+	total_settle = (settle_time + lp_time * 1000) / byte_clk;
+
+	if (total_settle > 0xFF)
+		total_settle = 0xFF;
+
+	return total_settle;
+}
+
+static void dw_dphy_pwr_down(struct dw_dphy_rx *dphy)
+{
+	dw_dphy_write(dphy, R_CSI2_DPHY_RSTZ, 0);
+
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL0, 0, PHY_TESTCLK, 1);
+	if (dphy->lanes_config == CTRL_8_LANES)
+		dw_dphy_write_msk(dphy,
+			R_CSI2_DPHY2_TST_CTRL0, 0, PHY_TESTCLK, 1);
+
+	dw_dphy_write(dphy, R_CSI2_DPHY_SHUTDOWNZ, 0);
+}
+
+static void dw_dphy_pwr_up(struct dw_dphy_rx *dphy)
+{
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL0, 1, PHY_TESTCLK, 1);
+	if (dphy->lanes_config == CTRL_8_LANES)
+		dw_dphy_write_msk(dphy,
+			R_CSI2_DPHY2_TST_CTRL0, 1, PHY_TESTCLK, 1);
+
+	dw_dphy_write(dphy, R_CSI2_DPHY_SHUTDOWNZ, 1);
+	dw_dphy_write(dphy, R_CSI2_DPHY_RSTZ, 1);
+}
+
+static int dw_dphy_gen3_12bit_configure(struct dw_dphy_rx *dphy)
+{
+	u32 input_freq = dphy->dphy_freq;
+	u8 range = 0;
+
+	pr_debug("PHY GEN 3 Freq: %u\n", input_freq);
+	for (range = 0; (range < ARRAY_SIZE(range_gen3) - 1) &&
+		((input_freq / 1000) > range_gen3[range].freq); range++)
+		;
+
+	dw_dphy_gen3_12bit_tc_power_up(dphy);
+
+	dw_dphy_te_write(dphy, RX_SYS_1, range_gen3[range].hsfregrange);
+	dw_dphy_te_write(dphy, RX_SYS_0, 0x20);
+	dw_dphy_te_write(dphy, RX_RX_STARTUP_OVR_2,
+			(u8) range_gen3[range].osc_freq_target);
+	dw_dphy_te_write(dphy, RX_RX_STARTUP_OVR_3,
+			(u8) (range_gen3[range].osc_freq_target >> 8));
+	dw_dphy_te_write(dphy, RX_RX_STARTUP_OVR_4, 0x01);
+
+	if (dphy->compat_mode) {
+		dw_dphy_te_write(dphy, RX_RX_STARTUP_OVR_1, 0x01);
+		dw_dphy_te_write(dphy, RX_RX_STARTUP_OVR_0, 0x80);
+	}
+
+	if ((dphy->compat_mode) || (input_freq <= 1500))
+		dw_dphy_te_write(dphy, RX_SYS_7, 0x38);
+
+	return 0;
+}
+
+static int dw_dphy_gen3_8bit_configure(struct dw_dphy_rx *dphy)
+{
+	u32 input_freq = dphy->dphy_freq;
+	u8 data;
+	u8 range = 0;
+
+	pr_debug("PHY GEN 3 Freq: %u\n", input_freq);
+	for (range = 0; (range < ARRAY_SIZE(range_gen3) - 1) &&
+		((input_freq / 1000) > range_gen3[range].freq); range++)
+		;
+
+	dw_dphy_te_write(dphy, RX_SKEW_CAL, dw_dphy_g118_settle(dphy));
+	data = 1<<7 | range_gen3[range].hsfregrange;
+	dw_dphy_te_write(dphy, HSFREQRANGE_8BIT, data);
+	dw_dphy_gen3_8bit_tc_power_up(dphy);
+
+	return 0;
+}
+
+static int dw_dphy_gen2_configure(struct dw_dphy_rx *dphy)
+{
+	u32 input_freq = dphy->dphy_freq;
+	u8 data;
+	u8 range = 0;
+
+	/* provide an initial active-high test clear pulse in TESTCLR  */
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL0, 1, PHY_TESTCLR, 1);
+	dw_dphy_write_msk(dphy, R_CSI2_DPHY_TST_CTRL0, 0, PHY_TESTCLR, 1);
+
+	pr_debug("PHY GEN 2 Freq: %u\n", input_freq);
+	for (range = 0; (range < ARRAY_SIZE(range_gen2) - 1) &&
+		((input_freq / 1000) > range_gen2[range].freq); range++)
+		;
+
+	data = range_gen2[range].hsfregrange << 1;
+	dw_dphy_te_write(dphy, HSFREQRANGE_8BIT, data);
+
+	return 0;
+}
+
+static int dw_dphy_configure(struct dw_dphy_rx *dphy)
+{
+	dw_dphy_pwr_down(dphy);
+
+	if (dphy->dphy_gen == GEN3) {
+		dw_dphy_if_init(dphy);
+
+		if (dphy->dphy_te_len == BIT12)
+			dw_dphy_gen3_12bit_configure(dphy);
+		else
+			dw_dphy_gen3_8bit_configure(dphy);
+	} else
+		dw_dphy_gen2_configure(dphy);
+
+	dw_dphy_pwr_up(dphy);
+
+	return 0;
+}
+
+int dw_dphy_if_set_idelay(struct dw_dphy_rx *dphy, u8 dly, u8 cells)
+{
+	uint32_t val = 0;
+
+	dw_dphy_if_write(dphy, IDLYCFG, 0);
+
+	dw_dphy_if_write(dphy, IDLYSEL, cells);
+	dw_dphy_if_write(dphy, IDLYCNTINVAL, dly);
+
+	/* Pulse Value Set */
+	dw_dphy_if_write(dphy, IDLYCFG, 1);
+	usleep_range(10, 20);
+	dw_dphy_if_write(dphy, IDLYCFG, 0);
+
+	/* Pulse IDELAY CTRL Reset */
+	dw_dphy_if_write(dphy, DPHY1REGRSTN, 0);
+	usleep_range(10, 20);
+	dw_dphy_if_write(dphy, DPHY1REGRSTN, 1);
+
+	/* Get Value*/
+	val = dw_dphy_if_read(dphy, IDLYCNTOUTVAL);
+
+	if (val != dly) {
+		pr_info("odelay config failed, set %d get %d", dly, val);
+		return -1;
+	}
+
+	return 0;
+}
+
+int dw_dphy_if_get_idelay(struct dw_dphy_rx *dphy)
+{
+	return dw_dphy_if_read(dphy, IDLYCNTOUTVAL);
+}
+
+int dw_dphy_if_set_idelay_lane(struct dw_dphy_rx *dphy, u8 dly, u8 lane)
+{
+	int cell;
+
+	switch (lane) {
+	case 0:
+		for (cell = 3; cell <= 10; cell++)
+			dw_dphy_if_set_idelay(dphy, dly, cell);
+		break;
+	case 1:
+		for (cell = 14; cell <= 21; cell++)
+			dw_dphy_if_set_idelay(dphy, dly, cell);
+		break;
+	case 2:
+		for (cell = 24; cell <= 31; cell++)
+			dw_dphy_if_set_idelay(dphy, dly, cell);
+		break;
+	case 3:
+		for (cell = 34; cell <= 41; cell++)
+			dw_dphy_if_set_idelay(dphy, dly, cell);
+		break;
+	case 4: /* ALL */
+		dw_dphy_if_set_idelay(dphy, dly, 0x7F);
+		break;
+	default:
+		pr_err("Lane Value not recognized\n");
+		return -1;
+	}
+	return 0;
+}
+
+int dw_dphy_init(struct phy *phy)
+{
+	struct dw_dphy_rx *dphy = phy_get_drvdata(phy);
+
+	dw_dphy_write(dphy, R_CSI2_DPHY_RSTZ, 0);
+	dw_dphy_write(dphy, R_CSI2_DPHY_SHUTDOWNZ, 0);
+
+	return 0;
+}
+
+static int dw_dphy_set_phy_state(struct dw_dphy_rx *dphy, u32 on)
+{
+	u8 hs_freq;
+
+	dphy->lanes_config = dw_dphy_setup_config(dphy);
+
+	if (dphy->dphy_te_len == BIT12)
+		hs_freq = RX_SYS_1;
+	else
+		hs_freq = HSFREQRANGE_8BIT;
+
+	if (on) {
+		dw_dphy_configure(dphy);
+		pr_debug("HS Code: 0X%x\n", dw_dphy_te_read(dphy, hs_freq));
+	} else {
+		dw_dphy_write(dphy, R_CSI2_DPHY_SHUTDOWNZ, 0);
+		dw_dphy_write(dphy, R_CSI2_DPHY_RSTZ, 0);
+	}
+
+	return 0;
+}
+
+int dw_dphy_power_on(struct phy *phy)
+{
+	struct dw_dphy_rx *dphy = phy_get_drvdata(phy);
+
+	return dw_dphy_set_phy_state(dphy, 1);
+}
+
+int dw_dphy_power_off(struct phy *phy)
+{
+	struct dw_dphy_rx *dphy = phy_get_drvdata(phy);
+
+	return dw_dphy_set_phy_state(dphy, 0);
+}
+
+int dw_dphy_reset(struct phy *phy)
+{
+	struct dw_dphy_rx *dphy = phy_get_drvdata(phy);
+
+	dw_dphy_write(dphy, R_CSI2_DPHY_RSTZ, 0);
+	usleep_range(100, 200);
+	dw_dphy_write(dphy, R_CSI2_DPHY_RSTZ, 1);
+
+	return 0;
+}
diff --git a/drivers/media/platform/dwc/dw-dphy-rx.h b/drivers/media/platform/dwc/dw-dphy-rx.h
new file mode 100644
index 0000000..7ae4982
--- /dev/null
+++ b/drivers/media/platform/dwc/dw-dphy-rx.h
@@ -0,0 +1,176 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Synopsys MIPI D-PHY driver
+ *
+ * Copyright (c) 2018 Synopsys, Inc. and/or its affiliates.
+ * Author: Luis Oliveira <Luis.Oliveira@synopsys.com>
+ */
+
+#ifndef __PHY_SNPS_DPHY_RX_H__
+#define __PHY_SNPS_DPHY_RX_H__
+
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_gpio.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+
+/* DPHY interface register bank*/
+#define R_CSI2_DPHY_SHUTDOWNZ 0x0
+#define R_CSI2_DPHY_RSTZ 0x4
+#define R_CSI2_DPHY_RX 0x8
+#define	R_CSI2_DPHY_STOPSTATE 0xC
+#define R_CSI2_DPHY_TST_CTRL0 0x10
+#define R_CSI2_DPHY_TST_CTRL1 0x14
+#define R_CSI2_DPHY2_TST_CTRL0 0x18
+#define R_CSI2_DPHY2_TST_CTRL1 0x1C
+
+enum dphy_id_mask {
+	DPHY_ID_LANE_SUPPORT = 0,
+	DPHY_ID_IF = 4,
+	DPHY_ID_GEN = 8,
+};
+
+enum dphy_gen_values {
+	GEN1 = 0,
+	GEN2 = 1,
+	GEN3 = 2,
+};
+
+enum dphy_interface_length {
+	BIT8 = 8,
+	BIT12 = 12,
+};
+
+enum tst_ctrl0 {
+	PHY_TESTCLR = 0,
+	PHY_TESTCLK = 1,
+};
+
+enum tst_ctrl1 {
+	PHY_TESTDIN = 0,
+	PHY_TESTDOUT = 8,
+	PHY_TESTEN = 16,
+};
+
+enum lanes_config_values {
+	CTRL_4_LANES = 0,
+	CTRL_8_LANES = 1,
+};
+
+enum dphy_tc {
+	CFGCLKFREQRANGE_TX = 0x02,
+	CFGCLKFREQRANGE_RX = 0x05,
+	BYPASS = 0x20,
+	IO_DS = 0x30,
+};
+
+enum dphy_8bit_interface_addr {
+	BANDGAP_CTRL = 0x24,
+	HS_RX_CTRL_LANE0 = 0x42,
+	HSFREQRANGE_8BIT = 0x44,
+	OSC_FREQ_TARGET_RX0_LSB	= 0x4e,
+	OSC_FREQ_TARGET_RX0_MSB	= 0x4f,
+	HS_RX_CTRL_LANE1 = 0x52,
+	OSC_FREQ_TARGET_RX1_LSB	= 0x5e,
+	OSC_FREQ_TARGET_RX1_MSB	= 0x5f,
+	RX_SKEW_CAL	= 0x7e,
+	HS_RX_CTRL_LANE2 = 0x82,
+	OSC_FREQ_TARGET_RX2_LSB	= 0x8e,
+	OSC_FREQ_TARGET_RX2_MSB	= 0x8f,
+	HS_RX_CTRL_LANE3 = 0x92,
+	OSC_FREQ_TARGET_RX3_LSB	= 0x9e,
+	OSC_FREQ_TARGET_RX3_MSB	= 0x9f,
+};
+
+enum dphy_12bit_interface_addr {
+	RX_SYS_0 = 0x01,
+	RX_SYS_1 = 0x02,
+	RX_SYS_7 = 0x08,
+	RX_RX_STARTUP_OVR_0 = 0xe0,
+	RX_RX_STARTUP_OVR_1 = 0xe1,
+	RX_RX_STARTUP_OVR_2 = 0xe2,
+	RX_RX_STARTUP_OVR_3 = 0xe3,
+	RX_RX_STARTUP_OVR_4 = 0xe4,
+};
+
+/* Gen3 interface register bank*/
+#define IDLYCFG	0x00
+#define IDLYSEL	0x04
+#define IDLYCNTINVAL 0x08
+#define IDLYCNTOUTVAL 0x0c
+#define DPHY1REGRSTN 0x10
+#define DPHYZCALSTAT 0x14
+#define DPHYZCALCTRL 0x18
+#define DPHYLANE0STAT 0x1c
+#define DPHYLANE1STAT 0x20
+#define DPHYLANE2STAT 0x24
+#define DPHYLANE3STAT 0x28
+#define DPHYCLKSTAT 0x2c
+#define DPHYZCLKCTRL 0x30
+#define TCGENPURPOSOUT 0x34
+#define TCGENPURPOSIN 0x38
+#define DPHYGENERICOUT 0x3c
+#define DPHYGENERICIN 0x40
+#define DPHYGLUEIFTESTER 0x44
+#define DPHYID 0x100
+
+enum glueiftester {
+	GLUELOGIC = 0x4,
+	RX_PHY = 0x2,
+	TX_PHY = 0x1,
+	RESET = 0x0,
+};
+
+struct dw_dphy_rx {
+	spinlock_t slock;
+	struct phy *phy;
+	uint32_t dphy_freq;
+	uint32_t dphy_gen;
+	uint32_t dphy_te_len;
+	uint32_t lanes_config;
+	uint32_t max_lanes;
+	uint32_t compat_mode;
+	uint32_t lp_time;
+
+	void __iomem *base_address; /* test interface */
+	void __iomem *dphy1_if_addr; /* gluelogic phy 1 */
+	void __iomem *dphy2_if_addr; /* gluelogic phy 2 */
+
+	int config_gpio;
+	uint8_t setup_config;
+};
+
+int dw_dphy_init(struct phy *phy);
+int dw_dphy_reset(struct phy *phy);
+int dw_dphy_power_off(struct phy *phy);
+int dw_dphy_power_on(struct phy *phy);
+
+u8 dw_dphy_setup_config(struct dw_dphy_rx *dphy);
+u32 dw_dphy_if_read(struct dw_dphy_rx *dphy, u64 address);
+void dw_dphy_write(struct dw_dphy_rx *dphy, u32 address, u32 data);
+u32 dw_dphy_read(struct dw_dphy_rx *dphy, u64 address);
+int dw_dphy_te_read(struct dw_dphy_rx *dphy, u32 addr);
+int dw_dphy_if_get_idelay(struct dw_dphy_rx *dphy);
+int dw_dphy_if_set_idelay_lane(struct dw_dphy_rx *dphy, u8 dly, u8 lane);
+
+static inline
+u32 dw_dphy_if_read_msk(struct dw_dphy_rx *dphy,
+		u32 address, u8 shift, u8 width)
+{
+	return (dw_dphy_if_read(dphy, address) >> shift) & ((1 << width) - 1);
+}
+
+static inline
+u32 dw_dphy_read_msk(struct dw_dphy_rx *dev, u32 address, u8 shift,  u8 width)
+{
+	return (dw_dphy_read(dev, address) >> shift) & ((1 << width) - 1);
+}
+#endif /*__PHY_SNPS_DPHY_RX_H__*/
-- 
2.9.3


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 4/5] Documentation: dt-bindings: Document bindings for DW MIPI CSI-2 Host
  2018-09-14 22:48 [PATCH 0/5] platform: dwc: Add of DesignWare MIPI CSI-2 Host Luis Oliveira
                   ` (2 preceding siblings ...)
  2018-09-14 22:48 ` [PATCH 3/5] media: platform: dwc: Add DW MIPI DPHY core and platform Luis Oliveira
@ 2018-09-14 22:48 ` Luis Oliveira
  2018-09-14 22:48 ` [PATCH 5/5] media: platform: dwc: Add MIPI CSI-2 controller driver Luis Oliveira
  4 siblings, 0 replies; 10+ messages in thread
From: Luis Oliveira @ 2018-09-14 22:48 UTC (permalink / raw)
  To: linux-media, linux-kernel
  Cc: all-jpinto-org-pt02, Luis Oliveira, Luis Oliveira,
	Mauro Carvalho Chehab, Rob Herring, Mark Rutland, Hans Verkuil,
	Geert Uytterhoeven, Laurent Pinchart, Arnd Bergmann, Jacob Chen,
	Neil Armstrong, Keiichi Watanabe, Kate Stewart, Philipp Zabel,
	Todor Tomov, devicetree

Add bindings for Synopsys DesignWare MIPI CSI-2 host.

Signed-off-by: Luis Oliveira <lolivei@synopsys.com>
---
 .../devicetree/bindings/media/snps,dw-csi-plat.txt | 74 ++++++++++++++++++++++
 1 file changed, 74 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/media/snps,dw-csi-plat.txt

diff --git a/Documentation/devicetree/bindings/media/snps,dw-csi-plat.txt b/Documentation/devicetree/bindings/media/snps,dw-csi-plat.txt
new file mode 100644
index 0000000..0cc2915
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/snps,dw-csi-plat.txt
@@ -0,0 +1,74 @@
+Synopsys DesignWare CSI-2 Host controller
+
+Description
+-----------
+
+This HW block is used to receive image coming from an MIPI CSI-2 compatible
+camera.
+
+Required properties:
+- compatible: shall be "snps,dw-csi-plat"
+- reg			: physical base address and size of the device memory mapped
+  registers;
+- interrupts		: CSI-2 Host interrupt
+- snps,output-type	: Core output to be used (IPI-> 0 or IDI->1 or BOTH->2) These
+  			  values choose which of the Core outputs will be used, it
+			  can be Image Data Interface or Image Pixel Interface.
+- phys			: List of one PHY specifier (as defined in
+			  Documentation/devicetree/bindings/phy/phy-bindings.txt).
+			  This PHY is a MIPI DPHY working in RX mode.
+- resets		: Reference to a reset controller (optional)
+
+Optional properties(if in IPI mode):
+- snps,ipi-mode 	: Mode to be used when in IPI(Camera -> 0 or Controller -> 1)
+			  This property defines if the controller will use the video
+			  timings available
+			  in the video stream or if it will use pre-defined ones.
+- snps,ipi-color-mode	: Bus depth to be used in IPI (48 bits -> 0 or 16 bits -> 1)
+			  This property defines the width of the IPI bus.
+- snps,ipi-auto-flush	: Data auto-flush (1 -> Yes or 0 -> No). This property defines
+			  if the data is automatically flushed in each vsync or if
+			  this process is done manually
+- snps,virtual-channel	: Virtual channel where data is present when in IPI mode. This
+			  property chooses the virtual channel which IPI will use to
+			  retrieve the video stream.
+
+The per-board settings:
+ - port sub-node describing a single endpoint connected to the camera as
+   described in video-interfaces.txt[1].
+
+Example:
+
+	csi2_1: csi2@3000 {
+		compatible = "snps,dw-csi-plat";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = < 0x03000 0x7FF>;
+		interrupts = <2>;
+		output-type = <2>;
+		resets = <&dw_rst 1>;
+		phys = <&mipi_dphy_rx1 0>;
+		phy-names = "csi2-dphy";
+
+		/* IPI optional Configurations */
+		snps,ipi-mode = <0>;
+		snps,ipi-color-mode = <0>;
+		snps,ipi-auto-flush = <1>;
+		snps,virtual-channel = <0>;
+
+		/* CSI-2 per-board settings */
+		port@1 {
+			reg = <1>;
+			csi1_ep1: endpoint {
+				remote-endpoint = <&camera_1>;
+				data-lanes = <1 2>;
+			};
+		};
+		port@2 {
+			csi1_ep2: endpoint {
+				remote-endpoint = <&vif1_ep>;
+			};
+		};
+	};
+
+
-- 
2.9.3


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 5/5] media: platform: dwc: Add MIPI CSI-2 controller driver
  2018-09-14 22:48 [PATCH 0/5] platform: dwc: Add of DesignWare MIPI CSI-2 Host Luis Oliveira
                   ` (3 preceding siblings ...)
  2018-09-14 22:48 ` [PATCH 4/5] Documentation: dt-bindings: Document bindings for DW MIPI CSI-2 Host Luis Oliveira
@ 2018-09-14 22:48 ` Luis Oliveira
  2018-09-19 19:03   ` Fabio Estevam
  4 siblings, 1 reply; 10+ messages in thread
From: Luis Oliveira @ 2018-09-14 22:48 UTC (permalink / raw)
  To: linux-media, linux-kernel
  Cc: all-jpinto-org-pt02, Luis Oliveira, Mauro Carvalho Chehab,
	Luis Oliveira, David S. Miller, Greg Kroah-Hartman,
	Andrew Morton, Arnd Bergmann, Hans Verkuil, Laurent Pinchart,
	Geert Uytterhoeven, Jacob Chen, Neil Armstrong, Thierry Reding,
	Maxime Ripard, Philipp Zabel, Todor Tomov

Add the Synopsys MIPI CSI-2 controller driver. This
controller driver is divided in platform dependent functions
and core functions. It also includes a platform for future
DesignWare drivers.

Signed-off-by: Luis Oliveira <lolivei@synopsys.com>
---
 MAINTAINERS                              |  10 +
 drivers/media/platform/dwc/Kconfig       |  11 +
 drivers/media/platform/dwc/Makefile      |   2 +
 drivers/media/platform/dwc/dw-csi-plat.c | 508 +++++++++++++++++++++++++++++++
 drivers/media/platform/dwc/dw-csi-plat.h |  76 +++++
 drivers/media/platform/dwc/dw-mipi-csi.c | 491 +++++++++++++++++++++++++++++
 drivers/media/platform/dwc/dw-mipi-csi.h | 202 ++++++++++++
 include/media/dwc/dw-mipi-csi-pltfrm.h   | 101 ++++++
 8 files changed, 1401 insertions(+)
 create mode 100644 drivers/media/platform/dwc/dw-csi-plat.c
 create mode 100644 drivers/media/platform/dwc/dw-csi-plat.h
 create mode 100644 drivers/media/platform/dwc/dw-mipi-csi.c
 create mode 100644 drivers/media/platform/dwc/dw-mipi-csi.h
 create mode 100644 include/media/dwc/dw-mipi-csi-pltfrm.h

diff --git a/MAINTAINERS b/MAINTAINERS
index da2e509..dd540bc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14032,6 +14032,16 @@ S:	Maintained
 F:	drivers/dma/dwi-axi-dmac/
 F:	Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.txt
 
+SYNOPSYS DESIGNWARE MIPI CSI-2 HOST VIDEO PLATFORM
+M:	Luis Oliveira <luis.oliveira@synopsys.com>
+L:	linux-media@vger.kernel.org
+T:	git git://linuxtv.org/media_tree.git
+S:	Maintained
+F:	drivers/media/platform/dwc
+F:	include/media/dwc/dw-mipi-csi-pltfrm.h
+F:	Documentation/devicetree/bindings/media/snps,dw-csi-plat.txt
+F:	Documentation/devicetree/bindings/phy/snps,dphy-rx.txt
+
 SYNOPSYS DESIGNWARE DMAC DRIVER
 M:	Viresh Kumar <vireshk@kernel.org>
 R:	Andy Shevchenko <andriy.shevchenko@linux.intel.com>
diff --git a/drivers/media/platform/dwc/Kconfig b/drivers/media/platform/dwc/Kconfig
index 6d1a712..252d45f 100644
--- a/drivers/media/platform/dwc/Kconfig
+++ b/drivers/media/platform/dwc/Kconfig
@@ -19,6 +19,17 @@ config DWC_MIPI_CSI2_HOST
 
 if DWC_MIPI_CSI2_HOST
 
+config DWC_MIPI_CSI2_HOST_PLATFORM
+	tristate "Platform bus based CSI-2 Host Controller support"
+	depends on HAS_DMA
+	help
+	 This selects the CSI-2 host controller support. Select this if
+	 you have an CSI-2 Host controller on Platform bus.
+
+	 If you have a controller with this interface, say Y or M here.
+
+	  If unsure, say N.
+
 config DWC_MIPI_TC_DPHY_G128
 	tristate "DesignWare platform support using a G128 Test Chip"
 	depends on DWC_MIPI_CSI2_HOST
diff --git a/drivers/media/platform/dwc/Makefile b/drivers/media/platform/dwc/Makefile
index 8be6f68..e19cede 100644
--- a/drivers/media/platform/dwc/Makefile
+++ b/drivers/media/platform/dwc/Makefile
@@ -1,2 +1,4 @@
+obj-$(CONFIG_DWC_MIPI_CSI2_HOST_PLATFORM)	+= dw-csi-platfrm.o
+dw-csi-platfrm-objs		:= dw-csi-plat.o dw-mipi-csi.o
 obj-$(CONFIG_DWC_MIPI_TC_DPHY_G128)	+= dw-dphy-platfrm.o
 dw-dphy-platfrm-objs	:= dw-dphy-plat.o dw-dphy-rx.o
diff --git a/drivers/media/platform/dwc/dw-csi-plat.c b/drivers/media/platform/dwc/dw-csi-plat.c
new file mode 100644
index 0000000..c4ed8db
--- /dev/null
+++ b/drivers/media/platform/dwc/dw-csi-plat.c
@@ -0,0 +1,508 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * dw-csi-plat.c
+ *
+ * Copyright(c) 2018-present, Synopsys, Inc. and/or its affiliates.
+ * Luis Oliveira <Luis.Oliveira@synopsys.com>
+ *
+ */
+
+#include "dw-csi-plat.h"
+
+static const struct mipi_fmt *
+find_dw_mipi_csi_format(struct v4l2_mbus_framefmt *mf)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(dw_mipi_csi_formats); i++)
+		if (mf->code == dw_mipi_csi_formats[i].code)
+			return &dw_mipi_csi_formats[i];
+	return NULL;
+}
+
+static int dw_mipi_csi_enum_mbus_code(struct v4l2_subdev *sd,
+		struct v4l2_subdev_pad_config *cfg,
+		struct v4l2_subdev_mbus_code_enum *code)
+{
+	if (code->index >= ARRAY_SIZE(dw_mipi_csi_formats))
+		return -EINVAL;
+
+	code->code = dw_mipi_csi_formats[code->index].code;
+	return 0;
+}
+
+static struct mipi_fmt const *
+dw_mipi_csi_try_format(struct v4l2_mbus_framefmt *mf)
+{
+	struct mipi_fmt const *fmt;
+
+	fmt = find_dw_mipi_csi_format(mf);
+	if (fmt == NULL)
+		fmt = &dw_mipi_csi_formats[0];
+
+	mf->code = fmt->code;
+	return fmt;
+}
+
+static struct v4l2_mbus_framefmt *
+dw_mipi_csi_get_format(struct mipi_csi_dev *dev,
+		struct v4l2_subdev_pad_config *cfg,
+		enum v4l2_subdev_format_whence which)
+{
+	if (which == V4L2_SUBDEV_FORMAT_TRY)
+		return cfg ? v4l2_subdev_get_try_format(&dev->sd, cfg,
+							0) : NULL;
+
+	return &dev->format;
+}
+
+static int
+dw_mipi_csi_set_fmt(struct v4l2_subdev *sd,
+		struct v4l2_subdev_pad_config *cfg,
+		struct v4l2_subdev_format *fmt)
+{
+	struct mipi_csi_dev *dev = sd_to_mipi_csi_dev(sd);
+	struct mipi_fmt const *dev_fmt;
+	struct v4l2_mbus_framefmt *mf;
+	unsigned int i = 0;
+	const struct v4l2_bt_timings *bt_r = &v4l2_dv_timings_presets[0].bt;
+
+	mf = dw_mipi_csi_get_format(dev, cfg, fmt->which);
+
+	dev_fmt = dw_mipi_csi_try_format(&fmt->format);
+	if (dev_fmt) {
+		*mf = fmt->format;
+		if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+			dev->fmt = dev_fmt;
+		dw_mipi_csi_set_ipi_fmt(dev);
+	}
+	while (v4l2_dv_timings_presets[i].bt.width) {
+		const struct v4l2_bt_timings *bt =
+		    &v4l2_dv_timings_presets[i].bt;
+		if (mf->width == bt->width && mf->height == bt->width) {
+			dw_mipi_csi_fill_timings(dev, bt);
+			return 0;
+		}
+		i++;
+	}
+
+	dw_mipi_csi_fill_timings(dev, bt_r);
+	return 0;
+
+}
+
+static int
+dw_mipi_csi_get_fmt(struct v4l2_subdev *sd,
+		struct v4l2_subdev_pad_config *cfg,
+		struct v4l2_subdev_format *fmt)
+{
+	struct mipi_csi_dev *dev = sd_to_mipi_csi_dev(sd);
+	struct v4l2_mbus_framefmt *mf;
+
+	mf = dw_mipi_csi_get_format(dev, cfg, fmt->which);
+	if (!mf)
+		return -EINVAL;
+
+	mutex_lock(&dev->lock);
+	fmt->format = *mf;
+	mutex_unlock(&dev->lock);
+	return 0;
+}
+
+static int
+dw_mipi_csi_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct mipi_csi_dev *dev = sd_to_mipi_csi_dev(sd);
+
+	if (on) {
+		dw_mipi_csi_hw_stdby(dev);
+		dw_mipi_csi_start(dev);
+	} else {
+		phy_power_off(dev->phy);
+		dw_mipi_csi_mask_irq_power_off(dev);
+	}
+	return 0;
+}
+
+static int
+dw_mipi_csi_init_cfg(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg)
+{
+	struct v4l2_mbus_framefmt *format =
+	    v4l2_subdev_get_try_format(sd, cfg, 0);
+
+	format->colorspace = V4L2_COLORSPACE_SRGB;
+	format->code = dw_mipi_csi_formats[0].code;
+	format->width = MIN_WIDTH;
+	format->height = MIN_HEIGHT;
+	format->field = V4L2_FIELD_NONE;
+
+	return 0;
+}
+
+static struct v4l2_subdev_core_ops dw_mipi_csi_core_ops = {
+	.s_power = dw_mipi_csi_s_power,
+};
+
+static struct v4l2_subdev_pad_ops dw_mipi_csi_pad_ops = {
+	.init_cfg =	dw_mipi_csi_init_cfg,
+	.enum_mbus_code = dw_mipi_csi_enum_mbus_code,
+	.get_fmt = dw_mipi_csi_get_fmt,
+	.set_fmt = dw_mipi_csi_set_fmt,
+};
+
+static struct v4l2_subdev_ops dw_mipi_csi_subdev_ops = {
+	.core = &dw_mipi_csi_core_ops,
+	.pad = &dw_mipi_csi_pad_ops,
+};
+
+static irqreturn_t dw_mipi_csi_irq1(int irq, void *dev_id)
+{
+	struct mipi_csi_dev *csi_dev = dev_id;
+
+	dw_mipi_csi_irq_handler(csi_dev);
+
+	return IRQ_HANDLED;
+}
+
+static int
+dw_mipi_csi_parse_dt(struct platform_device *pdev, struct mipi_csi_dev *dev)
+{
+	struct device_node *node = pdev->dev.of_node;
+	struct v4l2_fwnode_endpoint endpoint;
+	int ret = 0;
+
+	ret = of_property_read_u32(node, "snps,output-type", &dev->hw.output);
+	if (ret) {
+		dev_err(&pdev->dev, "Couldn't read output-type\n");
+		return ret;
+	}
+
+	ret = of_property_read_u32(node, "snps,ipi-mode", &dev->hw.ipi_mode);
+	if (ret) {
+		dev_err(&pdev->dev, "Couldn't read ipi-mode\n");
+		return ret;
+	}
+
+	ret = of_property_read_u32(node, "snps,ipi-auto-flush",
+				 &dev->hw.ipi_auto_flush);
+	if (ret) {
+		dev_err(&pdev->dev, "Couldn't read ipi-auto-flush\n");
+		return ret;
+	}
+
+	ret = of_property_read_u32(node, "snps,ipi-color-mode",
+				 &dev->hw.ipi_color_mode);
+	if (ret) {
+		dev_err(&pdev->dev, "Couldn't read ipi-color-mode\n");
+		return ret;
+	}
+
+	ret = of_property_read_u32(node, "snps,virtual-channel",
+				&dev->hw.virtual_ch);
+	if (ret) {
+		dev_err(&pdev->dev, "Couldn't read virtual-channel\n");
+		return ret;
+	}
+
+	node = of_graph_get_next_endpoint(node, NULL);
+	if (!node) {
+		dev_err(&pdev->dev, "No port node at %s\n",
+				pdev->dev.of_node->full_name);
+		return -EINVAL;
+	}
+
+	ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(node), &endpoint);
+	if (ret)
+		goto err;
+
+	dev->index = endpoint.base.port - 1;
+	if (dev->index >= CSI_MAX_ENTITIES) {
+		ret = -ENXIO;
+		goto err;
+	}
+	dev->hw.num_lanes = endpoint.bus.mipi_csi2.num_data_lanes;
+
+err:
+	of_node_put(node);
+	return ret;
+}
+
+static ssize_t csih_version_show(struct device *dev,
+						struct device_attribute *attr,
+						char *buf)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+	struct mipi_csi_dev *csi_dev = sd_to_mipi_csi_dev(sd);
+
+	char buffer[10];
+
+	snprintf(buffer, 10, "v.%d.%d*\n", csi_dev->hw_version_major,
+					csi_dev->hw_version_minor);
+
+	return strlcpy(buf, buffer, PAGE_SIZE);
+}
+
+static ssize_t n_lanes_store(struct device *dev, struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	int ret;
+	unsigned long lanes;
+
+	struct platform_device *pdev = to_platform_device(dev);
+	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+	struct mipi_csi_dev *csi_dev = sd_to_mipi_csi_dev(sd);
+
+	ret = kstrtoul(buf, 10, &lanes);
+	if (ret < 0)
+		return ret;
+
+	if (lanes > 8) {
+		dev_err(dev, "Invalid number of lanes %lu\n", lanes);
+		return count;
+	}
+
+	dev_info(dev, "Lanes %lu\n", lanes);
+	csi_dev->hw.num_lanes = lanes;
+
+	return count;
+}
+static ssize_t n_lanes_show(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+	struct mipi_csi_dev *csi_dev = sd_to_mipi_csi_dev(sd);
+
+	char buffer[10];
+
+	snprintf(buffer, 10, "Lanes %d\n", csi_dev->hw.num_lanes);
+
+	return strlcpy(buf, buffer, PAGE_SIZE);
+}
+
+static ssize_t csih_reset_show(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+	struct mipi_csi_dev *csi_dev = sd_to_mipi_csi_dev(sd);
+
+	char buffer[10];
+
+	/* Reset Controller and DPHY */
+	phy_reset(csi_dev->phy);
+	dw_mipi_csi_reset(csi_dev);
+
+	snprintf(buffer, 10, "Reset\n");
+
+	return strlcpy(buf, buffer, PAGE_SIZE);
+}
+
+static ssize_t dt_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	int ret;
+	unsigned long dt;
+
+	struct platform_device *pdev = to_platform_device(dev);
+	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+	struct mipi_csi_dev *csi_dev = sd_to_mipi_csi_dev(sd);
+
+	ret = kstrtoul(buf, 16, &dt);
+	if (ret < 0)
+		return ret;
+
+	if ((dt < 0x18) || (dt > 0x2F)) {
+		dev_err(dev, "Invalid data type %lx\n", dt);
+		return count;
+	}
+
+	dev_info(dev, "Data type %lx\n", dt);
+	csi_dev->ipi_dt = dt;
+
+	return count;
+}
+
+static ssize_t dt_show(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+	struct mipi_csi_dev *csi_dev = sd_to_mipi_csi_dev(sd);
+
+	char buffer[10];
+
+	snprintf(buffer, 10, "DT %x\n", csi_dev->ipi_dt);
+
+	return strlcpy(buf, buffer, PAGE_SIZE);
+}
+
+static DEVICE_ATTR_RO(csih_version);
+static DEVICE_ATTR_RO(csih_reset);
+static DEVICE_ATTR_RW(n_lanes);
+static DEVICE_ATTR_RW(dt);
+
+static const struct of_device_id dw_mipi_csi_of_match[];
+
+static int csi_plat_probe(struct platform_device *pdev)
+{
+	const struct of_device_id *of_id;
+	struct device *dev = &pdev->dev;
+	struct resource *res = NULL;
+	struct mipi_csi_dev *mipi_csi;
+	int ret = -ENOMEM;
+
+	mipi_csi = devm_kzalloc(dev, sizeof(*mipi_csi), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+
+	mutex_init(&mipi_csi->lock);
+	spin_lock_init(&mipi_csi->slock);
+	mipi_csi->dev = dev;
+
+	of_id = of_match_node(dw_mipi_csi_of_match, dev->of_node);
+	if (WARN_ON(of_id == NULL))
+		return -EINVAL;
+
+	ret = dw_mipi_csi_parse_dt(pdev, mipi_csi);
+	if (ret < 0)
+		return ret;
+
+	mipi_csi->phy = devm_of_phy_get(dev, dev->of_node, NULL);
+	if (IS_ERR(mipi_csi->phy)) {
+		dev_err(dev, "No DPHY available\n");
+		return PTR_ERR(mipi_csi->phy);
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	mipi_csi->base_address = devm_ioremap_resource(dev, res);
+
+	if (IS_ERR(mipi_csi->base_address)) {
+		dev_err(dev, "Base address not set.\n");
+		return PTR_ERR(mipi_csi->base_address);
+	}
+
+	mipi_csi->ctrl_irq_number = platform_get_irq(pdev, 0);
+	if (mipi_csi->ctrl_irq_number <= 0) {
+		dev_err(dev, "IRQ number not set.\n");
+		return mipi_csi->ctrl_irq_number;
+	}
+
+	mipi_csi->rst = devm_reset_control_get_optional_shared(dev, NULL);
+	if (IS_ERR(mipi_csi->rst)) {
+		ret = PTR_ERR(mipi_csi->rst);
+		dev_err(dev, "error getting reset control %d\n", ret);
+		return ret;
+	}
+
+	ret = devm_request_irq(dev, mipi_csi->ctrl_irq_number,
+			       dw_mipi_csi_irq1, IRQF_SHARED,
+			       dev_name(dev), mipi_csi);
+	if (ret) {
+		dev_err(dev, "IRQ failed\n");
+		goto end;
+	}
+
+	v4l2_subdev_init(&mipi_csi->sd, &dw_mipi_csi_subdev_ops);
+	mipi_csi->sd.owner = THIS_MODULE;
+	snprintf(mipi_csi->sd.name, sizeof(mipi_csi->sd.name), "%s.%d",
+		 CSI_HOST_NAME, mipi_csi->index);
+	mipi_csi->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	mipi_csi->fmt = &dw_mipi_csi_formats[0];
+
+	mipi_csi->format.code = dw_mipi_csi_formats[0].code;
+	mipi_csi->format.width = MIN_WIDTH;
+	mipi_csi->format.height = MIN_HEIGHT;
+
+	mipi_csi->sd.entity.function = MEDIA_ENT_F_IO_V4L;
+	mipi_csi->pads[CSI_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+	mipi_csi->pads[CSI_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+	ret = media_entity_pads_init(&mipi_csi->sd.entity,
+				     CSI_PADS_NUM, mipi_csi->pads);
+
+	if (ret < 0) {
+		dev_err(dev, "Media Entity init failed\n");
+		goto entity_cleanup;
+	}
+
+	v4l2_set_subdevdata(&mipi_csi->sd, pdev);
+
+	platform_set_drvdata(pdev, &mipi_csi->sd);
+
+	device_create_file(&pdev->dev, &dev_attr_csih_version);
+	device_create_file(&pdev->dev, &dev_attr_csih_reset);
+	device_create_file(&pdev->dev, &dev_attr_n_lanes);
+	device_create_file(&pdev->dev, &dev_attr_dt);
+
+	if (mipi_csi->rst)
+		reset_control_deassert(mipi_csi->rst);
+
+	dw_mipi_csi_get_version(mipi_csi);
+	dw_mipi_csi_specific_mappings(mipi_csi);
+	dw_mipi_csi_mask_irq_power_off(mipi_csi);
+
+	dev_info(dev, "DW MIPI CSI-2 Host registered successfully HW v%u.%u\n",
+		mipi_csi->hw_version_major, mipi_csi->hw_version_minor);
+	return 0;
+
+entity_cleanup:
+	media_entity_cleanup(&mipi_csi->sd.entity);
+end:
+	return ret;
+}
+
+/**
+ * @short Exit routine - Exit point of the driver
+ * @param[in] pdev pointer to the platform device structure
+ * @return 0 on success and a negative number on failure
+ * Refer to Linux errors.
+ */
+static int csi_plat_remove(struct platform_device *pdev)
+{
+	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+	struct mipi_csi_dev *mipi_csi = sd_to_mipi_csi_dev(sd);
+
+	dev_dbg(&pdev->dev, "Removing MIPI CSI-2 module\n");
+
+	if (mipi_csi->rst)
+		reset_control_assert(mipi_csi->rst);
+
+	media_entity_cleanup(&mipi_csi->sd.entity);
+
+	return 0;
+}
+
+/**
+ * @short of_device_id structure
+ */
+static const struct of_device_id dw_mipi_csi_of_match[] = {
+	{
+	 .compatible = "snps,dw-csi-plat"},
+	{ /* sentinel */ },
+};
+
+MODULE_DEVICE_TABLE(of, dw_mipi_csi_of_match);
+
+/**
+ * @short Platform driver structure
+ */
+static struct platform_driver __refdata dw_mipi_csi_pdrv = {
+	.remove = csi_plat_remove,
+	.probe = csi_plat_probe,
+	.driver = {
+		   .name = CSI_HOST_NAME,
+		   .owner = THIS_MODULE,
+		   .of_match_table = dw_mipi_csi_of_match,
+		   },
+};
+
+module_platform_driver(dw_mipi_csi_pdrv);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Luis Oliveira <lolivei@synopsys.com>");
+MODULE_DESCRIPTION("Synopsys DesignWare MIPI CSI-2 Host Platform driver");
diff --git a/drivers/media/platform/dwc/dw-csi-plat.h b/drivers/media/platform/dwc/dw-csi-plat.h
new file mode 100644
index 0000000..713f40f
--- /dev/null
+++ b/drivers/media/platform/dwc/dw-csi-plat.h
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * dw-csi-plat.h
+ *
+ * Copyright(c) 2018-present, Synopsys, Inc. and/or its affiliates.
+ * Luis Oliveira <Luis.Oliveira@synopsys.com>
+ *
+ */
+
+#ifndef _DW_CSI_PLAT_H__
+#define _DW_CSI_PLAT_H__
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/ratelimit.h>
+#include <linux/reset.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <linux/wait.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-dv-timings.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-subdev.h>
+
+#include "dw-mipi-csi.h"
+
+#define CSI_HOST_NAME	"dw-mipi-csi"
+
+/* Video formats supported by the MIPI CSI-2 */
+const struct mipi_fmt dw_mipi_csi_formats[] = {
+	{
+		/* RAW 8 */
+		.code = MEDIA_BUS_FMT_SBGGR8_1X8,
+		.depth = 8,
+	},
+	{
+		/* RAW 10 */
+		.code = MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE,
+		.depth = 10,
+	},
+	{
+		/* RGB 565 */
+		.code = MEDIA_BUS_FMT_RGB565_2X8_BE,
+		.depth = 16,
+	},
+	{
+		/* BGR 565 */
+		.code = MEDIA_BUS_FMT_RGB565_2X8_LE,
+		.depth = 16,
+	},
+	{
+		/* RGB 888 */
+		.code = MEDIA_BUS_FMT_RGB888_2X12_LE,
+		.depth = 24,
+	},
+	{
+		/* BGR 888 */
+		.code = MEDIA_BUS_FMT_RGB888_2X12_BE,
+		.depth = 24,
+	},
+};
+
+static inline struct mipi_csi_dev *sd_to_mipi_csi_dev(struct v4l2_subdev *sdev)
+{
+	return container_of(sdev, struct mipi_csi_dev, sd);
+}
+
+#endif	/* _DW_CSI_PLAT_H__ */
diff --git a/drivers/media/platform/dwc/dw-mipi-csi.c b/drivers/media/platform/dwc/dw-mipi-csi.c
new file mode 100644
index 0000000..926b287
--- /dev/null
+++ b/drivers/media/platform/dwc/dw-mipi-csi.c
@@ -0,0 +1,491 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * dw-mipi-csi.c
+ *
+ * Copyright(c) 2018-present, Synopsys, Inc. and/or its affiliates.
+ * Luis Oliveira <Luis.Oliveira@synopsys.com>
+ *
+ */
+
+#include "dw-mipi-csi.h"
+
+static struct R_CSI2 reg = {
+	.VERSION = 0x00,
+	.N_LANES = 0x04,
+	.CTRL_RESETN = 0x08,
+	.INTERRUPT = 0x0C,
+	.DATA_IDS_1	= 0x10,
+	.DATA_IDS_2	= 0x14,
+	.IPI_MODE = 0x80,
+	.IPI_VCID = 0x84,
+	.IPI_DATA_TYPE = 0x88,
+	.IPI_MEM_FLUSH = 0x8C,
+	.IPI_HSA_TIME = 0x90,
+	.IPI_HBP_TIME = 0x94,
+	.IPI_HSD_TIME = 0x98,
+	.IPI_HLINE_TIME = 0x9C,
+	.IPI_SOFTRSTN = 0xA0,
+	.IPI_ADV_FEATURES = 0xAC,
+	.IPI_VSA_LINES = 0xB0,
+	.IPI_VBP_LINES = 0xB4,
+	.IPI_VFP_LINES = 0xB8,
+	.IPI_VACTIVE_LINES = 0xBC,
+	.INT_PHY_FATAL = 0xe0,
+	.MASK_INT_PHY_FATAL = 0xe4,
+	.FORCE_INT_PHY_FATAL = 0xe8,
+	.INT_PKT_FATAL = 0xf0,
+	.MASK_INT_PKT_FATAL = 0xf4,
+	.FORCE_INT_PKT_FATAL = 0xf8,
+	.INT_PHY = 0x110,
+	.MASK_INT_PHY = 0x114,
+	.FORCE_INT_PHY = 0x118,
+	.INT_LINE = 0x130,
+	.MASK_INT_LINE = 0x134,
+	.FORCE_INT_LINE = 0x138,
+	.INT_IPI = 0x140,
+	.MASK_INT_IPI = 0x144,
+	.FORCE_INT_IPI = 0x148,
+};
+struct interrupt_type csi_int = {
+	.PHY_FATAL = BIT(0),
+	.PKT_FATAL = BIT(1),
+	.PHY = BIT(16),
+};
+static void dw_mipi_csi_write(struct mipi_csi_dev *dev,
+		  unsigned int address, unsigned int data)
+{
+	iowrite32(data, dev->base_address + address);
+}
+
+static u32 dw_mipi_csi_read(struct mipi_csi_dev *dev, unsigned long address)
+{
+	return ioread32(dev->base_address + address);
+}
+
+void dw_mipi_csi_write_part(struct mipi_csi_dev *dev,
+		       unsigned long address, unsigned long data,
+		       unsigned char shift, unsigned char width)
+{
+	u32 mask = (1 << width) - 1;
+	u32 temp = dw_mipi_csi_read(dev, address);
+
+	temp &= ~(mask << shift);
+	temp |= (data & mask) << shift;
+	dw_mipi_csi_write(dev, address, temp);
+}
+
+void dw_mipi_csi_reset(struct mipi_csi_dev *csi_dev)
+{
+	dw_mipi_csi_write(csi_dev, reg.CTRL_RESETN, 0);
+	usleep_range(100, 200);
+	dw_mipi_csi_write(csi_dev, reg.CTRL_RESETN, 1);
+}
+
+int dw_mipi_csi_mask_irq_power_off(struct mipi_csi_dev *csi_dev)
+{
+	if ((csi_dev->hw_version_major) == 1) {
+
+		/* set only one lane (lane 0) as active (ON) */
+		dw_mipi_csi_write(csi_dev, reg.N_LANES, 0);
+		dw_mipi_csi_write(csi_dev, reg.MASK_INT_PHY_FATAL, 0);
+		dw_mipi_csi_write(csi_dev, reg.MASK_INT_PKT_FATAL, 0);
+		dw_mipi_csi_write(csi_dev, reg.MASK_INT_PHY, 0);
+		dw_mipi_csi_write(csi_dev, reg.MASK_INT_PKT, 0);
+		dw_mipi_csi_write(csi_dev, reg.MASK_INT_LINE, 0);
+		dw_mipi_csi_write(csi_dev, reg.MASK_INT_IPI, 0);
+
+		/* only for version 1.30 */
+		if ((csi_dev->hw_version_minor) == 30)
+			dw_mipi_csi_write(csi_dev, reg.MASK_INT_FRAME_FATAL, 0);
+
+		dw_mipi_csi_write(csi_dev, reg.CTRL_RESETN, 0);
+
+		/* only for version 1.40 */
+		if ((csi_dev->hw_version_minor) == 40) {
+			dw_mipi_csi_write(csi_dev,
+					reg.MSK_BNDRY_FRAME_FATAL, 0);
+			dw_mipi_csi_write(csi_dev, reg.MSK_SEQ_FRAME_FATAL, 0);
+			dw_mipi_csi_write(csi_dev, reg.MSK_CRC_FRAME_FATAL, 0);
+			dw_mipi_csi_write(csi_dev, reg.MSK_PLD_CRC_FATAL, 0);
+			dw_mipi_csi_write(csi_dev, reg.MSK_DATA_ID, 0);
+			dw_mipi_csi_write(csi_dev, reg.MSK_ECC_CORRECT, 0);
+		}
+	}
+
+	return 0;
+}
+
+int dw_mipi_csi_hw_stdby(struct mipi_csi_dev *csi_dev)
+{
+	if ((csi_dev->hw_version_major) == 1) {
+
+		/* set only one lane (lane 0) as active (ON) */
+		dw_mipi_csi_reset(csi_dev);
+		dw_mipi_csi_write(csi_dev, reg.N_LANES, 0);
+		phy_init(csi_dev->phy);
+
+		/* only for version 1.30 */
+		if ((csi_dev->hw_version_minor) == 30)
+			dw_mipi_csi_write(csi_dev,
+					reg.MASK_INT_FRAME_FATAL, 0xFFFFFFFF);
+
+		/* common */
+		dw_mipi_csi_write(csi_dev, reg.MASK_INT_PHY_FATAL, 0xFFFFFFFF);
+		dw_mipi_csi_write(csi_dev, reg.MASK_INT_PKT_FATAL, 0xFFFFFFFF);
+		dw_mipi_csi_write(csi_dev, reg.MASK_INT_PHY, 0xFFFFFFFF);
+		dw_mipi_csi_write(csi_dev, reg.MASK_INT_PKT, 0xFFFFFFFF);
+		dw_mipi_csi_write(csi_dev, reg.MASK_INT_LINE, 0xFFFFFFFF);
+		dw_mipi_csi_write(csi_dev, reg.MASK_INT_IPI, 0xFFFFFFFF);
+
+		/* only for version 1.40 */
+		if ((csi_dev->hw_version_minor) == 40) {
+			dw_mipi_csi_write(csi_dev,
+					reg.MSK_BNDRY_FRAME_FATAL, 0xFFFFFFFF);
+			dw_mipi_csi_write(csi_dev,
+					reg.MSK_SEQ_FRAME_FATAL, 0xFFFFFFFF);
+			dw_mipi_csi_write(csi_dev,
+					reg.MSK_CRC_FRAME_FATAL, 0xFFFFFFFF);
+			dw_mipi_csi_write(csi_dev,
+					reg.MSK_PLD_CRC_FATAL, 0xFFFFFFFF);
+			dw_mipi_csi_write(csi_dev, reg.MSK_DATA_ID, 0xFFFFFFFF);
+			dw_mipi_csi_write(csi_dev,
+					reg.MSK_ECC_CORRECT, 0xFFFFFFFF);
+		}
+	}
+	return 0;
+}
+
+void dw_mipi_csi_set_ipi_fmt(struct mipi_csi_dev *csi_dev)
+{
+	struct device *dev = csi_dev->dev;
+
+	if (csi_dev->ipi_dt)
+		dw_mipi_csi_write(csi_dev, reg.IPI_DATA_TYPE, csi_dev->ipi_dt);
+	else {
+		switch (csi_dev->fmt->code) {
+		case MEDIA_BUS_FMT_RGB565_2X8_BE:
+		case MEDIA_BUS_FMT_RGB565_2X8_LE:
+			dw_mipi_csi_write(csi_dev,
+					reg.IPI_DATA_TYPE, CSI_2_RGB565);
+			dev_dbg(dev, "DT: RGB 565");
+			break;
+
+		case MEDIA_BUS_FMT_RGB888_2X12_LE:
+		case MEDIA_BUS_FMT_RGB888_2X12_BE:
+			dw_mipi_csi_write(csi_dev,
+					reg.IPI_DATA_TYPE, CSI_2_RGB888);
+			dev_dbg(dev, "DT: RGB 888");
+			break;
+		case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE:
+			dw_mipi_csi_write(csi_dev,
+					reg.IPI_DATA_TYPE, CSI_2_RAW10);
+			dev_dbg(dev, "DT: RAW 10");
+			break;
+		case MEDIA_BUS_FMT_SBGGR8_1X8:
+			dw_mipi_csi_write(csi_dev,
+					reg.IPI_DATA_TYPE, CSI_2_RAW8);
+			dev_dbg(dev, "DT: RAW 8");
+			break;
+		default:
+			dw_mipi_csi_write(csi_dev,
+					reg.IPI_DATA_TYPE, CSI_2_RGB565);
+			dev_dbg(dev, "Error");
+			break;
+		}
+	}
+}
+
+void dw_mipi_csi_fill_timings(struct mipi_csi_dev *dev,
+			   const struct v4l2_bt_timings *bt)
+{
+
+	if (bt == NULL)
+		return;
+
+	dev->hw.hsa = bt->hsync;
+	dev->hw.hbp = bt->hbackporch;
+	dev->hw.hsd = bt->hsync;
+	dev->hw.htotal = bt->height + bt->vfrontporch +
+	    bt->vsync + bt->vbackporch;
+	dev->hw.vsa = bt->vsync;
+	dev->hw.vbp = bt->vbackporch;
+	dev->hw.vfp = bt->vfrontporch;
+	dev->hw.vactive = bt->height;
+}
+
+void dw_mipi_csi_start(struct mipi_csi_dev *csi_dev)
+{
+	const struct v4l2_bt_timings *bt = &v4l2_dv_timings_presets[0].bt;
+	struct device *dev = csi_dev->dev;
+
+	dw_mipi_csi_fill_timings(csi_dev, bt);
+	dw_mipi_csi_write(csi_dev, reg.N_LANES, (csi_dev->hw.num_lanes - 1));
+	dev_dbg(dev, "N Lanes: %d\n", csi_dev->hw.num_lanes);
+
+	/* IPI Related Configuration */
+	if ((csi_dev->hw.output == IPI_OUT)
+		|| (csi_dev->hw.output == BOTH_OUT)) {
+
+		if (csi_dev->hw_version_major >= 1) {
+			if (csi_dev->hw_version_minor >= 20)
+				dw_mipi_csi_write(csi_dev,
+					reg.IPI_ADV_FEATURES, 0x30000);
+
+			if (csi_dev->hw_version_minor >= 30)
+				dw_mipi_csi_write(csi_dev,
+					reg.IPI_SOFTRSTN, 0x1);
+		}
+		/*  address | data, | shift | width */
+		dw_mipi_csi_write_part(csi_dev, reg.IPI_MODE, 1, 24, 1);
+		dw_mipi_csi_write_part(csi_dev,
+					reg.IPI_MODE,
+					csi_dev->hw.ipi_mode,
+					0, 1);
+
+		dw_mipi_csi_write_part(csi_dev,
+					reg.IPI_MODE,
+					csi_dev->hw.ipi_color_mode,
+					8, 1);
+
+		dw_mipi_csi_write_part(csi_dev,
+					reg.IPI_VCID,
+					csi_dev->hw.virtual_ch,
+					0, 2);
+
+		dw_mipi_csi_write_part(csi_dev,
+					reg.IPI_MEM_FLUSH,
+					csi_dev->hw.ipi_auto_flush,
+					8, 1);
+
+		dw_mipi_csi_write(csi_dev,
+					reg.IPI_HSA_TIME, csi_dev->hw.hsa);
+
+		dw_mipi_csi_write(csi_dev,
+					reg.IPI_HBP_TIME, csi_dev->hw.hbp);
+
+		dw_mipi_csi_write(csi_dev,
+					reg.IPI_HSD_TIME, csi_dev->hw.hsd);
+
+		dev_dbg(dev, "IPI enable\n");
+		dev_dbg(dev, "IPI MODE: %d\n", csi_dev->hw.ipi_mode);
+		dev_dbg(dev, "Color Mode: %d\n", csi_dev->hw.ipi_color_mode);
+		dev_dbg(dev, "Virtual Channel: %d\n", csi_dev->hw.virtual_ch);
+		dev_dbg(dev, "Auto-flush: %d\n", csi_dev->hw.ipi_auto_flush);
+		dev_dbg(dev, "HSA: %d\n", csi_dev->hw.hsa);
+		dev_dbg(dev, "HBP: %d\n", csi_dev->hw.hbp);
+		dev_dbg(dev, "HSD: %d\n", csi_dev->hw.hsd);
+
+		if (csi_dev->hw.ipi_mode == AUTO_TIMING) {
+			dw_mipi_csi_write(csi_dev,
+				reg.IPI_HLINE_TIME, csi_dev->hw.htotal);
+			dw_mipi_csi_write(csi_dev,
+				reg.IPI_VSA_LINES, csi_dev->hw.vsa);
+			dw_mipi_csi_write(csi_dev,
+				reg.IPI_VBP_LINES, csi_dev->hw.vbp);
+			dw_mipi_csi_write(csi_dev,
+				reg.IPI_VFP_LINES, csi_dev->hw.vfp);
+			dw_mipi_csi_write(csi_dev,
+				reg.IPI_VACTIVE_LINES, csi_dev->hw.vactive);
+			dev_dbg(dev,
+				"Horizontal Total: %d\n", csi_dev->hw.htotal);
+			dev_dbg(dev,
+				"Vertical Sync Active: %d\n", csi_dev->hw.vsa);
+			dev_dbg(dev,
+				"Vertical Back Porch: %d\n", csi_dev->hw.vbp);
+			dev_dbg(dev,
+				"Vertical Front Porch: %d\n", csi_dev->hw.vfp);
+			dev_dbg(dev,
+				"Vertical Active: %d\n", csi_dev->hw.vactive);
+		}
+	}
+	phy_power_on(csi_dev->phy);
+}
+
+int dw_mipi_csi_irq_handler(struct mipi_csi_dev *csi_dev)
+{
+	struct device *dev = csi_dev->dev;
+	u32 global_int_status, i_sts;
+	unsigned long flags;
+
+	global_int_status = dw_mipi_csi_read(csi_dev, reg.INTERRUPT);
+	spin_lock_irqsave(&csi_dev->slock, flags);
+
+	if (global_int_status & csi_int.PHY_FATAL) {
+		i_sts = dw_mipi_csi_read(csi_dev, reg.INT_PHY_FATAL);
+		dev_err_ratelimited(dev,
+			"interrupt %08X: PHY FATAL: %08X\n",
+			reg.INT_PHY_FATAL, i_sts);
+	}
+
+	if (global_int_status & csi_int.PKT_FATAL) {
+		i_sts = dw_mipi_csi_read(csi_dev, reg.INT_PKT_FATAL);
+		dev_err_ratelimited(dev,
+			"interrupt %08X: PKT FATAL: %08X\n",
+			reg.INT_PKT_FATAL, i_sts);
+	}
+
+	if ((global_int_status & csi_int.FRAME_FATAL)
+	&& ((csi_dev->hw_version_major) == 1)
+	&& ((csi_dev->hw_version_minor) == 30)) {
+		i_sts = dw_mipi_csi_read(csi_dev, reg.INT_FRAME_FATAL);
+			dev_err_ratelimited(dev,
+			"interrupt %08X: FRAME FATAL: %08X\n",
+			reg.INT_FRAME_FATAL, i_sts);
+	}
+
+	if (global_int_status & csi_int.PHY) {
+		i_sts = dw_mipi_csi_read(csi_dev, reg.INT_PHY);
+		dev_err_ratelimited(dev,
+			"interrupt %08X: PHY: %08X\n",
+			reg.INT_PHY, i_sts);
+	}
+
+	if (global_int_status & csi_int.PKT) {
+		i_sts = dw_mipi_csi_read(csi_dev, reg.INT_PKT);
+		dev_err_ratelimited(dev,
+			"interrupt %08X: PKT: %08X\n",
+			reg.INT_PKT, i_sts);
+	}
+
+	if (global_int_status & csi_int.LINE) {
+		i_sts = dw_mipi_csi_read(csi_dev, reg.INT_LINE);
+		dev_err_ratelimited(dev,
+			"interrupt %08X: LINE: %08X\n",
+			reg.INT_LINE, i_sts);
+	}
+
+	if (global_int_status & csi_int.IPI) {
+		i_sts = dw_mipi_csi_read(csi_dev, reg.INT_IPI);
+		dev_err_ratelimited(dev,
+			"interrupt %08X: IPI: %08X\n",
+			reg.INT_IPI, i_sts);
+	}
+
+	if (global_int_status & csi_int.BNDRY_FRAME_FATAL) {
+		i_sts = dw_mipi_csi_read(csi_dev, reg.ST_BNDRY_FRAME_FATAL);
+		dev_err_ratelimited(dev,
+			"interrupt %08X: ST_BNDRY_FRAME_FATAL: %08X\n",
+			reg.ST_BNDRY_FRAME_FATAL, i_sts);
+	}
+
+	if (global_int_status & csi_int.SEQ_FRAME_FATAL) {
+		i_sts = dw_mipi_csi_read(csi_dev, reg.ST_SEQ_FRAME_FATAL);
+		dev_err_ratelimited(dev,
+			"interrupt %08X: ST_SEQ_FRAME_FATAL: %08X\n",
+			reg.ST_SEQ_FRAME_FATAL, i_sts);
+	}
+
+	if (global_int_status & csi_int.CRC_FRAME_FATAL) {
+		i_sts = dw_mipi_csi_read(csi_dev, reg.ST_CRC_FRAME_FATAL);
+		dev_err_ratelimited(dev,
+			"interrupt %08X: ST_CRC_FRAME_FATAL: %08X\n",
+			reg.ST_CRC_FRAME_FATAL, i_sts);
+	}
+
+	if (global_int_status & csi_int.PLD_CRC_FATAL) {
+		i_sts = dw_mipi_csi_read(csi_dev, reg.ST_PLD_CRC_FATAL);
+		dev_err_ratelimited(dev,
+			"interrupt %08X: ST_PLD_CRC_FATAL: %08X\n",
+			reg.ST_PLD_CRC_FATAL, i_sts);
+	}
+
+	if (global_int_status & csi_int.DATA_ID) {
+		i_sts = dw_mipi_csi_read(csi_dev, reg.ST_DATA_ID);
+		dev_err_ratelimited(dev,
+			"interrupt %08X: ST_DATA_ID: %08X\n",
+			reg.ST_DATA_ID, i_sts);
+	}
+
+	if (global_int_status & csi_int.ECC_CORRECTED) {
+		i_sts = dw_mipi_csi_read(csi_dev, reg.ST_ECC_CORRECT);
+		dev_err_ratelimited(dev,
+			"interrupt %08X: ST_ECC_CORRECT: %08X\n",
+			reg.ST_ECC_CORRECT, i_sts);
+	}
+
+	spin_unlock_irqrestore(&csi_dev->slock, flags);
+
+	return 1;
+}
+
+void dw_mipi_csi_get_version(struct mipi_csi_dev *csi_dev)
+{
+	uint32_t hw_version;
+
+	hw_version = dw_mipi_csi_read(csi_dev, reg.VERSION);
+	csi_dev->hw_version_major = (uint8_t) ((hw_version >> 24) - '0');
+	csi_dev->hw_version_minor = (uint8_t) ((hw_version >> 16) - '0');
+	csi_dev->hw_version_minor = csi_dev->hw_version_minor * 10;
+	csi_dev->hw_version_minor += (uint8_t) ((hw_version >> 8) - '0');
+}
+
+int dw_mipi_csi_specific_mappings(struct mipi_csi_dev *csi_dev)
+{
+	struct device *dev = csi_dev->dev;
+
+	if ((csi_dev->hw_version_major) == 1)
+		if ((csi_dev->hw_version_minor) == 30) {
+
+			dev_dbg(dev, "We are version 30");
+			/*
+			 * Hardware registers that were
+			 * exclusive to version < 1.40
+			 */
+			reg.INT_FRAME_FATAL = 0x100;
+			reg.MASK_INT_FRAME_FATAL = 0x104;
+			reg.FORCE_INT_FRAME_FATAL = 0x108;
+			reg.INT_PKT = 0x120;
+			reg.MASK_INT_PKT = 0x124;
+			reg.FORCE_INT_PKT = 0x128;
+
+			/* interrupt source present until this release */
+			csi_int.PKT = BIT(17);
+			csi_int.LINE = BIT(18);
+			csi_int.IPI = BIT(19);
+			csi_int.FRAME_FATAL = BIT(2);
+
+		} else if ((csi_dev->hw_version_minor) == 40) {
+			dev_dbg(dev, "We are version 40");
+			/*
+			 * HW registers that were added
+			 * to version 1.40
+			 */
+			reg.ST_BNDRY_FRAME_FATAL = 0x280;
+			reg.MSK_BNDRY_FRAME_FATAL = 0x284;
+			reg.FORCE_BNDRY_FRAME_FATAL	= 0x288;
+			reg.ST_SEQ_FRAME_FATAL = 0x290;
+			reg.MSK_SEQ_FRAME_FATAL	= 0x294;
+			reg.FORCE_SEQ_FRAME_FATAL = 0x298;
+			reg.ST_CRC_FRAME_FATAL = 0x2a0;
+			reg.MSK_CRC_FRAME_FATAL	= 0x2a4;
+			reg.FORCE_CRC_FRAME_FATAL = 0x2a8;
+			reg.ST_PLD_CRC_FATAL = 0x2b0;
+			reg.MSK_PLD_CRC_FATAL = 0x2b4;
+			reg.FORCE_PLD_CRC_FATAL = 0x2b8;
+			reg.ST_DATA_ID = 0x2c0;
+			reg.MSK_DATA_ID = 0x2c4;
+			reg.FORCE_DATA_ID = 0x2c8;
+			reg.ST_ECC_CORRECT = 0x2d0;
+			reg.MSK_ECC_CORRECT = 0x2d4;
+			reg.FORCE_ECC_CORRECT = 0x2d8;
+			reg.DATA_IDS_VC_1 = 0x0;
+			reg.DATA_IDS_VC_2 = 0x0;
+			reg.VC_EXTENSION = 0x0;
+
+			/* interrupts map were changed */
+			csi_int.LINE = BIT(17);
+			csi_int.IPI = BIT(18);
+			csi_int.BNDRY_FRAME_FATAL = BIT(2);
+			csi_int.SEQ_FRAME_FATAL	= BIT(3);
+			csi_int.CRC_FRAME_FATAL = BIT(4);
+			csi_int.PLD_CRC_FATAL = BIT(5);
+			csi_int.DATA_ID = BIT(6);
+			csi_int.ECC_CORRECTED = BIT(7);
+
+		} else
+			dev_info(dev, "Version minor not supported.");
+	else
+		dev_info(dev, "Version major not supported.");
+
+	return 0;
+}
diff --git a/drivers/media/platform/dwc/dw-mipi-csi.h b/drivers/media/platform/dwc/dw-mipi-csi.h
new file mode 100644
index 0000000..eca0e48
--- /dev/null
+++ b/drivers/media/platform/dwc/dw-mipi-csi.h
@@ -0,0 +1,202 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * DWC MIPI CSI-2 Host device driver
+ *
+ * Copyright (C) 2018 Synopsys, Inc. All rights reserved.
+ * Author: Luis Oliveira <Luis.Oliveira@synopsys.com>
+ *
+ */
+
+#ifndef _DW_MIPI_CSI_H__
+#define _DW_MIPI_CSI_H__
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/phy/phy.h>
+#include <media/v4l2-dv-timings.h>
+#include <media/dwc/dw-mipi-csi-pltfrm.h>
+
+/* DW MIPI CSI-2 register addresses*/
+
+struct R_CSI2 {
+	u16 VERSION;
+	u16 N_LANES;
+	u16 CTRL_RESETN;
+	u16 INTERRUPT;
+	u16 DATA_IDS_1;
+	u16 DATA_IDS_2;
+	u16 DATA_IDS_VC_1;
+	u16 DATA_IDS_VC_2;
+	u16 IPI_MODE;
+	u16 IPI_VCID;
+	u16 IPI_DATA_TYPE;
+	u16 IPI_MEM_FLUSH;
+	u16 IPI_HSA_TIME;
+	u16 IPI_HBP_TIME;
+	u16 IPI_HSD_TIME;
+	u16 IPI_HLINE_TIME;
+	u16 IPI_SOFTRSTN;
+	u16 IPI_ADV_FEATURES;
+	u16 IPI_VSA_LINES;
+	u16 IPI_VBP_LINES;
+	u16 IPI_VFP_LINES;
+	u16 IPI_VACTIVE_LINES;
+	u16 VC_EXTENSION;
+	u16 INT_PHY_FATAL;
+	u16 MASK_INT_PHY_FATAL;
+	u16 FORCE_INT_PHY_FATAL;
+	u16 INT_PKT_FATAL;
+	u16 MASK_INT_PKT_FATAL;
+	u16 FORCE_INT_PKT_FATAL;
+	u16 INT_FRAME_FATAL;
+	u16 MASK_INT_FRAME_FATAL;
+	u16 FORCE_INT_FRAME_FATAL;
+	u16 INT_PHY;
+	u16 MASK_INT_PHY;
+	u16 FORCE_INT_PHY;
+	u16 INT_PKT;
+	u16 MASK_INT_PKT;
+	u16 FORCE_INT_PKT;
+	u16 INT_LINE;
+	u16 MASK_INT_LINE;
+	u16 FORCE_INT_LINE;
+	u16 INT_IPI;
+	u16 MASK_INT_IPI;
+	u16 FORCE_INT_IPI;
+	u16 ST_BNDRY_FRAME_FATAL;
+	u16 MSK_BNDRY_FRAME_FATAL;
+	u16 FORCE_BNDRY_FRAME_FATAL;
+	u16 ST_SEQ_FRAME_FATAL;
+	u16 MSK_SEQ_FRAME_FATAL;
+	u16 FORCE_SEQ_FRAME_FATAL;
+	u16 ST_CRC_FRAME_FATAL;
+	u16 MSK_CRC_FRAME_FATAL;
+	u16 FORCE_CRC_FRAME_FATAL;
+	u16 ST_PLD_CRC_FATAL;
+	u16 MSK_PLD_CRC_FATAL;
+	u16 FORCE_PLD_CRC_FATAL;
+	u16 ST_DATA_ID;
+	u16 MSK_DATA_ID;
+	u16 FORCE_DATA_ID;
+	u16 ST_ECC_CORRECT;
+	u16 MSK_ECC_CORRECT;
+	u16 FORCE_ECC_CORRECT;
+};
+/* Interrupt Masks */
+struct interrupt_type {
+	u32 PHY_FATAL;
+	u32 PKT_FATAL;
+	u32 FRAME_FATAL;
+	u32 PHY;
+	u32 PKT;
+	u32 LINE;
+	u32 IPI;
+	u32 BNDRY_FRAME_FATAL;
+	u32 SEQ_FRAME_FATAL;
+	u32 CRC_FRAME_FATAL;
+	u32 PLD_CRC_FATAL;
+	u32 DATA_ID;
+	u32 ECC_CORRECTED;
+};
+
+/* IPI Data Types */
+enum data_type {
+	CSI_2_YUV420_8 = 0x18,
+	CSI_2_YUV420_10 = 0x19,
+	CSI_2_YUV420_8_LEG = 0x1A,
+	CSI_2_YUV420_8_SHIFT = 0x1C,
+	CSI_2_YUV420_10_SHIFT = 0x1D,
+	CSI_2_YUV422_8 = 0x1E,
+	CSI_2_YUV422_10 = 0x1F,
+	CSI_2_RGB444 = 0x20,
+	CSI_2_RGB555 = 0x21,
+	CSI_2_RGB565 = 0x22,
+	CSI_2_RGB666 = 0x23,
+	CSI_2_RGB888 = 0x24,
+	CSI_2_RAW6 = 0x28,
+	CSI_2_RAW7 = 0x29,
+	CSI_2_RAW8 = 0x2A,
+	CSI_2_RAW10 = 0x2B,
+	CSI_2_RAW12 = 0x2C,
+	CSI_2_RAW14 = 0x2D,
+};
+
+/* DWC MIPI CSI-2 output types */
+enum output {
+	IPI_OUT = 0,
+	IDI_OUT = 1,
+	BOTH_OUT = 2
+};
+
+/* IPI output types */
+enum ipi_output {
+	CAMERA_TIMING = 0,
+	AUTO_TIMING = 1
+};
+
+/* Format template */
+struct mipi_fmt {
+	u32 code;
+	u8 depth;
+};
+
+/* CSI specific configuration */
+struct csi_hw {
+
+	uint32_t num_lanes;
+	uint32_t output;
+	uint32_t ipi_mode;
+	uint32_t ipi_color_mode;
+	uint32_t ipi_auto_flush;
+	uint32_t virtual_ch;
+	uint32_t hsa;
+	uint32_t hbp;
+	uint32_t hsd;
+	uint32_t htotal;
+	uint32_t vsa;
+	uint32_t vbp;
+	uint32_t vfp;
+	uint32_t vactive;
+};
+
+/* Structure to embed device driver information */
+struct mipi_csi_dev {
+	struct v4l2_subdev sd;
+	struct video_device vdev;
+	struct device *dev;
+
+	struct mutex lock;
+	spinlock_t slock;
+	struct media_pad pads[CSI_PADS_NUM];
+	u8 index;
+
+	/* Store current format */
+	const struct mipi_fmt *fmt;
+	struct v4l2_mbus_framefmt format;
+
+	/* Device Tree Information */
+	void __iomem *base_address;
+	uint32_t ctrl_irq_number;
+
+	struct csi_hw hw;
+	struct phy *phy;
+	struct reset_control *rst;
+
+	u8 ipi_dt;
+	u8 hw_version_major;
+	u16 hw_version_minor;
+};
+
+void dw_mipi_csi_reset(struct mipi_csi_dev *csi_dev);
+int dw_mipi_csi_mask_irq_power_off(struct mipi_csi_dev *csi_dev);
+int dw_mipi_csi_hw_stdby(struct mipi_csi_dev *csi_dev);
+void dw_mipi_csi_set_ipi_fmt(struct mipi_csi_dev *csi_dev);
+void dw_mipi_csi_start(struct mipi_csi_dev *csi_dev);
+int dw_mipi_csi_irq_handler(struct mipi_csi_dev *csi_dev);
+void dw_mipi_csi_get_version(struct mipi_csi_dev *csi_dev);
+int dw_mipi_csi_specific_mappings(struct mipi_csi_dev *csi_dev);
+void dw_mipi_csi_fill_timings(struct mipi_csi_dev *dev,
+		const struct v4l2_bt_timings *bt);
+
+#endif /*_DW_MIPI_CSI_H__ */
diff --git a/include/media/dwc/dw-mipi-csi-pltfrm.h b/include/media/dwc/dw-mipi-csi-pltfrm.h
new file mode 100644
index 0000000..00f4d90
--- /dev/null
+++ b/include/media/dwc/dw-mipi-csi-pltfrm.h
@@ -0,0 +1,101 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * CSI-2 Video platform video library
+ *
+ * Copyright (C) 2018 Synopsys, Inc. All rights reserved.
+ * Author: Luis Oliveira <Luis.Oliveira@synopsys.com>
+ *
+ */
+
+#ifndef __MIPI_CSI_PLTFRM_INCLUDES_H_
+#define __MIPI_CSI_PLTFRM_INCLUDES_H_
+
+#include <media/media-entity.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-mediabus.h>
+#include <media/v4l2-subdev.h>
+
+#define MAX_WIDTH	3280
+#define MAX_HEIGHT	1852
+#define MIN_WIDTH	640
+#define MIN_HEIGHT	480
+
+/* The subdevices' group IDs. */
+#define GRP_ID_SENSOR		(10)
+#define GRP_ID_CSI		(20)
+#define GRP_ID_VIF		(30)
+#define GRP_ID_VIDEODEV		(40)
+
+#define CSI_MAX_ENTITIES	(2)
+#define VIF_MAX_ENTITIES	(2)
+#define PLAT_MAX_SENSORS	(2)
+
+enum video_dev_pads {
+	VIDEO_DEV_SD_PAD_SINK_VIF1	= 0,
+	VIDEO_DEV_SD_PAD_SINK_VIF2	= 1,
+	VIDEO_DEV_SD_PAD_SOURCE_DMA	= 2,
+	VIDEO_DEV_SD_PADS_NUM		= 3,
+};
+enum vif_pads {
+	VIF_PAD_SINK_CSI		= 0,
+	VIF_PAD_SOURCE_DMA		= 1,
+	VIF_PADS_NUM			= 2,
+};
+
+enum mipi_csi_pads {
+	CSI_PAD_SINK			= 0,
+	CSI_PAD_SOURCE			= 1,
+	CSI_PADS_NUM			= 2,
+};
+
+struct plat_csi_source_info {
+	u16 flags;
+	u16 mux_id;
+};
+
+struct plat_csi_fmt {
+	char *name;
+	u32 mbus_code;
+	u32 fourcc;
+	u8 depth;
+};
+
+struct plat_csi_media_pipeline;
+
+/*
+ * Media pipeline operations to be called from within a video node,  i.e. the
+ * last entity within the pipeline. Implemented by related media device driver.
+ */
+struct plat_csi_media_pipeline_ops {
+	int (*prepare)(struct plat_csi_media_pipeline *p,
+				   struct media_entity *me);
+	int (*unprepare)(struct plat_csi_media_pipeline *p);
+	int (*open)(struct plat_csi_media_pipeline *p, struct media_entity *me,
+				bool resume);
+	int (*close)(struct plat_csi_media_pipeline *p);
+	int (*set_stream)(struct plat_csi_media_pipeline *p, bool state);
+	int (*set_format)(struct plat_csi_media_pipeline *p,
+					  struct v4l2_subdev_format *fmt);
+};
+
+struct plat_csi_video_entity {
+	struct video_device vdev;
+	struct plat_csi_media_pipeline *pipe;
+};
+
+struct plat_csi_media_pipeline {
+	struct media_pipeline mp;
+	const struct plat_csi_media_pipeline_ops *ops;
+};
+
+static inline struct plat_csi_video_entity *vdev_to_plat_csi_video_entity(
+					struct video_device *vdev)
+{
+	return container_of(vdev, struct plat_csi_video_entity, vdev);
+}
+
+#define plat_csi_pipeline_call(ent, op, args...)			  \
+	(!(ent) ? -ENOENT : (((ent)->pipe->ops && (ent)->pipe->ops->op) ? \
+	(ent)->pipe->ops->op(((ent)->pipe), ##args) : -ENOIOCTLCMD))	  \
+
+#endif /* __MIPI_CSI_PLTFRM_INCLUDES_H_ */
-- 
2.9.3


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 3/5] media: platform: dwc: Add DW MIPI DPHY core and platform
  2018-09-14 22:48 ` [PATCH 3/5] media: platform: dwc: Add DW MIPI DPHY core and platform Luis Oliveira
@ 2018-09-15  9:23   ` kbuild test robot
  0 siblings, 0 replies; 10+ messages in thread
From: kbuild test robot @ 2018-09-15  9:23 UTC (permalink / raw)
  To: Luis Oliveira
  Cc: kbuild-all, linux-media, linux-kernel, all-jpinto-org-pt02,
	Luis Oliveira, Mauro Carvalho Chehab, Hans Verkuil,
	Geert Uytterhoeven, Laurent Pinchart, Arnd Bergmann, Jacob Chen,
	Neil Armstrong, Keiichi Watanabe, Kate Stewart, Philipp Zabel,
	Todor Tomov

[-- Attachment #1: Type: text/plain, Size: 2079 bytes --]

Hi Luis,

I love your patch! Perhaps something to improve:

[auto build test WARNING on linuxtv-media/master]
[also build test WARNING on v4.19-rc3 next-20180913]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Luis-Oliveira/media-platform-Add-DesignWare-MIPI-CSI2-Host-placeholder/20180915-163514
base:   git://linuxtv.org/media_tree.git master
config: sh-allmodconfig (attached as .config)
compiler: sh4-linux-gnu-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        GCC_VERSION=7.2.0 make.cross ARCH=sh 

Note: it may well be a FALSE warning. FWIW you are at least aware of it now.
http://gcc.gnu.org/wiki/Better_Uninitialized_Warnings

All warnings (new ones prefixed by >>):

   drivers/media/platform/dwc/dw-dphy-rx.c: In function 'dw_dphy_read':
>> drivers/media/platform/dwc/dw-dphy-rx.c:147:5: warning: 'dphy2' may be used uninitialized in this function [-Wmaybe-uninitialized]
     if (dphy1 != dphy2)
        ^

vim +/dphy2 +147 drivers/media/platform/dwc/dw-dphy-rx.c

   132	
   133	u32 dw_dphy_read(struct dw_dphy_rx *dphy, u64 address)
   134	{
   135		u32 dphy1, dphy2;
   136	
   137		dphy1 = ioread32(dphy->base_address + address);
   138	
   139		if (dphy->lanes_config == CTRL_4_LANES)
   140			goto end;
   141	
   142		if (address == R_CSI2_DPHY_TST_CTRL0)
   143			dphy2 = ioread32(dphy->base_address + R_CSI2_DPHY2_TST_CTRL0);
   144		else if (address == R_CSI2_DPHY_TST_CTRL1)
   145			dphy2 = ioread32(dphy->base_address + R_CSI2_DPHY2_TST_CTRL1);
   146	
 > 147		if (dphy1 != dphy2)
   148			pr_err("Values read different for each dphy\n");
   149	
   150	end:
   151		return dphy1;
   152	}
   153	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 49563 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/5] media: platform: Add DesignWare MIPI CSI2 Host placeholder
  2018-09-14 22:48 ` [PATCH 1/5] media: platform: Add DesignWare MIPI CSI2 Host placeholder Luis Oliveira
@ 2018-09-15 12:16   ` kbuild test robot
  2018-09-15 12:34   ` kbuild test robot
  1 sibling, 0 replies; 10+ messages in thread
From: kbuild test robot @ 2018-09-15 12:16 UTC (permalink / raw)
  To: Luis Oliveira
  Cc: kbuild-all, linux-media, linux-kernel, all-jpinto-org-pt02,
	Luis Oliveira, Mauro Carvalho Chehab, Hans Verkuil,
	Geert Uytterhoeven, Laurent Pinchart, Arnd Bergmann, Jacob Chen,
	Neil Armstrong, Keiichi Watanabe, Kate Stewart, Philipp Zabel,
	Todor Tomov

[-- Attachment #1: Type: text/plain, Size: 2060 bytes --]

Hi Luis,

I love your patch! Yet something to improve:

[auto build test ERROR on linuxtv-media/master]
[also build test ERROR on v4.19-rc3 next-20180913]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Luis-Oliveira/media-platform-Add-DesignWare-MIPI-CSI2-Host-placeholder/20180915-163514
base:   git://linuxtv.org/media_tree.git master
config: i386-randconfig-s2-201836-CONFIG_DEBUG_INFO_REDUCED (attached as .config)
compiler: gcc-6 (Debian 6.4.0-9) 6.4.0 20171026
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

Note: the linux-review/Luis-Oliveira/media-platform-Add-DesignWare-MIPI-CSI2-Host-placeholder/20180915-163514 HEAD 2381c016179252d3b126e055b21edaef9ae5e1e2 builds fine.
      It only hurts bisectibility.

All errors (new ones prefixed by >>):

>> scripts/Makefile.build:45: drivers/media/platform/dwc/Makefile: No such file or directory
>> make[5]: *** No rule to make target 'drivers/media/platform/dwc/Makefile'.
   make[5]: Failed to remake makefile 'drivers/media/platform/dwc/Makefile'.

vim +45 scripts/Makefile.build

0c53c8e6 Sam Ravnborg   2007-10-14  41  
2a691470 Sam Ravnborg   2005-07-25  42  # The filename Kbuild has precedence over Makefile
db8c1a7b Sam Ravnborg   2005-07-27  43  kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
0c53c8e6 Sam Ravnborg   2007-10-14  44  kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)
0c53c8e6 Sam Ravnborg   2007-10-14 @45  include $(kbuild-file)
^1da177e Linus Torvalds 2005-04-16  46  

:::::: The code at line 45 was first introduced by commit
:::::: 0c53c8e6eb456cde30f2305421c605713856abc8 kbuild: check for wrong use of CFLAGS

:::::: TO: Sam Ravnborg <sam@neptun.(none)>
:::::: CC: Sam Ravnborg <sam@neptun.(none)>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 23279 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/5] media: platform: Add DesignWare MIPI CSI2 Host placeholder
  2018-09-14 22:48 ` [PATCH 1/5] media: platform: Add DesignWare MIPI CSI2 Host placeholder Luis Oliveira
  2018-09-15 12:16   ` kbuild test robot
@ 2018-09-15 12:34   ` kbuild test robot
  1 sibling, 0 replies; 10+ messages in thread
From: kbuild test robot @ 2018-09-15 12:34 UTC (permalink / raw)
  To: Luis Oliveira
  Cc: kbuild-all, linux-media, linux-kernel, all-jpinto-org-pt02,
	Luis Oliveira, Mauro Carvalho Chehab, Hans Verkuil,
	Geert Uytterhoeven, Laurent Pinchart, Arnd Bergmann, Jacob Chen,
	Neil Armstrong, Keiichi Watanabe, Kate Stewart, Philipp Zabel,
	Todor Tomov

[-- Attachment #1: Type: text/plain, Size: 2021 bytes --]

Hi Luis,

I love your patch! Yet something to improve:

[auto build test ERROR on linuxtv-media/master]
[also build test ERROR on v4.19-rc3 next-20180913]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Luis-Oliveira/media-platform-Add-DesignWare-MIPI-CSI2-Host-placeholder/20180915-163514
base:   git://linuxtv.org/media_tree.git master
config: i386-randconfig-s3-201836 (attached as .config)
compiler: gcc-6 (Debian 6.4.0-9) 6.4.0 20171026
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

Note: the linux-review/Luis-Oliveira/media-platform-Add-DesignWare-MIPI-CSI2-Host-placeholder/20180915-163514 HEAD 2381c016179252d3b126e055b21edaef9ae5e1e2 builds fine.
      It only hurts bisectibility.

All errors (new ones prefixed by >>):

>> scripts/Makefile.modbuiltin:26: drivers/media/platform/dwc/Makefile: No such file or directory
   make[5]: *** No rule to make target 'drivers/media/platform/dwc/Makefile'.
   make[5]: Failed to remake makefile 'drivers/media/platform/dwc/Makefile'.

vim +26 scripts/Makefile.modbuiltin

607b30fc Michal Marek 2010-06-10  22  
bc081dd6 Michal Marek 2009-12-07  23  # The filename Kbuild has precedence over Makefile
bc081dd6 Michal Marek 2009-12-07  24  kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
bc081dd6 Michal Marek 2009-12-07  25  kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)
bc081dd6 Michal Marek 2009-12-07 @26  include $(kbuild-file)
bc081dd6 Michal Marek 2009-12-07  27  

:::::: The code at line 26 was first introduced by commit
:::::: bc081dd6e9f622c73334dc465359168543ccaabf kbuild: generate modules.builtin

:::::: TO: Michal Marek <mmarek@suse.cz>
:::::: CC: Michal Marek <mmarek@suse.cz>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 27473 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 5/5] media: platform: dwc: Add MIPI CSI-2 controller driver
  2018-09-14 22:48 ` [PATCH 5/5] media: platform: dwc: Add MIPI CSI-2 controller driver Luis Oliveira
@ 2018-09-19 19:03   ` Fabio Estevam
  0 siblings, 0 replies; 10+ messages in thread
From: Fabio Estevam @ 2018-09-19 19:03 UTC (permalink / raw)
  To: Luis Oliveira
  Cc: linux-media, linux-kernel, all-jpinto-org-pt02,
	Mauro Carvalho Chehab, David S. Miller, Greg Kroah-Hartman,
	Andrew Morton, Arnd Bergmann, Hans Verkuil, Laurent Pinchart,
	Geert Uytterhoeven, Jacob Chen, Neil Armstrong, Thierry Reding,
	Maxime Ripard, Philipp Zabel, Todor Tomov

Hi Luis,

On Fri, Sep 14, 2018 at 7:48 PM, Luis Oliveira
<Luis.Oliveira@synopsys.com> wrote:

> +++ b/drivers/media/platform/dwc/dw-csi-plat.c
> @@ -0,0 +1,508 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later

According to Documentation/process/license-rules.rst this should be:
// SPDX-License-Identifier: GPL-2.0+

> +static int
> +dw_mipi_csi_parse_dt(struct platform_device *pdev, struct mipi_csi_dev *dev)
> +{
> +       struct device_node *node = pdev->dev.of_node;
> +       struct v4l2_fwnode_endpoint endpoint;
> +       int ret = 0;

No need to assign ret to 0.

> +
> +       ret = of_property_read_u32(node, "snps,output-type", &dev->hw.output);

> --- /dev/null
> +++ b/drivers/media/platform/dwc/dw-csi-plat.h
> @@ -0,0 +1,76 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */

Same as before.

> diff --git a/drivers/media/platform/dwc/dw-mipi-csi.c b/drivers/media/platform/dwc/dw-mipi-csi.c
> new file mode 100644
> index 0000000..926b287
> --- /dev/null
> +++ b/drivers/media/platform/dwc/dw-mipi-csi.c
> @@ -0,0 +1,491 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later

Ditto.

> +void dw_mipi_csi_fill_timings(struct mipi_csi_dev *dev,
> +                          const struct v4l2_bt_timings *bt)
> +{
> +

No need for this empty line.

> +       if (bt == NULL)

> diff --git a/drivers/media/platform/dwc/dw-mipi-csi.h b/drivers/media/platform/dwc/dw-mipi-csi.h
> new file mode 100644
> index 0000000..eca0e48
> --- /dev/null
> +++ b/drivers/media/platform/dwc/dw-mipi-csi.h
> @@ -0,0 +1,202 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */

Ditto.

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2018-09-19 19:03 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-09-14 22:48 [PATCH 0/5] platform: dwc: Add of DesignWare MIPI CSI-2 Host Luis Oliveira
2018-09-14 22:48 ` [PATCH 1/5] media: platform: Add DesignWare MIPI CSI2 Host placeholder Luis Oliveira
2018-09-15 12:16   ` kbuild test robot
2018-09-15 12:34   ` kbuild test robot
2018-09-14 22:48 ` [PATCH 2/5] Documentation: dt-bindings: Document the Synopsys MIPI DPHY Rx bindings Luis Oliveira
2018-09-14 22:48 ` [PATCH 3/5] media: platform: dwc: Add DW MIPI DPHY core and platform Luis Oliveira
2018-09-15  9:23   ` kbuild test robot
2018-09-14 22:48 ` [PATCH 4/5] Documentation: dt-bindings: Document bindings for DW MIPI CSI-2 Host Luis Oliveira
2018-09-14 22:48 ` [PATCH 5/5] media: platform: dwc: Add MIPI CSI-2 controller driver Luis Oliveira
2018-09-19 19:03   ` Fabio Estevam

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).