[PATCH 16/29][SRU][OEM-5.14] UBUNTU: SAUCE: IPU6 driver release for kernel 5.14 on 2021-11-01

You-Sheng Yang vicamo.yang at canonical.com
Tue Dec 28 06:19:42 UTC 2021


From: Hao Yao <hao.yao at intel.com>

BugLink: https://bugs.launchpad.net/bugs/1955383

Add support for both Tiger Lake and Alder Lake platforms.
Add support for OV01A10 sensor.

Signed-off-by: Hao Yao <hao.yao at intel.com>
(backported from
https://github.com/intel/ipu6-drivers/commit/1f26f0c8cb13d14c22d9f7010b1b4774b89136a9
added CONFIG_VIDEO_OV01A10 to drivers/media/i2c/Kconfig)
Signed-off-by: You-Sheng Yang <vicamo.yang at canonical.com>
---
 drivers/media/i2c/Kconfig                     |  14 +
 drivers/media/i2c/Makefile                    |   1 +
 drivers/media/i2c/hm11b1.c                    |  17 +-
 drivers/media/i2c/ov01a10.c                   | 934 ++++++++++++++++++
 drivers/media/i2c/ov01a1s.c                   |  37 +-
 drivers/media/i2c/power_ctrl_logic.c          |   2 +-
 drivers/media/pci/intel/Kconfig               |   3 +-
 drivers/media/pci/intel/ipu-buttress.c        |  59 +-
 drivers/media/pci/intel/ipu-buttress.h        |   1 -
 .../media/pci/intel/ipu-isys-csi2-be-soc.c    |  18 +-
 drivers/media/pci/intel/ipu-isys-csi2-be.c    | 325 ++++++
 drivers/media/pci/intel/ipu-isys-csi2.c       |  40 +-
 drivers/media/pci/intel/ipu-isys-subdev.c     |  95 +-
 drivers/media/pci/intel/ipu-isys-subdev.h     |  23 +-
 drivers/media/pci/intel/ipu-isys-tpg.c        | 311 ++++++
 drivers/media/pci/intel/ipu-isys-tpg.h        |  99 ++
 drivers/media/pci/intel/ipu-isys.c            |  32 +-
 drivers/media/pci/intel/ipu-isys.h            |   1 -
 drivers/media/pci/intel/ipu-mmu.c             |   4 +-
 drivers/media/pci/intel/ipu-psys-compat32.c   |   1 -
 drivers/media/pci/intel/ipu-psys.c            |  16 +-
 drivers/media/pci/intel/ipu-psys.h            |   5 +-
 drivers/media/pci/intel/ipu.c                 |   6 +-
 drivers/media/pci/intel/ipu.h                 |   3 +-
 drivers/media/pci/intel/ipu6/ipu-resources.c  |  32 +-
 .../media/pci/intel/ipu6/ipu6-fw-resources.c  |  23 +-
 drivers/media/pci/intel/ipu6/ipu6-isys-gpc.c  |   6 +-
 drivers/media/pci/intel/ipu6/ipu6-isys-phy.c  |  36 +-
 drivers/media/pci/intel/ipu6/ipu6-ppg.c       |  11 +-
 drivers/media/pci/intel/ipu6/ipu6-psys-gpc.c  |   6 +-
 drivers/media/pci/intel/ipu6/ipu6-psys.c      |  32 +-
 .../pci/intel/ipu6/ipu6ep-fw-resources.c      |  10 +-
 32 files changed, 1910 insertions(+), 293 deletions(-)
 create mode 100644 drivers/media/i2c/ov01a10.c
 create mode 100644 drivers/media/pci/intel/ipu-isys-csi2-be.c
 create mode 100644 drivers/media/pci/intel/ipu-isys-tpg.c
 create mode 100644 drivers/media/pci/intel/ipu-isys-tpg.h

diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index 3992c1b04d04..2baa70602722 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -1360,6 +1360,20 @@ config POWER_CTRL_LOGIC
 	  To compile this driver as a module, choose M here: the
 	  module will be called power_ctrl_logic.
 
+config VIDEO_OV01A10
+	tristate "OmniVision OV01A10 sensor support"
+	depends on VIDEO_V4L2 && I2C
+	depends on ACPI || COMPILE_TEST
+	select MEDIA_CONTROLLER
+	select VIDEO_V4L2_SUBDEV_API
+	select V4L2_FWNODE
+	help
+	  This is a Video4Linux2 sensor driver for the OmniVision
+	  OV01A10 camera.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ov01a10.
+
 config VIDEO_OV01A1S
 	tristate "OmniVision OV01A1S sensor support"
 	depends on POWER_CTRL_LOGIC
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index 4bfed5ed7cff..dae80fb28128 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -135,4 +135,5 @@ obj-$(CONFIG_SDR_MAX2175) += max2175.o
 
 obj-$(CONFIG_VIDEO_HM11B1) += hm11b1.o
 obj-$(CONFIG_VIDEO_OV01A1S) += ov01a1s.o
+obj-$(CONFIG_VIDEO_OV01A10) += ov01a10.o
 obj-$(CONFIG_POWER_CTRL_LOGIC) += power_ctrl_logic.o
diff --git a/drivers/media/i2c/hm11b1.c b/drivers/media/i2c/hm11b1.c
index ecc74d2bc250..27d5acebb73c 100644
--- a/drivers/media/i2c/hm11b1.c
+++ b/drivers/media/i2c/hm11b1.c
@@ -7,6 +7,7 @@
 #include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
+#include <linux/version.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-fwnode.h>
@@ -847,7 +848,7 @@ static int __maybe_unused hm11b1_resume(struct device *dev)
 }
 
 static int hm11b1_set_format(struct v4l2_subdev *sd,
-			     struct v4l2_subdev_pad_config *cfg,
+			     struct v4l2_subdev_state *sd_state,
 			     struct v4l2_subdev_format *fmt)
 {
 	struct hm11b1 *hm11b1 = to_hm11b1(sd);
@@ -862,7 +863,7 @@ static int hm11b1_set_format(struct v4l2_subdev *sd,
 	mutex_lock(&hm11b1->mutex);
 	hm11b1_update_pad_format(mode, &fmt->format);
 	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-		*v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format;
+		*v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format;
 	} else {
 		hm11b1->cur_mode = mode;
 		__v4l2_ctrl_s_ctrl(hm11b1->link_freq, mode->link_freq_index);
@@ -887,15 +888,15 @@ static int hm11b1_set_format(struct v4l2_subdev *sd,
 }
 
 static int hm11b1_get_format(struct v4l2_subdev *sd,
-			     struct v4l2_subdev_pad_config *cfg,
+			     struct v4l2_subdev_state *sd_state,
 			     struct v4l2_subdev_format *fmt)
 {
 	struct hm11b1 *hm11b1 = to_hm11b1(sd);
 
 	mutex_lock(&hm11b1->mutex);
 	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
-		fmt->format = *v4l2_subdev_get_try_format(&hm11b1->sd, cfg,
-							  fmt->pad);
+		fmt->format = *v4l2_subdev_get_try_format(&hm11b1->sd,
+							  sd_state, fmt->pad);
 	else
 		hm11b1_update_pad_format(hm11b1->cur_mode, &fmt->format);
 
@@ -905,7 +906,7 @@ static int hm11b1_get_format(struct v4l2_subdev *sd,
 }
 
 static int hm11b1_enum_mbus_code(struct v4l2_subdev *sd,
-				 struct v4l2_subdev_pad_config *cfg,
+				 struct v4l2_subdev_state *sd_state,
 				 struct v4l2_subdev_mbus_code_enum *code)
 {
 	if (code->index > 0)
@@ -917,7 +918,7 @@ static int hm11b1_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int hm11b1_enum_frame_size(struct v4l2_subdev *sd,
-				  struct v4l2_subdev_pad_config *cfg,
+				  struct v4l2_subdev_state *sd_state,
 				  struct v4l2_subdev_frame_size_enum *fse)
 {
 	if (fse->index >= ARRAY_SIZE(supported_modes))
@@ -940,7 +941,7 @@ static int hm11b1_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 
 	mutex_lock(&hm11b1->mutex);
 	hm11b1_update_pad_format(&supported_modes[0],
-				 v4l2_subdev_get_try_format(sd, fh->pad, 0));
+				 v4l2_subdev_get_try_format(sd, fh->state, 0));
 	mutex_unlock(&hm11b1->mutex);
 
 	return 0;
diff --git a/drivers/media/i2c/ov01a10.c b/drivers/media/i2c/ov01a10.c
new file mode 100644
index 000000000000..54968bbe1598
--- /dev/null
+++ b/drivers/media/i2c/ov01a10.c
@@ -0,0 +1,934 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2020-2021 Intel Corporation.
+
+#include <asm/unaligned.h>
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/version.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
+#include <linux/vsc.h>
+
+#define OV01A10_LINK_FREQ_400MHZ	400000000ULL
+#define OV01A10_SCLK			40000000LL
+#define OV01A10_MCLK			19200000
+#define OV01A10_DATA_LANES		1
+#define OV01A10_RGB_DEPTH		10
+
+#define OV01A10_REG_CHIP_ID		0x300a
+#define OV01A10_CHIP_ID			0x560141
+
+#define OV01A10_REG_MODE_SELECT		0x0100
+#define OV01A10_MODE_STANDBY		0x00
+#define OV01A10_MODE_STREAMING		0x01
+
+/* vertical-timings from sensor */
+#define OV01A10_REG_VTS			0x380e
+#define OV01A10_VTS_DEF			0x0380
+#define OV01A10_VTS_MIN			0x0380
+#define OV01A10_VTS_MAX			0xffff
+
+/* Exposure controls from sensor */
+#define OV01A10_REG_EXPOSURE		0x3501
+#define OV01A10_EXPOSURE_MIN		4
+#define OV01A10_EXPOSURE_MAX_MARGIN	8
+#define OV01A10_EXPOSURE_STEP		1
+
+/* Analog gain controls from sensor */
+#define OV01A10_REG_ANALOG_GAIN		0x3508
+#define OV01A10_ANAL_GAIN_MIN		0x100
+#define OV01A10_ANAL_GAIN_MAX		0xffff
+#define OV01A10_ANAL_GAIN_STEP		1
+
+/* Digital gain controls from sensor */
+#define OV01A10_REG_DIGILAL_GAIN_B	0x350A
+#define OV01A10_REG_DIGITAL_GAIN_GB	0x3510
+#define OV01A10_REG_DIGITAL_GAIN_GR	0x3513
+#define OV01A10_REG_DIGITAL_GAIN_R	0x3516
+#define OV01A10_DGTL_GAIN_MIN		0
+#define OV01A10_DGTL_GAIN_MAX		0x3ffff
+#define OV01A10_DGTL_GAIN_STEP		1
+#define OV01A10_DGTL_GAIN_DEFAULT	1024
+
+/* Test Pattern Control */
+#define OV01A10_REG_TEST_PATTERN		0x4503
+#define OV01A10_TEST_PATTERN_ENABLE	BIT(7)
+#define OV01A10_TEST_PATTERN_BAR_SHIFT	0
+
+enum {
+	OV01A10_LINK_FREQ_400MHZ_INDEX,
+};
+
+struct ov01a10_reg {
+	u16 address;
+	u8 val;
+};
+
+struct ov01a10_reg_list {
+	u32 num_of_regs;
+	const struct ov01a10_reg *regs;
+};
+
+struct ov01a10_link_freq_config {
+	const struct ov01a10_reg_list reg_list;
+};
+
+struct ov01a10_mode {
+	/* Frame width in pixels */
+	u32 width;
+
+	/* Frame height in pixels */
+	u32 height;
+
+	/* Horizontal timining size */
+	u32 hts;
+
+	/* Default vertical timining size */
+	u32 vts_def;
+
+	/* Min vertical timining size */
+	u32 vts_min;
+
+	/* Link frequency needed for this resolution */
+	u32 link_freq_index;
+
+	/* Sensor register settings for this resolution */
+	const struct ov01a10_reg_list reg_list;
+};
+
+static const struct ov01a10_reg mipi_data_rate_720mbps[] = {
+};
+
+static const struct ov01a10_reg sensor_1280x800_setting[] = {
+	{0x0103, 0x01},
+	{0x0302, 0x00},
+	{0x0303, 0x06},
+	{0x0304, 0x01},
+	{0x0305, 0xe0},
+	{0x0306, 0x00},
+	{0x0308, 0x01},
+	{0x0309, 0x00},
+	{0x030c, 0x01},
+	{0x0322, 0x01},
+	{0x0323, 0x06},
+	{0x0324, 0x01},
+	{0x0325, 0x68},
+	{0x3002, 0xa1},
+	{0x301e, 0xf0},
+	{0x3022, 0x01},
+	{0x3501, 0x03},
+	{0x3502, 0x78},
+	{0x3504, 0x0c},
+	{0x3508, 0x01},
+	{0x3509, 0x00},
+	{0x3601, 0xc0},
+	{0x3603, 0x71},
+	{0x3610, 0x68},
+	{0x3611, 0x86},
+	{0x3640, 0x10},
+	{0x3641, 0x80},
+	{0x3642, 0xdc},
+	{0x3646, 0x55},
+	{0x3647, 0x57},
+	{0x364b, 0x00},
+	{0x3653, 0x10},
+	{0x3655, 0x00},
+	{0x3656, 0x00},
+	{0x365f, 0x0f},
+	{0x3661, 0x45},
+	{0x3662, 0x24},
+	{0x3663, 0x11},
+	{0x3664, 0x07},
+	{0x3709, 0x34},
+	{0x370b, 0x6f},
+	{0x3714, 0x22},
+	{0x371b, 0x27},
+	{0x371c, 0x67},
+	{0x371d, 0xa7},
+	{0x371e, 0xe7},
+	{0x3730, 0x81},
+	{0x3733, 0x10},
+	{0x3734, 0x40},
+	{0x3737, 0x04},
+	{0x3739, 0x1c},
+	{0x3767, 0x00},
+	{0x376c, 0x81},
+	{0x3772, 0x14},
+	{0x37c2, 0x04},
+	{0x37d8, 0x03},
+	{0x37d9, 0x0c},
+	{0x37e0, 0x00},
+	{0x37e1, 0x08},
+	{0x37e2, 0x10},
+	{0x37e3, 0x04},
+	{0x37e4, 0x04},
+	{0x37e5, 0x03},
+	{0x37e6, 0x04},
+	{0x3800, 0x00},
+	{0x3801, 0x00},
+	{0x3802, 0x00},
+	{0x3803, 0x00},
+	{0x3804, 0x05},
+	{0x3805, 0x0f},
+	{0x3806, 0x03},
+	{0x3807, 0x2f},
+	{0x3808, 0x05},
+	{0x3809, 0x00},
+	{0x380a, 0x03},
+	{0x380b, 0x20},
+	{0x380c, 0x02},
+	{0x380d, 0xe8},
+	{0x380e, 0x03},
+	{0x380f, 0x80},
+	{0x3810, 0x00},
+	{0x3811, 0x09},
+	{0x3812, 0x00},
+	{0x3813, 0x08},
+	{0x3814, 0x01},
+	{0x3815, 0x01},
+	{0x3816, 0x01},
+	{0x3817, 0x01},
+	{0x3820, 0xa8},
+	{0x3822, 0x13},
+	{0x3832, 0x28},
+	{0x3833, 0x10},
+	{0x3b00, 0x00},
+	{0x3c80, 0x00},
+	{0x3c88, 0x02},
+	{0x3c8c, 0x07},
+	{0x3c8d, 0x40},
+	{0x3cc7, 0x80},
+	{0x4000, 0xc3},
+	{0x4001, 0xe0},
+	{0x4003, 0x40},
+	{0x4008, 0x02},
+	{0x4009, 0x19},
+	{0x400a, 0x01},
+	{0x400b, 0x6c},
+	{0x4011, 0x00},
+	{0x4041, 0x00},
+	{0x4300, 0xff},
+	{0x4301, 0x00},
+	{0x4302, 0x0f},
+	{0x4503, 0x00},
+	{0x4601, 0x50},
+	{0x4800, 0x64},
+	{0x481f, 0x34},
+	{0x4825, 0x33},
+	{0x4837, 0x11},
+	{0x4881, 0x40},
+	{0x4883, 0x01},
+	{0x4890, 0x00},
+	{0x4901, 0x00},
+	{0x4902, 0x00},
+	{0x4b00, 0x2a},
+	{0x4b0d, 0x00},
+	{0x450a, 0x04},
+	{0x450b, 0x00},
+	{0x5000, 0x65},
+	{0x5200, 0x18},
+	{0x5004, 0x00},
+	{0x5080, 0x40},
+	{0x0305, 0xf4},
+	{0x0325, 0xc2},
+	{0x380c, 0x05},
+	{0x380d, 0xd0},
+};
+
+static const char * const ov01a10_test_pattern_menu[] = {
+	"Disabled",
+	"Color Bar",
+	"Top-Bottom Darker Color Bar",
+	"Right-Left Darker Color Bar",
+	"Color Bar type 4",
+};
+
+static const s64 link_freq_menu_items[] = {
+	OV01A10_LINK_FREQ_400MHZ,
+};
+
+static const struct ov01a10_link_freq_config link_freq_configs[] = {
+	[OV01A10_LINK_FREQ_400MHZ_INDEX] = {
+		.reg_list = {
+			.num_of_regs = ARRAY_SIZE(mipi_data_rate_720mbps),
+			.regs = mipi_data_rate_720mbps,
+		}
+	},
+};
+
+static const struct ov01a10_mode supported_modes[] = {
+	{
+		.width = 1280,
+		.height = 800,
+		.hts = 1488,
+		.vts_def = OV01A10_VTS_DEF,
+		.vts_min = OV01A10_VTS_MIN,
+		.reg_list = {
+			.num_of_regs = ARRAY_SIZE(sensor_1280x800_setting),
+			.regs = sensor_1280x800_setting,
+		},
+		.link_freq_index = OV01A10_LINK_FREQ_400MHZ_INDEX,
+	},
+};
+
+struct ov01a10 {
+	struct v4l2_subdev sd;
+	struct media_pad pad;
+	struct v4l2_ctrl_handler ctrl_handler;
+
+	/* V4L2 Controls */
+	struct v4l2_ctrl *link_freq;
+	struct v4l2_ctrl *pixel_rate;
+	struct v4l2_ctrl *vblank;
+	struct v4l2_ctrl *hblank;
+	struct v4l2_ctrl *exposure;
+
+	/* Current mode */
+	const struct ov01a10_mode *cur_mode;
+
+	/* To serialize asynchronus callbacks */
+	struct mutex mutex;
+
+	/* Streaming on/off */
+	bool streaming;
+};
+
+static inline struct ov01a10 *to_ov01a10(struct v4l2_subdev *subdev)
+{
+	return container_of(subdev, struct ov01a10, sd);
+}
+
+static int ov01a10_read_reg(struct ov01a10 *ov01a10, u16 reg, u16 len, u32 *val)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&ov01a10->sd);
+	struct i2c_msg msgs[2];
+	u8 addr_buf[2];
+	u8 data_buf[4] = {0};
+	int ret = 0;
+
+	if (len > sizeof(data_buf))
+		return -EINVAL;
+
+	put_unaligned_be16(reg, addr_buf);
+	msgs[0].addr = client->addr;
+	msgs[0].flags = 0;
+	msgs[0].len = sizeof(addr_buf);
+	msgs[0].buf = addr_buf;
+	msgs[1].addr = client->addr;
+	msgs[1].flags = I2C_M_RD;
+	msgs[1].len = len;
+	msgs[1].buf = &data_buf[sizeof(data_buf) - len];
+
+	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+
+	if (ret != ARRAY_SIZE(msgs))
+		return ret < 0 ? ret : -EIO;
+
+	*val = get_unaligned_be32(data_buf);
+
+	return 0;
+}
+
+static int ov01a10_write_reg(struct ov01a10 *ov01a10, u16 reg, u16 len, u32 val)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&ov01a10->sd);
+	u8 buf[6];
+	int ret = 0;
+
+	if (len > 4)
+		return -EINVAL;
+
+	put_unaligned_be16(reg, buf);
+	put_unaligned_be32(val << 8 * (4 - len), buf + 2);
+
+	ret = i2c_master_send(client, buf, len + 2);
+	if (ret != len + 2)
+		return ret < 0 ? ret : -EIO;
+
+	return 0;
+}
+
+static int ov01a10_write_reg_list(struct ov01a10 *ov01a10,
+				  const struct ov01a10_reg_list *r_list)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&ov01a10->sd);
+	unsigned int i;
+	int ret = 0;
+
+	for (i = 0; i < r_list->num_of_regs; i++) {
+		ret = ov01a10_write_reg(ov01a10, r_list->regs[i].address, 1,
+					r_list->regs[i].val);
+		if (ret) {
+			dev_err_ratelimited(&client->dev,
+					    "write reg 0x%4.4x return err = %d",
+					    r_list->regs[i].address, ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int ov01a10_update_digital_gain(struct ov01a10 *ov01a10, u32 d_gain)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&ov01a10->sd);
+	u32 real = d_gain << 6;
+	int ret = 0;
+
+	ret = ov01a10_write_reg(ov01a10, OV01A10_REG_DIGILAL_GAIN_B, 3, real);
+	if (ret) {
+		dev_err(&client->dev, "failed to set OV01A10_REG_DIGITAL_GAIN_B");
+		return ret;
+	}
+	ret = ov01a10_write_reg(ov01a10, OV01A10_REG_DIGITAL_GAIN_GB, 3, real);
+	if (ret) {
+		dev_err(&client->dev, "failed to set OV01A10_REG_DIGITAL_GAIN_GB");
+		return ret;
+	}
+	ret = ov01a10_write_reg(ov01a10, OV01A10_REG_DIGITAL_GAIN_GR, 3, real);
+	if (ret) {
+		dev_err(&client->dev, "failed to set OV01A10_REG_DIGITAL_GAIN_GR");
+		return ret;
+	}
+
+	ret = ov01a10_write_reg(ov01a10, OV01A10_REG_DIGITAL_GAIN_R, 3, real);
+	if (ret) {
+		dev_err(&client->dev, "failed to set OV01A10_REG_DIGITAL_GAIN_R");
+		return ret;
+	}
+	return ret;
+}
+
+static int ov01a10_test_pattern(struct ov01a10 *ov01a10, u32 pattern)
+{
+	if (pattern)
+		pattern = (pattern - 1) << OV01A10_TEST_PATTERN_BAR_SHIFT |
+			  OV01A10_TEST_PATTERN_ENABLE;
+
+	return ov01a10_write_reg(ov01a10, OV01A10_REG_TEST_PATTERN, 1, pattern);
+}
+
+static int ov01a10_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct ov01a10 *ov01a10 = container_of(ctrl->handler,
+					     struct ov01a10, ctrl_handler);
+	struct i2c_client *client = v4l2_get_subdevdata(&ov01a10->sd);
+	s64 exposure_max;
+	int ret = 0;
+
+	/* Propagate change of current control to all related controls */
+	if (ctrl->id == V4L2_CID_VBLANK) {
+		/* Update max exposure while meeting expected vblanking */
+		exposure_max = ov01a10->cur_mode->height + ctrl->val -
+			       OV01A10_EXPOSURE_MAX_MARGIN;
+		__v4l2_ctrl_modify_range(ov01a10->exposure,
+					 ov01a10->exposure->minimum,
+					 exposure_max, ov01a10->exposure->step,
+					 exposure_max);
+	}
+
+	/* V4L2 controls values will be applied only when power is already up */
+	if (!pm_runtime_get_if_in_use(&client->dev))
+		return 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_ANALOGUE_GAIN:
+		ret = ov01a10_write_reg(ov01a10, OV01A10_REG_ANALOG_GAIN, 2,
+					ctrl->val);
+		break;
+
+	case V4L2_CID_DIGITAL_GAIN:
+		ret = ov01a10_update_digital_gain(ov01a10, ctrl->val);
+		break;
+
+	case V4L2_CID_EXPOSURE:
+		ret = ov01a10_write_reg(ov01a10, OV01A10_REG_EXPOSURE, 2,
+					ctrl->val);
+		break;
+
+	case V4L2_CID_VBLANK:
+		ret = ov01a10_write_reg(ov01a10, OV01A10_REG_VTS, 2,
+					ov01a10->cur_mode->height + ctrl->val);
+		break;
+
+	case V4L2_CID_TEST_PATTERN:
+		ret = ov01a10_test_pattern(ov01a10, ctrl->val);
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	pm_runtime_put(&client->dev);
+
+	return ret;
+}
+
+static const struct v4l2_ctrl_ops ov01a10_ctrl_ops = {
+	.s_ctrl = ov01a10_set_ctrl,
+};
+
+static int ov01a10_init_controls(struct ov01a10 *ov01a10)
+{
+	struct v4l2_ctrl_handler *ctrl_hdlr;
+	const struct ov01a10_mode *cur_mode;
+	s64 exposure_max, h_blank;
+	u32 vblank_min, vblank_max, vblank_default;
+	int size;
+	int ret = 0;
+
+	ctrl_hdlr = &ov01a10->ctrl_handler;
+	ret = v4l2_ctrl_handler_init(ctrl_hdlr, 8);
+	if (ret)
+		return ret;
+
+	ctrl_hdlr->lock = &ov01a10->mutex;
+	cur_mode = ov01a10->cur_mode;
+	size = ARRAY_SIZE(link_freq_menu_items);
+
+	ov01a10->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr,
+						    &ov01a10_ctrl_ops,
+						    V4L2_CID_LINK_FREQ,
+						    size - 1, 0,
+						    link_freq_menu_items);
+	if (ov01a10->link_freq)
+		ov01a10->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+	ov01a10->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &ov01a10_ctrl_ops,
+						V4L2_CID_PIXEL_RATE, 0,
+						OV01A10_SCLK, 1, OV01A10_SCLK);
+
+	vblank_min = cur_mode->vts_min - cur_mode->height;
+	vblank_max = OV01A10_VTS_MAX - cur_mode->height;
+	vblank_default = cur_mode->vts_def - cur_mode->height;
+	ov01a10->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov01a10_ctrl_ops,
+					    V4L2_CID_VBLANK, vblank_min,
+					    vblank_max, 1, vblank_default);
+
+	h_blank = cur_mode->hts - cur_mode->width;
+	ov01a10->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov01a10_ctrl_ops,
+					    V4L2_CID_HBLANK, h_blank, h_blank,
+					    1, h_blank);
+	if (ov01a10->hblank)
+		ov01a10->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+	v4l2_ctrl_new_std(ctrl_hdlr, &ov01a10_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
+			  OV01A10_ANAL_GAIN_MIN, OV01A10_ANAL_GAIN_MAX,
+			  OV01A10_ANAL_GAIN_STEP, OV01A10_ANAL_GAIN_MIN);
+	v4l2_ctrl_new_std(ctrl_hdlr, &ov01a10_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
+			  OV01A10_DGTL_GAIN_MIN, OV01A10_DGTL_GAIN_MAX,
+			  OV01A10_DGTL_GAIN_STEP, OV01A10_DGTL_GAIN_DEFAULT);
+	exposure_max = cur_mode->vts_def - OV01A10_EXPOSURE_MAX_MARGIN;
+	ov01a10->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &ov01a10_ctrl_ops,
+					      V4L2_CID_EXPOSURE,
+					      OV01A10_EXPOSURE_MIN,
+					      exposure_max,
+					      OV01A10_EXPOSURE_STEP,
+					      exposure_max);
+	v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &ov01a10_ctrl_ops,
+				     V4L2_CID_TEST_PATTERN,
+				     ARRAY_SIZE(ov01a10_test_pattern_menu) - 1,
+				     0, 0, ov01a10_test_pattern_menu);
+	if (ctrl_hdlr->error)
+		return ctrl_hdlr->error;
+
+	ov01a10->sd.ctrl_handler = ctrl_hdlr;
+
+	return 0;
+}
+
+static void ov01a10_update_pad_format(const struct ov01a10_mode *mode,
+				      struct v4l2_mbus_framefmt *fmt)
+{
+	fmt->width = mode->width;
+	fmt->height = mode->height;
+	fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
+	fmt->field = V4L2_FIELD_NONE;
+}
+
+static int ov01a10_start_streaming(struct ov01a10 *ov01a10)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&ov01a10->sd);
+	const struct ov01a10_reg_list *reg_list;
+	int link_freq_index;
+	int ret = 0;
+
+	link_freq_index = ov01a10->cur_mode->link_freq_index;
+	reg_list = &link_freq_configs[link_freq_index].reg_list;
+	ret = ov01a10_write_reg_list(ov01a10, reg_list);
+	if (ret) {
+		dev_err(&client->dev, "failed to set plls");
+		return ret;
+	}
+
+	reg_list = &ov01a10->cur_mode->reg_list;
+	ret = ov01a10_write_reg_list(ov01a10, reg_list);
+	if (ret) {
+		dev_err(&client->dev, "failed to set mode");
+		return ret;
+	}
+
+	ret = __v4l2_ctrl_handler_setup(ov01a10->sd.ctrl_handler);
+	if (ret)
+		return ret;
+
+	ret = ov01a10_write_reg(ov01a10, OV01A10_REG_MODE_SELECT, 1,
+				OV01A10_MODE_STREAMING);
+	if (ret)
+		dev_err(&client->dev, "failed to start streaming");
+
+	return ret;
+}
+
+static void ov01a10_stop_streaming(struct ov01a10 *ov01a10)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&ov01a10->sd);
+	int ret = 0;
+
+	ret = ov01a10_write_reg(ov01a10, OV01A10_REG_MODE_SELECT, 1,
+				OV01A10_MODE_STANDBY);
+	if (ret)
+		dev_err(&client->dev, "failed to stop streaming");
+}
+
+static int ov01a10_set_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct ov01a10 *ov01a10 = to_ov01a10(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int ret = 0;
+
+	if (ov01a10->streaming == enable)
+		return 0;
+
+	mutex_lock(&ov01a10->mutex);
+	if (enable) {
+		ret = pm_runtime_get_sync(&client->dev);
+		if (ret < 0) {
+			pm_runtime_put_noidle(&client->dev);
+			mutex_unlock(&ov01a10->mutex);
+			return ret;
+		}
+
+		ret = ov01a10_start_streaming(ov01a10);
+		if (ret) {
+			enable = 0;
+			ov01a10_stop_streaming(ov01a10);
+			pm_runtime_put(&client->dev);
+		}
+	} else {
+		ov01a10_stop_streaming(ov01a10);
+		pm_runtime_put(&client->dev);
+	}
+
+	ov01a10->streaming = enable;
+	mutex_unlock(&ov01a10->mutex);
+
+	return ret;
+}
+
+static int __maybe_unused ov01a10_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct ov01a10 *ov01a10 = to_ov01a10(sd);
+
+	mutex_lock(&ov01a10->mutex);
+	if (ov01a10->streaming)
+		ov01a10_stop_streaming(ov01a10);
+
+	mutex_unlock(&ov01a10->mutex);
+
+	return 0;
+}
+
+static int __maybe_unused ov01a10_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct ov01a10 *ov01a10 = to_ov01a10(sd);
+	int ret = 0;
+
+	mutex_lock(&ov01a10->mutex);
+	if (!ov01a10->streaming)
+		goto exit;
+
+	ret = ov01a10_start_streaming(ov01a10);
+	if (ret) {
+		ov01a10->streaming = false;
+		ov01a10_stop_streaming(ov01a10);
+	}
+
+exit:
+	mutex_unlock(&ov01a10->mutex);
+	return ret;
+}
+
+static int ov01a10_set_format(struct v4l2_subdev *sd,
+			      struct v4l2_subdev_state *sd_state,
+			      struct v4l2_subdev_format *fmt)
+{
+	struct ov01a10 *ov01a10 = to_ov01a10(sd);
+	const struct ov01a10_mode *mode;
+	s32 vblank_def, h_blank;
+
+	mode = v4l2_find_nearest_size(supported_modes,
+				      ARRAY_SIZE(supported_modes), width,
+				      height, fmt->format.width,
+				      fmt->format.height);
+
+	mutex_lock(&ov01a10->mutex);
+	ov01a10_update_pad_format(mode, &fmt->format);
+	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+		*v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format;
+	} else {
+		ov01a10->cur_mode = mode;
+		__v4l2_ctrl_s_ctrl(ov01a10->link_freq, mode->link_freq_index);
+		__v4l2_ctrl_s_ctrl_int64(ov01a10->pixel_rate, OV01A10_SCLK);
+
+		/* Update limits and set FPS to default */
+		vblank_def = mode->vts_def - mode->height;
+		__v4l2_ctrl_modify_range(ov01a10->vblank,
+					 mode->vts_min - mode->height,
+					 OV01A10_VTS_MAX - mode->height, 1,
+					 vblank_def);
+		__v4l2_ctrl_s_ctrl(ov01a10->vblank, vblank_def);
+		h_blank = mode->hts - mode->width;
+		__v4l2_ctrl_modify_range(ov01a10->hblank, h_blank, h_blank, 1,
+					 h_blank);
+	}
+	mutex_unlock(&ov01a10->mutex);
+
+	return 0;
+}
+
+static int ov01a10_get_format(struct v4l2_subdev *sd,
+			      struct v4l2_subdev_state *sd_state,
+			      struct v4l2_subdev_format *fmt)
+{
+	struct ov01a10 *ov01a10 = to_ov01a10(sd);
+
+	mutex_lock(&ov01a10->mutex);
+	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
+		fmt->format = *v4l2_subdev_get_try_format(&ov01a10->sd,
+							  sd_state, fmt->pad);
+	else
+		ov01a10_update_pad_format(ov01a10->cur_mode, &fmt->format);
+
+	mutex_unlock(&ov01a10->mutex);
+
+	return 0;
+}
+
+static int ov01a10_enum_mbus_code(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_state *sd_state,
+				  struct v4l2_subdev_mbus_code_enum *code)
+{
+	if (code->index > 0)
+		return -EINVAL;
+
+	code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
+
+	return 0;
+}
+
+static int ov01a10_enum_frame_size(struct v4l2_subdev *sd,
+				   struct v4l2_subdev_state *sd_state,
+				   struct v4l2_subdev_frame_size_enum *fse)
+{
+	if (fse->index >= ARRAY_SIZE(supported_modes))
+		return -EINVAL;
+
+	if (fse->code != MEDIA_BUS_FMT_SBGGR10_1X10)
+		return -EINVAL;
+
+	fse->min_width = supported_modes[fse->index].width;
+	fse->max_width = fse->min_width;
+	fse->min_height = supported_modes[fse->index].height;
+	fse->max_height = fse->min_height;
+
+	return 0;
+}
+
+static int ov01a10_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	struct ov01a10 *ov01a10 = to_ov01a10(sd);
+
+	mutex_lock(&ov01a10->mutex);
+	ov01a10_update_pad_format(&supported_modes[0],
+				  v4l2_subdev_get_try_format(sd, fh->state, 0));
+	mutex_unlock(&ov01a10->mutex);
+
+	return 0;
+}
+
+static const struct v4l2_subdev_video_ops ov01a10_video_ops = {
+	.s_stream = ov01a10_set_stream,
+};
+
+static const struct v4l2_subdev_pad_ops ov01a10_pad_ops = {
+	.set_fmt = ov01a10_set_format,
+	.get_fmt = ov01a10_get_format,
+	.enum_mbus_code = ov01a10_enum_mbus_code,
+	.enum_frame_size = ov01a10_enum_frame_size,
+};
+
+static const struct v4l2_subdev_ops ov01a10_subdev_ops = {
+	.video = &ov01a10_video_ops,
+	.pad = &ov01a10_pad_ops,
+};
+
+static const struct media_entity_operations ov01a10_subdev_entity_ops = {
+	.link_validate = v4l2_subdev_link_validate,
+};
+
+static const struct v4l2_subdev_internal_ops ov01a10_internal_ops = {
+	.open = ov01a10_open,
+};
+
+static int ov01a10_identify_module(struct ov01a10 *ov01a10)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&ov01a10->sd);
+	int ret;
+	u32 val;
+
+	ret = ov01a10_read_reg(ov01a10, OV01A10_REG_CHIP_ID, 3, &val);
+	if (ret)
+		return ret;
+
+	if (val != OV01A10_CHIP_ID) {
+		dev_err(&client->dev, "chip id mismatch: %x!=%x",
+			OV01A10_CHIP_ID, val);
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+static int ov01a10_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct ov01a10 *ov01a10 = to_ov01a10(sd);
+
+	v4l2_async_unregister_subdev(sd);
+	media_entity_cleanup(&sd->entity);
+	v4l2_ctrl_handler_free(sd->ctrl_handler);
+	pm_runtime_disable(&client->dev);
+	mutex_destroy(&ov01a10->mutex);
+
+	return 0;
+}
+
+static int ov01a10_probe(struct i2c_client *client)
+{
+	struct ov01a10 *ov01a10;
+	int ret = 0;
+	struct vsc_mipi_config conf;
+	struct vsc_camera_status status;
+	s64 link_freq;
+
+	conf.lane_num = OV01A10_DATA_LANES;
+	/* frequency unit 100k */
+	conf.freq = OV01A10_LINK_FREQ_400MHZ / 100000;
+	ret = vsc_acquire_camera_sensor(&conf, NULL, NULL, &status);
+	if (ret == -EAGAIN)
+		return -EPROBE_DEFER;
+	else if (ret) {
+		dev_err(&client->dev, "Acquire VSC failed.\n");
+		return ret;
+	}
+	ov01a10 = devm_kzalloc(&client->dev, sizeof(*ov01a10), GFP_KERNEL);
+	if (!ov01a10) {
+		ret = -ENOMEM;
+		goto probe_error_ret;
+	}
+
+	v4l2_i2c_subdev_init(&ov01a10->sd, client, &ov01a10_subdev_ops);
+
+	ret = ov01a10_identify_module(ov01a10);
+	if (ret) {
+		dev_err(&client->dev, "failed to find sensor: %d", ret);
+		goto probe_error_ret;
+	}
+
+	mutex_init(&ov01a10->mutex);
+	ov01a10->cur_mode = &supported_modes[0];
+	ret = ov01a10_init_controls(ov01a10);
+	if (ret) {
+		dev_err(&client->dev, "failed to init controls: %d", ret);
+		goto probe_error_v4l2_ctrl_handler_free;
+	}
+
+	ov01a10->sd.internal_ops = &ov01a10_internal_ops;
+	ov01a10->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	ov01a10->sd.entity.ops = &ov01a10_subdev_entity_ops;
+	ov01a10->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+	ov01a10->pad.flags = MEDIA_PAD_FL_SOURCE;
+	ret = media_entity_pads_init(&ov01a10->sd.entity, 1, &ov01a10->pad);
+	if (ret) {
+		dev_err(&client->dev, "failed to init entity pads: %d", ret);
+		goto probe_error_v4l2_ctrl_handler_free;
+	}
+
+	ret = v4l2_async_register_subdev_sensor(&ov01a10->sd);
+	if (ret < 0) {
+		dev_err(&client->dev, "failed to register V4L2 subdev: %d",
+			ret);
+		goto probe_error_media_entity_cleanup;
+	}
+
+	vsc_release_camera_sensor(&status);
+	/*
+	 * Device is already turned on by i2c-core with ACPI domain PM.
+	 * Enable runtime PM and turn off the device.
+	 */
+	pm_runtime_set_active(&client->dev);
+	pm_runtime_enable(&client->dev);
+	pm_runtime_idle(&client->dev);
+
+	return 0;
+
+probe_error_media_entity_cleanup:
+	media_entity_cleanup(&ov01a10->sd.entity);
+
+probe_error_v4l2_ctrl_handler_free:
+	v4l2_ctrl_handler_free(ov01a10->sd.ctrl_handler);
+	mutex_destroy(&ov01a10->mutex);
+
+probe_error_ret:
+	vsc_release_camera_sensor(&status);
+	return ret;
+}
+
+static const struct dev_pm_ops ov01a10_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(ov01a10_suspend, ov01a10_resume)
+};
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id ov01a10_acpi_ids[] = {
+	{"OVTI01A0"},
+	{}
+};
+
+MODULE_DEVICE_TABLE(acpi, ov01a10_acpi_ids);
+#endif
+
+static struct i2c_driver ov01a10_i2c_driver = {
+	.driver = {
+		.name = "ov01a10",
+		.pm = &ov01a10_pm_ops,
+		.acpi_match_table = ACPI_PTR(ov01a10_acpi_ids),
+	},
+	.probe_new = ov01a10_probe,
+	.remove = ov01a10_remove,
+};
+
+module_i2c_driver(ov01a10_i2c_driver);
+
+MODULE_AUTHOR("Wang Yating <yating.wang at intel.com>");
+MODULE_DESCRIPTION("OmniVision OV01A10 sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/ov01a1s.c b/drivers/media/i2c/ov01a1s.c
index dd299204d9e9..2bda3122ff47 100644
--- a/drivers/media/i2c/ov01a1s.c
+++ b/drivers/media/i2c/ov01a1s.c
@@ -7,10 +7,12 @@
 #include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
+#include <linux/version.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-fwnode.h>
 #include "power_ctrl_logic.h"
+#include <linux/vsc.h>
 
 #define OV01A1S_LINK_FREQ_400MHZ	400000000ULL
 #define OV01A1S_SCLK			40000000LL
@@ -677,7 +679,7 @@ static int __maybe_unused ov01a1s_resume(struct device *dev)
 }
 
 static int ov01a1s_set_format(struct v4l2_subdev *sd,
-			      struct v4l2_subdev_pad_config *cfg,
+			      struct v4l2_subdev_state *sd_state,
 			      struct v4l2_subdev_format *fmt)
 {
 	struct ov01a1s *ov01a1s = to_ov01a1s(sd);
@@ -692,7 +694,7 @@ static int ov01a1s_set_format(struct v4l2_subdev *sd,
 	mutex_lock(&ov01a1s->mutex);
 	ov01a1s_update_pad_format(mode, &fmt->format);
 	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-		*v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format;
+		*v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format;
 	} else {
 		ov01a1s->cur_mode = mode;
 		__v4l2_ctrl_s_ctrl(ov01a1s->link_freq, mode->link_freq_index);
@@ -715,15 +717,15 @@ static int ov01a1s_set_format(struct v4l2_subdev *sd,
 }
 
 static int ov01a1s_get_format(struct v4l2_subdev *sd,
-			      struct v4l2_subdev_pad_config *cfg,
+			      struct v4l2_subdev_state *sd_state,
 			      struct v4l2_subdev_format *fmt)
 {
 	struct ov01a1s *ov01a1s = to_ov01a1s(sd);
 
 	mutex_lock(&ov01a1s->mutex);
 	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
-		fmt->format = *v4l2_subdev_get_try_format(&ov01a1s->sd, cfg,
-							  fmt->pad);
+		fmt->format = *v4l2_subdev_get_try_format(&ov01a1s->sd,
+							  sd_state, fmt->pad);
 	else
 		ov01a1s_update_pad_format(ov01a1s->cur_mode, &fmt->format);
 
@@ -733,7 +735,7 @@ static int ov01a1s_get_format(struct v4l2_subdev *sd,
 }
 
 static int ov01a1s_enum_mbus_code(struct v4l2_subdev *sd,
-				  struct v4l2_subdev_pad_config *cfg,
+				  struct v4l2_subdev_state *sd_state,
 				  struct v4l2_subdev_mbus_code_enum *code)
 {
 	if (code->index > 0)
@@ -745,7 +747,7 @@ static int ov01a1s_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int ov01a1s_enum_frame_size(struct v4l2_subdev *sd,
-				   struct v4l2_subdev_pad_config *cfg,
+				   struct v4l2_subdev_state *sd_state,
 				   struct v4l2_subdev_frame_size_enum *fse)
 {
 	if (fse->index >= ARRAY_SIZE(supported_modes))
@@ -768,7 +770,7 @@ static int ov01a1s_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 
 	mutex_lock(&ov01a1s->mutex);
 	ov01a1s_update_pad_format(&supported_modes[0],
-				  v4l2_subdev_get_try_format(sd, fh->pad, 0));
+				  v4l2_subdev_get_try_format(sd, fh->state, 0));
 	mutex_unlock(&ov01a1s->mutex);
 
 	return 0;
@@ -835,11 +837,20 @@ static int ov01a1s_probe(struct i2c_client *client)
 {
 	struct ov01a1s *ov01a1s;
 	int ret = 0;
-
-	if (power_ctrl_logic_set_power(1)) {
-		dev_dbg(&client->dev, "power control driver not ready.\n");
+	struct vsc_mipi_config conf;
+	struct vsc_camera_status status;
+	s64 link_freq;
+
+	conf.lane_num = OV01A1S_DATA_LANES;
+	/* frequency unit 100k */
+	conf.freq = OV01A1S_LINK_FREQ_400MHZ / 100000;
+	ret = vsc_acquire_camera_sensor(&conf, NULL, NULL, &status);
+	if (ret == -EAGAIN)
+		ret = power_ctrl_logic_set_power(1);
+	if (ret == -EAGAIN)
 		return -EPROBE_DEFER;
-	}
+	else if (ret)
+		return ret;
 	ov01a1s = devm_kzalloc(&client->dev, sizeof(*ov01a1s), GFP_KERNEL);
 	if (!ov01a1s) {
 		ret = -ENOMEM;
@@ -879,6 +890,7 @@ static int ov01a1s_probe(struct i2c_client *client)
 		goto probe_error_media_entity_cleanup;
 	}
 
+	vsc_release_camera_sensor(&status);
 	/*
 	 * Device is already turned on by i2c-core with ACPI domain PM.
 	 * Enable runtime PM and turn off the device.
@@ -899,6 +911,7 @@ static int ov01a1s_probe(struct i2c_client *client)
 
 probe_error_ret:
 	power_ctrl_logic_set_power(0);
+	vsc_release_camera_sensor(&status);
 	return ret;
 }
 
diff --git a/drivers/media/i2c/power_ctrl_logic.c b/drivers/media/i2c/power_ctrl_logic.c
index 1ccd94f9e97e..90ee1e23d6ea 100644
--- a/drivers/media/i2c/power_ctrl_logic.c
+++ b/drivers/media/i2c/power_ctrl_logic.c
@@ -126,7 +126,7 @@ int power_ctrl_logic_set_power(int on)
 		pr_debug("@%s,failed to set power, gpio_ready=%d, on=%d\n",
 			 __func__, pcl.gpio_ready, on);
 		mutex_unlock(&pcl.status_lock);
-		return -EPROBE_DEFER;
+		return -EAGAIN;
 	}
 	if (pcl.power_on != on) {
 		gpiod_set_value_cansleep(pcl.reset_gpio, on);
diff --git a/drivers/media/pci/intel/Kconfig b/drivers/media/pci/intel/Kconfig
index defdca369fb5..ee4a77acb66f 100644
--- a/drivers/media/pci/intel/Kconfig
+++ b/drivers/media/pci/intel/Kconfig
@@ -3,10 +3,9 @@ config VIDEO_INTEL_IPU6
 	depends on ACPI
 	depends on MEDIA_SUPPORT
 	depends on MEDIA_PCI_SUPPORT
-	depends on X86_64
 	select IOMMU_API
 	select IOMMU_IOVA
-	select X86_DEV_DMA_OPS
+	select X86_DEV_DMA_OPS if X86
 	select VIDEOBUF2_DMA_CONTIG
 	select V4L2_FWNODE
 	select PHYS_ADDR_T_64BIT
diff --git a/drivers/media/pci/intel/ipu-buttress.c b/drivers/media/pci/intel/ipu-buttress.c
index eac4a43ed7b1..bf0b7916b381 100644
--- a/drivers/media/pci/intel/ipu-buttress.c
+++ b/drivers/media/pci/intel/ipu-buttress.c
@@ -893,7 +893,6 @@ int ipu_buttress_authenticate(struct ipu_device *isp)
 
 	return rval;
 }
-EXPORT_SYMBOL(ipu_buttress_authenticate);
 
 static int ipu_buttress_send_tsc_request(struct ipu_device *isp)
 {
@@ -963,50 +962,25 @@ struct clk_ipu_sensor {
 
 int ipu_buttress_tsc_read(struct ipu_device *isp, u64 *val)
 {
-	struct ipu_buttress *b = &isp->buttress;
-	u32 tsc_hi, tsc_lo_1, tsc_lo_2, tsc_lo_3, tsc_chk = 0;
+	u32 tsc_hi_1, tsc_hi_2, tsc_lo;
 	unsigned long flags;
-	short retry = IPU_BUTTRESS_TSC_RETRY;
-
-	do {
-		spin_lock_irqsave(&b->tsc_lock, flags);
-		tsc_hi = readl(isp->base + BUTTRESS_REG_TSC_HI);
-
-		/*
-		 * We are occasionally getting broken values from
-		 * HH. Reading 3 times and doing sanity check as a WA
-		 */
-		tsc_lo_1 = readl(isp->base + BUTTRESS_REG_TSC_LO);
-		tsc_lo_2 = readl(isp->base + BUTTRESS_REG_TSC_LO);
-		tsc_lo_3 = readl(isp->base + BUTTRESS_REG_TSC_LO);
-		tsc_chk = readl(isp->base + BUTTRESS_REG_TSC_HI);
-		spin_unlock_irqrestore(&b->tsc_lock, flags);
-		if (tsc_chk == tsc_hi && tsc_lo_2 &&
-		    tsc_lo_2 - tsc_lo_1 <= IPU_BUTTRESS_TSC_LIMIT &&
-		    tsc_lo_3 - tsc_lo_2 <= IPU_BUTTRESS_TSC_LIMIT) {
-			*val = (u64)tsc_hi << 32 | tsc_lo_2;
-			return 0;
-		}
 
-		/*
-		 * Trace error only if limit checkings fails at least
-		 *  by two consecutive readings.
-		 */
-		if (retry < IPU_BUTTRESS_TSC_RETRY - 1 && tsc_lo_2)
-			dev_err(&isp->pdev->dev,
-				"%s = %u, %s = %u, %s = %u, %s = %u, %s = %u",
-				"failure: tsc_hi", tsc_hi,
-				"tsc_chk", tsc_chk,
-				"tsc_lo_1", tsc_lo_1,
-				"tsc_lo_2", tsc_lo_2, "tsc_lo_3", tsc_lo_3);
-	} while (retry--);
-
-	if (!tsc_chk && !tsc_lo_2)
-		return -EIO;
-
-	WARN_ON_ONCE(1);
+	local_irq_save(flags);
+	tsc_hi_1 = readl(isp->base + BUTTRESS_REG_TSC_HI);
+	tsc_lo = readl(isp->base + BUTTRESS_REG_TSC_LO);
+	tsc_hi_2 = readl(isp->base + BUTTRESS_REG_TSC_HI);
+	if (tsc_hi_1 == tsc_hi_2) {
+		*val = (u64)tsc_hi_1 << 32 | tsc_lo;
+	} else {
+		/* Check if TSC has rolled over */
+		if (tsc_lo & BIT(31))
+			*val = (u64)tsc_hi_1 << 32 | tsc_lo;
+		else
+			*val = (u64)tsc_hi_2 << 32 | tsc_lo;
+	}
+	local_irq_restore(flags);
 
-	return -EINVAL;
+	return 0;
 }
 EXPORT_SYMBOL_GPL(ipu_buttress_tsc_read);
 
@@ -1299,7 +1273,6 @@ int ipu_buttress_init(struct ipu_device *isp)
 	mutex_init(&b->auth_mutex);
 	mutex_init(&b->cons_mutex);
 	mutex_init(&b->ipc_mutex);
-	spin_lock_init(&b->tsc_lock);
 	init_completion(&b->ish.send_complete);
 	init_completion(&b->cse.send_complete);
 	init_completion(&b->ish.recv_complete);
diff --git a/drivers/media/pci/intel/ipu-buttress.h b/drivers/media/pci/intel/ipu-buttress.h
index e1d054c3cd07..b57f4aaffa57 100644
--- a/drivers/media/pci/intel/ipu-buttress.h
+++ b/drivers/media/pci/intel/ipu-buttress.h
@@ -58,7 +58,6 @@ struct ipu_buttress_ipc {
 
 struct ipu_buttress {
 	struct mutex power_mutex, auth_mutex, cons_mutex, ipc_mutex;
-	spinlock_t tsc_lock;	/* tsc lock */
 	struct ipu_buttress_ipc cse;
 	struct ipu_buttress_ipc ish;
 	struct list_head constraints;
diff --git a/drivers/media/pci/intel/ipu-isys-csi2-be-soc.c b/drivers/media/pci/intel/ipu-isys-csi2-be-soc.c
index daaed97d1b13..7072500d930a 100644
--- a/drivers/media/pci/intel/ipu-isys-csi2-be-soc.c
+++ b/drivers/media/pci/intel/ipu-isys-csi2-be-soc.c
@@ -116,7 +116,7 @@ __subdev_link_validate(struct v4l2_subdev *sd, struct media_link *link,
 
 static int
 ipu_isys_csi2_be_soc_set_sel(struct v4l2_subdev *sd,
-			     struct v4l2_subdev_pad_config *cfg,
+			     struct v4l2_subdev_state *sd_state,
 			     struct v4l2_subdev_selection *sel)
 {
 	struct ipu_isys_subdev *asd = to_ipu_isys_subdev(sd);
@@ -128,7 +128,7 @@ ipu_isys_csi2_be_soc_set_sel(struct v4l2_subdev *sd,
 		enum isys_subdev_prop_tgt tgt =
 		    IPU_ISYS_SUBDEV_PROP_TGT_SOURCE_CROP;
 		struct v4l2_mbus_framefmt *ffmt =
-			__ipu_isys_get_ffmt(sd, cfg, sel->pad, sel->which);
+			__ipu_isys_get_ffmt(sd, sd_state, sel->pad, sel->which);
 
 		if (get_supported_code_index(ffmt->code) < 0) {
 			/* Non-bayer formats can't be odd lines cropped */
@@ -142,9 +142,9 @@ ipu_isys_csi2_be_soc_set_sel(struct v4l2_subdev *sd,
 		sel->r.height = clamp(sel->r.height, IPU_ISYS_MIN_HEIGHT,
 				      IPU_ISYS_MAX_HEIGHT);
 
-		*__ipu_isys_get_selection(sd, cfg, sel->target, sel->pad,
+		*__ipu_isys_get_selection(sd, sd_state, sel->target, sel->pad,
 					  sel->which) = sel->r;
-		ipu_isys_subdev_fmt_propagate(sd, cfg, NULL, &sel->r,
+		ipu_isys_subdev_fmt_propagate(sd, sd_state, NULL, &sel->r,
 					      tgt, sel->pad, sel->which);
 		return 0;
 	}
@@ -171,11 +171,11 @@ static struct media_entity_operations csi2_be_soc_entity_ops = {
 };
 
 static void csi2_be_soc_set_ffmt(struct v4l2_subdev *sd,
-				 struct v4l2_subdev_pad_config *cfg,
+				 struct v4l2_subdev_state *sd_state,
 				 struct v4l2_subdev_format *fmt)
 {
 	struct v4l2_mbus_framefmt *ffmt =
-		__ipu_isys_get_ffmt(sd, cfg, fmt->pad,
+		__ipu_isys_get_ffmt(sd, sd_state, fmt->pad,
 				    fmt->which);
 
 	if (sd->entity.pads[fmt->pad].flags & MEDIA_PAD_FL_SINK) {
@@ -183,19 +183,19 @@ static void csi2_be_soc_set_ffmt(struct v4l2_subdev *sd,
 			fmt->format.field = V4L2_FIELD_NONE;
 		*ffmt = fmt->format;
 
-		ipu_isys_subdev_fmt_propagate(sd, cfg, &fmt->format,
+		ipu_isys_subdev_fmt_propagate(sd, sd_state, &fmt->format,
 					      NULL,
 					      IPU_ISYS_SUBDEV_PROP_TGT_SINK_FMT,
 					      fmt->pad, fmt->which);
 	} else if (sd->entity.pads[fmt->pad].flags & MEDIA_PAD_FL_SOURCE) {
 		struct v4l2_mbus_framefmt *sink_ffmt;
-		struct v4l2_rect *r = __ipu_isys_get_selection(sd, cfg,
+		struct v4l2_rect *r = __ipu_isys_get_selection(sd, sd_state,
 			V4L2_SEL_TGT_CROP, fmt->pad, fmt->which);
 		struct ipu_isys_subdev *asd = to_ipu_isys_subdev(sd);
 		u32 code;
 		int idx;
 
-		sink_ffmt = __ipu_isys_get_ffmt(sd, cfg, 0, fmt->which);
+		sink_ffmt = __ipu_isys_get_ffmt(sd, sd_state, 0, fmt->which);
 		code = sink_ffmt->code;
 		idx = get_supported_code_index(code);
 
diff --git a/drivers/media/pci/intel/ipu-isys-csi2-be.c b/drivers/media/pci/intel/ipu-isys-csi2-be.c
new file mode 100644
index 000000000000..1ef87fe3dee8
--- /dev/null
+++ b/drivers/media/pci/intel/ipu-isys-csi2-be.c
@@ -0,0 +1,325 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2014 - 2020 Intel Corporation
+
+#include <linux/device.h>
+#include <linux/module.h>
+
+#include <media/ipu-isys.h>
+#include <media/media-entity.h>
+#include <media/v4l2-device.h>
+
+#include "ipu.h"
+#include "ipu-bus.h"
+#include "ipu-isys.h"
+#include "ipu-isys-csi2-be.h"
+#include "ipu-isys-subdev.h"
+#include "ipu-isys-video.h"
+
+/*
+ * Raw bayer format pixel order MUST BE MAINTAINED in groups of four codes.
+ * Otherwise pixel order calculation below WILL BREAK!
+ */
+static const u32 csi2_be_supported_codes_pad[] = {
+	MEDIA_BUS_FMT_SBGGR12_1X12,
+	MEDIA_BUS_FMT_SGBRG12_1X12,
+	MEDIA_BUS_FMT_SGRBG12_1X12,
+	MEDIA_BUS_FMT_SRGGB12_1X12,
+	MEDIA_BUS_FMT_SBGGR10_1X10,
+	MEDIA_BUS_FMT_SGBRG10_1X10,
+	MEDIA_BUS_FMT_SGRBG10_1X10,
+	MEDIA_BUS_FMT_SRGGB10_1X10,
+	MEDIA_BUS_FMT_SBGGR8_1X8,
+	MEDIA_BUS_FMT_SGBRG8_1X8,
+	MEDIA_BUS_FMT_SGRBG8_1X8,
+	MEDIA_BUS_FMT_SRGGB8_1X8,
+	0,
+};
+
+static const u32 *csi2_be_supported_codes[] = {
+	csi2_be_supported_codes_pad,
+	csi2_be_supported_codes_pad,
+};
+
+static struct v4l2_subdev_internal_ops csi2_be_sd_internal_ops = {
+	.open = ipu_isys_subdev_open,
+	.close = ipu_isys_subdev_close,
+};
+
+static const struct v4l2_subdev_core_ops csi2_be_sd_core_ops = {
+};
+
+static const struct v4l2_ctrl_config compression_ctrl_cfg = {
+	.ops = NULL,
+	.id = V4L2_CID_IPU_ISYS_COMPRESSION,
+	.name = "ISYS CSI-BE compression",
+	.type = V4L2_CTRL_TYPE_BOOLEAN,
+	.min = 0,
+	.max = 1,
+	.step = 1,
+	.def = 0,
+};
+
+static int set_stream(struct v4l2_subdev *sd, int enable)
+{
+	return 0;
+}
+
+static const struct v4l2_subdev_video_ops csi2_be_sd_video_ops = {
+	.s_stream = set_stream,
+};
+
+static int __subdev_link_validate(struct v4l2_subdev *sd,
+				  struct media_link *link,
+				  struct v4l2_subdev_format *source_fmt,
+				  struct v4l2_subdev_format *sink_fmt)
+{
+	struct ipu_isys_pipeline *ip = container_of(sd->entity.pipe,
+						    struct ipu_isys_pipeline,
+						    pipe);
+
+	ip->csi2_be = to_ipu_isys_csi2_be(sd);
+	return ipu_isys_subdev_link_validate(sd, link, source_fmt, sink_fmt);
+}
+
+static int get_supported_code_index(u32 code)
+{
+	int i;
+
+	for (i = 0; csi2_be_supported_codes_pad[i]; i++) {
+		if (csi2_be_supported_codes_pad[i] == code)
+			return i;
+	}
+	return -EINVAL;
+}
+
+static int ipu_isys_csi2_be_set_sel(struct v4l2_subdev *sd,
+				    struct v4l2_subdev_state *sd_state,
+				    struct v4l2_subdev_selection *sel)
+{
+	struct ipu_isys_subdev *asd = to_ipu_isys_subdev(sd);
+	struct media_pad *pad = &asd->sd.entity.pads[sel->pad];
+
+	if (sel->target == V4L2_SEL_TGT_CROP &&
+	    pad->flags & MEDIA_PAD_FL_SOURCE &&
+	    asd->valid_tgts[CSI2_BE_PAD_SOURCE].crop) {
+		struct v4l2_mbus_framefmt *ffmt =
+			__ipu_isys_get_ffmt(sd, sd_state, sel->pad, sel->which);
+		struct v4l2_rect *r = __ipu_isys_get_selection
+		    (sd, sd_state, sel->target, CSI2_BE_PAD_SINK, sel->which);
+
+		if (get_supported_code_index(ffmt->code) < 0) {
+			/* Non-bayer formats can't be single line cropped */
+			sel->r.left &= ~1;
+			sel->r.top &= ~1;
+
+			/* Non-bayer formats can't pe padded at all */
+			sel->r.width = clamp(sel->r.width,
+					     IPU_ISYS_MIN_WIDTH, r->width);
+		} else {
+			sel->r.width = clamp(sel->r.width,
+					     IPU_ISYS_MIN_WIDTH,
+					     IPU_ISYS_MAX_WIDTH);
+		}
+
+		/*
+		 * Vertical padding is not supported, height is
+		 * restricted by sink pad resolution.
+		 */
+		sel->r.height = clamp(sel->r.height, IPU_ISYS_MIN_HEIGHT,
+				      r->height);
+		*__ipu_isys_get_selection(sd, sd_state, sel->target,
+					sel->pad, sel->which) = sel->r;
+		ipu_isys_subdev_fmt_propagate
+		    (sd, sd_state, NULL, &sel->r,
+		     IPU_ISYS_SUBDEV_PROP_TGT_SOURCE_CROP,
+		     sel->pad, sel->which);
+		return 0;
+	}
+	return ipu_isys_subdev_set_sel(sd, sd_state, sel);
+}
+
+static const struct v4l2_subdev_pad_ops csi2_be_sd_pad_ops = {
+	.link_validate = __subdev_link_validate,
+	.get_fmt = ipu_isys_subdev_get_ffmt,
+	.set_fmt = ipu_isys_subdev_set_ffmt,
+	.get_selection = ipu_isys_subdev_get_sel,
+	.set_selection = ipu_isys_csi2_be_set_sel,
+	.enum_mbus_code = ipu_isys_subdev_enum_mbus_code,
+};
+
+static struct v4l2_subdev_ops csi2_be_sd_ops = {
+	.core = &csi2_be_sd_core_ops,
+	.video = &csi2_be_sd_video_ops,
+	.pad = &csi2_be_sd_pad_ops,
+};
+
+static struct media_entity_operations csi2_be_entity_ops = {
+	.link_validate = v4l2_subdev_link_validate,
+};
+
+static void csi2_be_set_ffmt(struct v4l2_subdev *sd,
+			     struct v4l2_subdev_state *sd_state,
+			     struct v4l2_subdev_format *fmt)
+{
+	struct ipu_isys_csi2 *csi2 = to_ipu_isys_csi2(sd);
+	struct v4l2_mbus_framefmt *ffmt =
+		__ipu_isys_get_ffmt(sd, sd_state, fmt->pad, fmt->which);
+
+	switch (fmt->pad) {
+	case CSI2_BE_PAD_SINK:
+		if (fmt->format.field != V4L2_FIELD_ALTERNATE)
+			fmt->format.field = V4L2_FIELD_NONE;
+		*ffmt = fmt->format;
+
+		ipu_isys_subdev_fmt_propagate
+		    (sd, sd_state, &fmt->format, NULL,
+		     IPU_ISYS_SUBDEV_PROP_TGT_SINK_FMT, fmt->pad, fmt->which);
+		return;
+	case CSI2_BE_PAD_SOURCE: {
+		struct v4l2_mbus_framefmt *sink_ffmt =
+			__ipu_isys_get_ffmt(sd, sd_state, CSI2_BE_PAD_SINK,
+					    fmt->which);
+		struct v4l2_rect *r =
+			__ipu_isys_get_selection(sd, sd_state, V4L2_SEL_TGT_CROP,
+						 CSI2_BE_PAD_SOURCE,
+						 fmt->which);
+		struct ipu_isys_subdev *asd = to_ipu_isys_subdev(sd);
+		u32 code = sink_ffmt->code;
+		int idx = get_supported_code_index(code);
+
+		if (asd->valid_tgts[CSI2_BE_PAD_SOURCE].crop && idx >= 0) {
+			int crop_info = 0;
+
+			if (r->top & 1)
+				crop_info |= CSI2_BE_CROP_VER;
+			if (r->left & 1)
+				crop_info |= CSI2_BE_CROP_HOR;
+			code = csi2_be_supported_codes_pad
+				[((idx & CSI2_BE_CROP_MASK) ^ crop_info)
+				+ (idx & ~CSI2_BE_CROP_MASK)];
+		}
+		ffmt->width = r->width;
+		ffmt->height = r->height;
+		ffmt->code = code;
+		ffmt->field = sink_ffmt->field;
+		return;
+	}
+	default:
+		dev_err(&csi2->isys->adev->dev, "Unknown pad type\n");
+		WARN_ON(1);
+	}
+}
+
+void ipu_isys_csi2_be_cleanup(struct ipu_isys_csi2_be *csi2_be)
+{
+	v4l2_ctrl_handler_free(&csi2_be->av.ctrl_handler);
+	v4l2_device_unregister_subdev(&csi2_be->asd.sd);
+	ipu_isys_subdev_cleanup(&csi2_be->asd);
+	ipu_isys_video_cleanup(&csi2_be->av);
+}
+
+int ipu_isys_csi2_be_init(struct ipu_isys_csi2_be *csi2_be,
+			  struct ipu_isys *isys)
+{
+	struct v4l2_subdev_format fmt = {
+		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
+		.pad = CSI2_BE_PAD_SINK,
+		.format = {
+			   .width = 4096,
+			   .height = 3072,
+			  },
+	};
+	struct v4l2_subdev_selection sel = {
+		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
+		.pad = CSI2_BE_PAD_SOURCE,
+		.target = V4L2_SEL_TGT_CROP,
+		.r = {
+		      .width = fmt.format.width,
+		      .height = fmt.format.height,
+		     },
+	};
+	int rval;
+
+	csi2_be->asd.sd.entity.ops = &csi2_be_entity_ops;
+	csi2_be->asd.isys = isys;
+
+	rval = ipu_isys_subdev_init(&csi2_be->asd, &csi2_be_sd_ops, 0,
+				    NR_OF_CSI2_BE_PADS,
+				    NR_OF_CSI2_BE_SOURCE_PADS,
+				    NR_OF_CSI2_BE_SINK_PADS, 0);
+	if (rval)
+		goto fail;
+
+	csi2_be->asd.pad[CSI2_BE_PAD_SINK].flags = MEDIA_PAD_FL_SINK
+	    | MEDIA_PAD_FL_MUST_CONNECT;
+	csi2_be->asd.pad[CSI2_BE_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+	csi2_be->asd.valid_tgts[CSI2_BE_PAD_SOURCE].crop = true;
+	csi2_be->asd.set_ffmt = csi2_be_set_ffmt;
+
+	BUILD_BUG_ON(ARRAY_SIZE(csi2_be_supported_codes) != NR_OF_CSI2_BE_PADS);
+	csi2_be->asd.supported_codes = csi2_be_supported_codes;
+	csi2_be->asd.be_mode = IPU_BE_RAW;
+	csi2_be->asd.isl_mode = IPU_ISL_CSI2_BE;
+
+	ipu_isys_subdev_set_ffmt(&csi2_be->asd.sd, NULL, &fmt);
+	ipu_isys_csi2_be_set_sel(&csi2_be->asd.sd, NULL, &sel);
+
+	csi2_be->asd.sd.internal_ops = &csi2_be_sd_internal_ops;
+	snprintf(csi2_be->asd.sd.name, sizeof(csi2_be->asd.sd.name),
+		 IPU_ISYS_ENTITY_PREFIX " CSI2 BE");
+	snprintf(csi2_be->av.vdev.name, sizeof(csi2_be->av.vdev.name),
+		 IPU_ISYS_ENTITY_PREFIX " CSI2 BE capture");
+	csi2_be->av.aq.css_pin_type = IPU_FW_ISYS_PIN_TYPE_RAW_NS;
+	v4l2_set_subdevdata(&csi2_be->asd.sd, &csi2_be->asd);
+	rval = v4l2_device_register_subdev(&isys->v4l2_dev, &csi2_be->asd.sd);
+	if (rval) {
+		dev_info(&isys->adev->dev, "can't register v4l2 subdev\n");
+		goto fail;
+	}
+
+	csi2_be->av.isys = isys;
+	csi2_be->av.pfmts = ipu_isys_pfmts;
+	csi2_be->av.try_fmt_vid_mplane =
+	    ipu_isys_video_try_fmt_vid_mplane_default;
+	csi2_be->av.prepare_fw_stream =
+	    ipu_isys_prepare_fw_cfg_default;
+	csi2_be->av.aq.buf_prepare = ipu_isys_buf_prepare;
+	csi2_be->av.aq.fill_frame_buff_set_pin =
+	    ipu_isys_buffer_to_fw_frame_buff_pin;
+	csi2_be->av.aq.link_fmt_validate = ipu_isys_link_fmt_validate;
+	csi2_be->av.aq.vbq.buf_struct_size =
+	    sizeof(struct ipu_isys_video_buffer);
+
+	/* create v4l2 ctrl for csi-be video node */
+	rval = v4l2_ctrl_handler_init(&csi2_be->av.ctrl_handler, 0);
+	if (rval) {
+		dev_err(&isys->adev->dev,
+			"failed to init v4l2 ctrl handler for csi2_be\n");
+		goto fail;
+	}
+
+	csi2_be->av.compression_ctrl =
+		v4l2_ctrl_new_custom(&csi2_be->av.ctrl_handler,
+				     &compression_ctrl_cfg, NULL);
+	if (!csi2_be->av.compression_ctrl) {
+		dev_err(&isys->adev->dev,
+			"failed to create CSI-BE cmprs ctrl\n");
+		goto fail;
+	}
+	csi2_be->av.compression = 0;
+	csi2_be->av.vdev.ctrl_handler = &csi2_be->av.ctrl_handler;
+
+	rval = ipu_isys_video_init(&csi2_be->av, &csi2_be->asd.sd.entity,
+				   CSI2_BE_PAD_SOURCE, MEDIA_PAD_FL_SINK, 0);
+	if (rval) {
+		dev_info(&isys->adev->dev, "can't init video node\n");
+		goto fail;
+	}
+
+	return 0;
+
+fail:
+	ipu_isys_csi2_be_cleanup(csi2_be);
+
+	return rval;
+}
diff --git a/drivers/media/pci/intel/ipu-isys-csi2.c b/drivers/media/pci/intel/ipu-isys-csi2.c
index 1242a79718b1..e206200b6f4d 100644
--- a/drivers/media/pci/intel/ipu-isys-csi2.c
+++ b/drivers/media/pci/intel/ipu-isys-csi2.c
@@ -1,9 +1,10 @@
 // SPDX-License-Identifier: GPL-2.0
-// Copyright (C) 2013 - 2020 Intel Corporation
+// Copyright (C) 2013 - 2021 Intel Corporation
 
 #include <linux/device.h>
 #include <linux/module.h>
 #include <linux/version.h>
+#include <linux/vsc.h>
 
 #include <media/ipu-isys.h>
 #include <media/media-entity.h>
@@ -224,6 +225,9 @@ static int set_stream(struct v4l2_subdev *sd, int enable)
 	struct ipu_isys_csi2_timing timing = {0};
 	unsigned int nlanes;
 	int rval;
+	struct vsc_mipi_config conf;
+	struct vsc_camera_status status;
+	s64 link_freq;
 
 	dev_dbg(&csi2->isys->adev->dev, "csi2 s_stream %d\n", enable);
 
@@ -236,6 +240,12 @@ static int set_stream(struct v4l2_subdev *sd, int enable)
 
 	if (!enable) {
 		ipu_isys_csi2_set_stream(sd, timing, 0, enable);
+		rval = vsc_release_camera_sensor(&status);
+		if (rval && rval != -EAGAIN) {
+			dev_err(&csi2->isys->adev->dev,
+				"Release VSC failed.\n");
+			return rval;
+		}
 		return 0;
 	}
 
@@ -250,6 +260,20 @@ static int set_stream(struct v4l2_subdev *sd, int enable)
 		return rval;
 
 	rval = ipu_isys_csi2_set_stream(sd, timing, nlanes, enable);
+	rval = ipu_isys_csi2_get_link_freq(csi2, &link_freq);
+	if (rval)
+		return rval;
+
+	conf.lane_num = nlanes;
+	/* frequency unit 100k */
+	conf.freq = link_freq / 100000;
+	rval = vsc_acquire_camera_sensor(&conf, NULL, NULL, &status);
+	if (rval && rval != -EAGAIN) {
+		dev_err(&csi2->isys->adev->dev, "Acquire VSC failed.\n");
+		return rval;
+	} else {
+		return 0;
+	}
 
 	return rval;
 }
@@ -314,17 +338,17 @@ static const struct v4l2_subdev_video_ops csi2_sd_video_ops = {
 };
 
 static int ipu_isys_csi2_get_fmt(struct v4l2_subdev *sd,
-				 struct v4l2_subdev_pad_config *cfg,
+				 struct v4l2_subdev_state *sd_state,
 				 struct v4l2_subdev_format *fmt)
 {
-	return ipu_isys_subdev_get_ffmt(sd, cfg, fmt);
+	return ipu_isys_subdev_get_ffmt(sd, sd_state, fmt);
 }
 
 static int ipu_isys_csi2_set_fmt(struct v4l2_subdev *sd,
-				 struct v4l2_subdev_pad_config *cfg,
+				 struct v4l2_subdev_state *sd_state,
 				 struct v4l2_subdev_format *fmt)
 {
-	return ipu_isys_subdev_set_ffmt(sd, cfg, fmt);
+	return ipu_isys_subdev_set_ffmt(sd, sd_state, fmt);
 }
 
 static int __subdev_link_validate(struct v4l2_subdev *sd,
@@ -360,12 +384,12 @@ static struct media_entity_operations csi2_entity_ops = {
 };
 
 static void csi2_set_ffmt(struct v4l2_subdev *sd,
-			  struct v4l2_subdev_pad_config *cfg,
+			  struct v4l2_subdev_state *sd_state,
 			  struct v4l2_subdev_format *fmt)
 {
 	enum isys_subdev_prop_tgt tgt = IPU_ISYS_SUBDEV_PROP_TGT_SINK_FMT;
 	struct v4l2_mbus_framefmt *ffmt =
-		__ipu_isys_get_ffmt(sd, cfg, fmt->pad,
+		__ipu_isys_get_ffmt(sd, sd_state, fmt->pad,
 				    fmt->which);
 
 	if (fmt->format.field != V4L2_FIELD_ALTERNATE)
@@ -373,7 +397,7 @@ static void csi2_set_ffmt(struct v4l2_subdev *sd,
 
 	if (fmt->pad == CSI2_PAD_SINK) {
 		*ffmt = fmt->format;
-		ipu_isys_subdev_fmt_propagate(sd, cfg, &fmt->format, NULL,
+		ipu_isys_subdev_fmt_propagate(sd, sd_state, &fmt->format, NULL,
 					      tgt, fmt->pad, fmt->which);
 		return;
 	}
diff --git a/drivers/media/pci/intel/ipu-isys-subdev.c b/drivers/media/pci/intel/ipu-isys-subdev.c
index 71a5fa592d44..7f00fa817252 100644
--- a/drivers/media/pci/intel/ipu-isys-subdev.c
+++ b/drivers/media/pci/intel/ipu-isys-subdev.c
@@ -134,8 +134,7 @@ u32 ipu_isys_subdev_code_to_uncompressed(u32 sink_code)
 }
 
 struct v4l2_mbus_framefmt *__ipu_isys_get_ffmt(struct v4l2_subdev *sd,
-					       struct v4l2_subdev_pad_config
-					       *cfg,
+					       struct v4l2_subdev_state *sd_state,
 					       unsigned int pad,
 					       unsigned int which)
 {
@@ -144,11 +143,11 @@ struct v4l2_mbus_framefmt *__ipu_isys_get_ffmt(struct v4l2_subdev *sd,
 	if (which == V4L2_SUBDEV_FORMAT_ACTIVE)
 		return &asd->ffmt[pad];
 	else
-		return v4l2_subdev_get_try_format(sd, cfg, pad);
+		return v4l2_subdev_get_try_format(sd, sd_state, pad);
 }
 
 struct v4l2_rect *__ipu_isys_get_selection(struct v4l2_subdev *sd,
-					   struct v4l2_subdev_pad_config *cfg,
+					   struct v4l2_subdev_state *sd_state,
 					   unsigned int target,
 					   unsigned int pad, unsigned int which)
 {
@@ -164,9 +163,9 @@ struct v4l2_rect *__ipu_isys_get_selection(struct v4l2_subdev *sd,
 	} else {
 		switch (target) {
 		case V4L2_SEL_TGT_CROP:
-			return v4l2_subdev_get_try_crop(sd, cfg, pad);
+			return v4l2_subdev_get_try_crop(sd, sd_state, pad);
 		case V4L2_SEL_TGT_COMPOSE:
-			return v4l2_subdev_get_try_compose(sd, cfg, pad);
+			return v4l2_subdev_get_try_compose(sd, sd_state, pad);
 		}
 	}
 	WARN_ON(1);
@@ -189,7 +188,7 @@ static int target_valid(struct v4l2_subdev *sd, unsigned int target,
 }
 
 int ipu_isys_subdev_fmt_propagate(struct v4l2_subdev *sd,
-				  struct v4l2_subdev_pad_config *cfg,
+				  struct v4l2_subdev_state *sd_state,
 				  struct v4l2_mbus_framefmt *ffmt,
 				  struct v4l2_rect *r,
 				  enum isys_subdev_prop_tgt tgt,
@@ -228,12 +227,11 @@ int ipu_isys_subdev_fmt_propagate(struct v4l2_subdev *sd,
 	}
 
 	for (i = 0; i < sd->entity.num_pads; i++) {
-		ffmts[i] = __ipu_isys_get_ffmt(sd, cfg, i, which);
-		crops[i] = __ipu_isys_get_selection(sd, cfg, V4L2_SEL_TGT_CROP,
-						    i, which);
-		compose[i] = __ipu_isys_get_selection(sd, cfg,
-						      V4L2_SEL_TGT_COMPOSE,
-						      i, which);
+		ffmts[i] = __ipu_isys_get_ffmt(sd, sd_state, i, which);
+		crops[i] = __ipu_isys_get_selection(sd, sd_state,
+						    V4L2_SEL_TGT_CROP, i, which);
+		compose[i] = __ipu_isys_get_selection(sd, sd_state,
+						      V4L2_SEL_TGT_COMPOSE, i, which);
 	}
 
 	switch (tgt) {
@@ -242,8 +240,8 @@ int ipu_isys_subdev_fmt_propagate(struct v4l2_subdev *sd,
 		crops[pad]->top = 0;
 		crops[pad]->width = ffmt->width;
 		crops[pad]->height = ffmt->height;
-		rval = ipu_isys_subdev_fmt_propagate(sd, cfg, ffmt, crops[pad],
-						     tgt + 1, pad, which);
+		rval = ipu_isys_subdev_fmt_propagate(sd, sd_state, ffmt,
+						     crops[pad], tgt + 1, pad, which);
 		goto out_subdev_fmt_propagate;
 	case IPU_ISYS_SUBDEV_PROP_TGT_SINK_CROP:
 		if (WARN_ON(sd->entity.pads[pad].flags & MEDIA_PAD_FL_SOURCE))
@@ -253,9 +251,8 @@ int ipu_isys_subdev_fmt_propagate(struct v4l2_subdev *sd,
 		compose[pad]->top = 0;
 		compose[pad]->width = r->width;
 		compose[pad]->height = r->height;
-		rval = ipu_isys_subdev_fmt_propagate(sd, cfg, ffmt,
-						     compose[pad], tgt + 1,
-						     pad, which);
+		rval = ipu_isys_subdev_fmt_propagate(sd, sd_state, ffmt,
+						     compose[pad], tgt + 1, pad, which);
 		goto out_subdev_fmt_propagate;
 	case IPU_ISYS_SUBDEV_PROP_TGT_SINK_COMPOSE:
 		if (WARN_ON(sd->entity.pads[pad].flags & MEDIA_PAD_FL_SOURCE)) {
@@ -272,11 +269,8 @@ int ipu_isys_subdev_fmt_propagate(struct v4l2_subdev *sd,
 			compose[i]->top = 0;
 			compose[i]->width = r->width;
 			compose[i]->height = r->height;
-			rval = ipu_isys_subdev_fmt_propagate(sd, cfg,
-							     ffmt,
-							     compose[i],
-							     tgt + 1, i,
-							     which);
+			rval = ipu_isys_subdev_fmt_propagate(sd, sd_state,
+							ffmt, compose[i], tgt + 1, i, which);
 			if (rval)
 				goto out_subdev_fmt_propagate;
 		}
@@ -291,9 +285,8 @@ int ipu_isys_subdev_fmt_propagate(struct v4l2_subdev *sd,
 		crops[pad]->top = 0;
 		crops[pad]->width = r->width;
 		crops[pad]->height = r->height;
-		rval = ipu_isys_subdev_fmt_propagate(sd, cfg, ffmt,
-						     crops[pad], tgt + 1,
-						     pad, which);
+		rval = ipu_isys_subdev_fmt_propagate(sd, sd_state, ffmt,
+						     crops[pad], tgt + 1, pad, which);
 		goto out_subdev_fmt_propagate;
 	case IPU_ISYS_SUBDEV_PROP_TGT_SOURCE_CROP:{
 			struct v4l2_subdev_format fmt = {
@@ -313,7 +306,7 @@ int ipu_isys_subdev_fmt_propagate(struct v4l2_subdev *sd,
 				},
 			};
 
-			asd->set_ffmt(sd, cfg, &fmt);
+			asd->set_ffmt(sd, sd_state, &fmt);
 			goto out_subdev_fmt_propagate;
 		}
 	}
@@ -326,16 +319,16 @@ int ipu_isys_subdev_fmt_propagate(struct v4l2_subdev *sd,
 }
 
 int ipu_isys_subdev_set_ffmt_default(struct v4l2_subdev *sd,
-				     struct v4l2_subdev_pad_config *cfg,
+				     struct v4l2_subdev_state *sd_state,
 				     struct v4l2_subdev_format *fmt)
 {
 	struct v4l2_mbus_framefmt *ffmt =
-		__ipu_isys_get_ffmt(sd, cfg, fmt->pad, fmt->which);
+		__ipu_isys_get_ffmt(sd, sd_state, fmt->pad, fmt->which);
 
 	/* No propagation for non-zero pads. */
 	if (fmt->pad) {
 		struct v4l2_mbus_framefmt *sink_ffmt =
-			__ipu_isys_get_ffmt(sd, cfg, 0, fmt->which);
+			__ipu_isys_get_ffmt(sd, sd_state, 0, fmt->which);
 
 		ffmt->width = sink_ffmt->width;
 		ffmt->height = sink_ffmt->height;
@@ -350,18 +343,18 @@ int ipu_isys_subdev_set_ffmt_default(struct v4l2_subdev *sd,
 	ffmt->code = fmt->format.code;
 	ffmt->field = fmt->format.field;
 
-	return ipu_isys_subdev_fmt_propagate(sd, cfg, &fmt->format, NULL,
+	return ipu_isys_subdev_fmt_propagate(sd, sd_state, &fmt->format, NULL,
 					     IPU_ISYS_SUBDEV_PROP_TGT_SINK_FMT,
 					     fmt->pad, fmt->which);
 }
 
 int __ipu_isys_subdev_set_ffmt(struct v4l2_subdev *sd,
-			       struct v4l2_subdev_pad_config *cfg,
+			       struct v4l2_subdev_state *sd_state,
 			       struct v4l2_subdev_format *fmt)
 {
 	struct ipu_isys_subdev *asd = to_ipu_isys_subdev(sd);
 	struct v4l2_mbus_framefmt *ffmt =
-		__ipu_isys_get_ffmt(sd, cfg, fmt->pad, fmt->which);
+		__ipu_isys_get_ffmt(sd, sd_state, fmt->pad, fmt->which);
 	u32 code = asd->supported_codes[fmt->pad][0];
 	unsigned int i;
 
@@ -381,7 +374,7 @@ int __ipu_isys_subdev_set_ffmt(struct v4l2_subdev *sd,
 
 	fmt->format.code = code;
 
-	asd->set_ffmt(sd, cfg, fmt);
+	asd->set_ffmt(sd, sd_state, fmt);
 
 	fmt->format = *ffmt;
 
@@ -389,27 +382,27 @@ int __ipu_isys_subdev_set_ffmt(struct v4l2_subdev *sd,
 }
 
 int ipu_isys_subdev_set_ffmt(struct v4l2_subdev *sd,
-			     struct v4l2_subdev_pad_config *cfg,
+			     struct v4l2_subdev_state *sd_state,
 			     struct v4l2_subdev_format *fmt)
 {
 	struct ipu_isys_subdev *asd = to_ipu_isys_subdev(sd);
 	int rval;
 
 	mutex_lock(&asd->mutex);
-	rval = __ipu_isys_subdev_set_ffmt(sd, cfg, fmt);
+	rval = __ipu_isys_subdev_set_ffmt(sd, sd_state, fmt);
 	mutex_unlock(&asd->mutex);
 
 	return rval;
 }
 
 int ipu_isys_subdev_get_ffmt(struct v4l2_subdev *sd,
-			     struct v4l2_subdev_pad_config *cfg,
+			     struct v4l2_subdev_state *sd_state,
 			     struct v4l2_subdev_format *fmt)
 {
 	struct ipu_isys_subdev *asd = to_ipu_isys_subdev(sd);
 
 	mutex_lock(&asd->mutex);
-	fmt->format = *__ipu_isys_get_ffmt(sd, cfg, fmt->pad,
+	fmt->format = *__ipu_isys_get_ffmt(sd, sd_state, fmt->pad,
 					   fmt->which);
 	mutex_unlock(&asd->mutex);
 
@@ -417,7 +410,7 @@ int ipu_isys_subdev_get_ffmt(struct v4l2_subdev *sd,
 }
 
 int ipu_isys_subdev_set_sel(struct v4l2_subdev *sd,
-			    struct v4l2_subdev_pad_config *cfg,
+			    struct v4l2_subdev_state *sd_state,
 			    struct v4l2_subdev_selection *sel)
 {
 	struct ipu_isys_subdev *asd = to_ipu_isys_subdev(sd);
@@ -432,7 +425,7 @@ int ipu_isys_subdev_set_sel(struct v4l2_subdev *sd,
 	case V4L2_SEL_TGT_CROP:
 		if (pad->flags & MEDIA_PAD_FL_SINK) {
 			struct v4l2_mbus_framefmt *ffmt =
-				__ipu_isys_get_ffmt(sd, cfg, sel->pad,
+				__ipu_isys_get_ffmt(sd, sd_state, sel->pad,
 						    sel->which);
 
 			__r.width = ffmt->width;
@@ -441,7 +434,7 @@ int ipu_isys_subdev_set_sel(struct v4l2_subdev *sd,
 			tgt = IPU_ISYS_SUBDEV_PROP_TGT_SINK_CROP;
 		} else {
 			/* 0 is the sink pad. */
-			r = __ipu_isys_get_selection(sd, cfg, sel->target, 0,
+			r = __ipu_isys_get_selection(sd, sd_state, sel->target, 0,
 						     sel->which);
 			tgt = IPU_ISYS_SUBDEV_PROP_TGT_SOURCE_CROP;
 		}
@@ -449,11 +442,11 @@ int ipu_isys_subdev_set_sel(struct v4l2_subdev *sd,
 		break;
 	case V4L2_SEL_TGT_COMPOSE:
 		if (pad->flags & MEDIA_PAD_FL_SINK) {
-			r = __ipu_isys_get_selection(sd, cfg, V4L2_SEL_TGT_CROP,
+			r = __ipu_isys_get_selection(sd, sd_state, V4L2_SEL_TGT_CROP,
 						     sel->pad, sel->which);
 			tgt = IPU_ISYS_SUBDEV_PROP_TGT_SINK_COMPOSE;
 		} else {
-			r = __ipu_isys_get_selection(sd, cfg,
+			r = __ipu_isys_get_selection(sd, sd_state,
 						     V4L2_SEL_TGT_COMPOSE, 0,
 						     sel->which);
 			tgt = IPU_ISYS_SUBDEV_PROP_TGT_SOURCE_COMPOSE;
@@ -465,27 +458,27 @@ int ipu_isys_subdev_set_sel(struct v4l2_subdev *sd,
 
 	sel->r.width = clamp(sel->r.width, IPU_ISYS_MIN_WIDTH, r->width);
 	sel->r.height = clamp(sel->r.height, IPU_ISYS_MIN_HEIGHT, r->height);
-	*__ipu_isys_get_selection(sd, cfg, sel->target, sel->pad,
+	*__ipu_isys_get_selection(sd, sd_state, sel->target, sel->pad,
 				  sel->which) = sel->r;
-	return ipu_isys_subdev_fmt_propagate(sd, cfg, NULL, &sel->r, tgt,
+	return ipu_isys_subdev_fmt_propagate(sd, sd_state, NULL, &sel->r, tgt,
 					     sel->pad, sel->which);
 }
 
 int ipu_isys_subdev_get_sel(struct v4l2_subdev *sd,
-			    struct v4l2_subdev_pad_config *cfg,
+			    struct v4l2_subdev_state *sd_state,
 			    struct v4l2_subdev_selection *sel)
 {
 	if (!target_valid(sd, sel->target, sel->pad))
 		return -EINVAL;
 
-	sel->r = *__ipu_isys_get_selection(sd, cfg, sel->target,
+	sel->r = *__ipu_isys_get_selection(sd, sd_state, sel->target,
 					   sel->pad, sel->which);
 
 	return 0;
 }
 
 int ipu_isys_subdev_enum_mbus_code(struct v4l2_subdev *sd,
-				   struct v4l2_subdev_pad_config *cfg,
+				   struct v4l2_subdev_state *sd_state,
 				   struct v4l2_subdev_mbus_code_enum *code)
 {
 	struct ipu_isys_subdev *asd = to_ipu_isys_subdev(sd);
@@ -555,11 +548,11 @@ int ipu_isys_subdev_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 
 	for (i = 0; i < asd->sd.entity.num_pads; i++) {
 		struct v4l2_mbus_framefmt *try_fmt =
-			v4l2_subdev_get_try_format(sd, fh->pad, i);
+			v4l2_subdev_get_try_format(sd, fh->state, i);
 		struct v4l2_rect *try_crop =
-			v4l2_subdev_get_try_crop(sd, fh->pad, i);
+			v4l2_subdev_get_try_crop(sd, fh->state, i);
 		struct v4l2_rect *try_compose =
-			v4l2_subdev_get_try_compose(sd, fh->pad, i);
+			v4l2_subdev_get_try_compose(sd, fh->state, i);
 
 		*try_fmt = asd->ffmt[i];
 		*try_crop = asd->crop[i];
diff --git a/drivers/media/pci/intel/ipu-isys-subdev.h b/drivers/media/pci/intel/ipu-isys-subdev.h
index 35eb9d1d3cb7..053ac094642d 100644
--- a/drivers/media/pci/intel/ipu-isys-subdev.h
+++ b/drivers/media/pci/intel/ipu-isys-subdev.h
@@ -75,7 +75,7 @@ struct ipu_isys_subdev {
 	struct v4l2_ctrl_handler ctrl_handler;
 	void (*ctrl_init)(struct v4l2_subdev *sd);
 	void (*set_ffmt)(struct v4l2_subdev *sd,
-			 struct v4l2_subdev_pad_config *cfg,
+			 struct v4l2_subdev_state *sd_state,
 			 struct v4l2_subdev_format *fmt);
 	struct {
 		bool crop;
@@ -90,8 +90,7 @@ struct ipu_isys_subdev {
 	container_of(__sd, struct ipu_isys_subdev, sd)
 
 struct v4l2_mbus_framefmt *__ipu_isys_get_ffmt(struct v4l2_subdev *sd,
-					       struct v4l2_subdev_pad_config
-					       *cfg,
+					       struct v4l2_subdev_state *sd_state,
 					       unsigned int pad,
 					       unsigned int which);
 
@@ -102,37 +101,37 @@ u32 ipu_isys_subdev_code_to_uncompressed(u32 sink_code);
 enum ipu_isys_subdev_pixelorder ipu_isys_subdev_get_pixelorder(u32 code);
 
 int ipu_isys_subdev_fmt_propagate(struct v4l2_subdev *sd,
-				  struct v4l2_subdev_pad_config *cfg,
+				  struct v4l2_subdev_state *sd_state,
 				  struct v4l2_mbus_framefmt *ffmt,
 				  struct v4l2_rect *r,
 				  enum isys_subdev_prop_tgt tgt,
 				  unsigned int pad, unsigned int which);
 
 int ipu_isys_subdev_set_ffmt_default(struct v4l2_subdev *sd,
-				     struct v4l2_subdev_pad_config *cfg,
+				     struct v4l2_subdev_state *sd_state,
 				     struct v4l2_subdev_format *fmt);
 int __ipu_isys_subdev_set_ffmt(struct v4l2_subdev *sd,
-			       struct v4l2_subdev_pad_config *cfg,
+			       struct v4l2_subdev_state *sd_state,
 			       struct v4l2_subdev_format *fmt);
 struct v4l2_rect *__ipu_isys_get_selection(struct v4l2_subdev *sd,
-					   struct v4l2_subdev_pad_config *cfg,
+					   struct v4l2_subdev_state *sd_state,
 					   unsigned int target,
 					   unsigned int pad,
 					   unsigned int which);
 int ipu_isys_subdev_set_ffmt(struct v4l2_subdev *sd,
-			     struct v4l2_subdev_pad_config *cfg,
+			     struct v4l2_subdev_state *sd_state,
 			     struct v4l2_subdev_format *fmt);
 int ipu_isys_subdev_get_ffmt(struct v4l2_subdev *sd,
-			     struct v4l2_subdev_pad_config *cfg,
+			     struct v4l2_subdev_state *sd_state,
 			     struct v4l2_subdev_format *fmt);
 int ipu_isys_subdev_get_sel(struct v4l2_subdev *sd,
-			    struct v4l2_subdev_pad_config *cfg,
+			    struct v4l2_subdev_state *sd_state,
 			    struct v4l2_subdev_selection *sel);
 int ipu_isys_subdev_set_sel(struct v4l2_subdev *sd,
-			    struct v4l2_subdev_pad_config *cfg,
+			    struct v4l2_subdev_state *sd_state,
 			    struct v4l2_subdev_selection *sel);
 int ipu_isys_subdev_enum_mbus_code(struct v4l2_subdev *sd,
-				   struct v4l2_subdev_pad_config *cfg,
+				   struct v4l2_subdev_state *sd_state,
 				   struct v4l2_subdev_mbus_code_enum
 				   *code);
 int ipu_isys_subdev_link_validate(struct v4l2_subdev *sd,
diff --git a/drivers/media/pci/intel/ipu-isys-tpg.c b/drivers/media/pci/intel/ipu-isys-tpg.c
new file mode 100644
index 000000000000..b77ea5d55881
--- /dev/null
+++ b/drivers/media/pci/intel/ipu-isys-tpg.c
@@ -0,0 +1,311 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2013 - 2020 Intel Corporation
+
+#include <linux/device.h>
+#include <linux/module.h>
+
+#include <media/media-entity.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+
+#include "ipu.h"
+#include "ipu-bus.h"
+#include "ipu-isys.h"
+#include "ipu-isys-subdev.h"
+#include "ipu-isys-tpg.h"
+#include "ipu-isys-video.h"
+#include "ipu-platform-isys-csi2-reg.h"
+
+static const u32 tpg_supported_codes_pad[] = {
+	MEDIA_BUS_FMT_SBGGR8_1X8,
+	MEDIA_BUS_FMT_SGBRG8_1X8,
+	MEDIA_BUS_FMT_SGRBG8_1X8,
+	MEDIA_BUS_FMT_SRGGB8_1X8,
+	MEDIA_BUS_FMT_SBGGR10_1X10,
+	MEDIA_BUS_FMT_SGBRG10_1X10,
+	MEDIA_BUS_FMT_SGRBG10_1X10,
+	MEDIA_BUS_FMT_SRGGB10_1X10,
+	0,
+};
+
+static const u32 *tpg_supported_codes[] = {
+	tpg_supported_codes_pad,
+};
+
+static struct v4l2_subdev_internal_ops tpg_sd_internal_ops = {
+	.open = ipu_isys_subdev_open,
+	.close = ipu_isys_subdev_close,
+};
+
+static const struct v4l2_subdev_video_ops tpg_sd_video_ops = {
+	.s_stream = tpg_set_stream,
+};
+
+static int ipu_isys_tpg_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct ipu_isys_tpg *tpg = container_of(container_of(ctrl->handler,
+							     struct
+							     ipu_isys_subdev,
+							     ctrl_handler),
+						struct ipu_isys_tpg, asd);
+
+	switch (ctrl->id) {
+	case V4L2_CID_HBLANK:
+		writel(ctrl->val, tpg->base + MIPI_GEN_REG_SYNG_HBLANK_CYC);
+		break;
+	case V4L2_CID_VBLANK:
+		writel(ctrl->val, tpg->base + MIPI_GEN_REG_SYNG_VBLANK_CYC);
+		break;
+	case V4L2_CID_TEST_PATTERN:
+		writel(ctrl->val, tpg->base + MIPI_GEN_REG_TPG_MODE);
+		break;
+	}
+
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops ipu_isys_tpg_ctrl_ops = {
+	.s_ctrl = ipu_isys_tpg_s_ctrl,
+};
+
+static s64 ipu_isys_tpg_rate(struct ipu_isys_tpg *tpg, unsigned int bpp)
+{
+	return MIPI_GEN_PPC * IPU_ISYS_FREQ / bpp;
+}
+
+static const char *const tpg_mode_items[] = {
+	"Ramp",
+	"Checkerboard",	/* Does not work, disabled. */
+	"Frame Based Colour",
+};
+
+static struct v4l2_ctrl_config tpg_mode = {
+	.ops = &ipu_isys_tpg_ctrl_ops,
+	.id = V4L2_CID_TEST_PATTERN,
+	.name = "Test Pattern",
+	.type = V4L2_CTRL_TYPE_MENU,
+	.min = 0,
+	.max = ARRAY_SIZE(tpg_mode_items) - 1,
+	.def = 0,
+	.menu_skip_mask = 0x2,
+	.qmenu = tpg_mode_items,
+};
+
+static const struct v4l2_ctrl_config csi2_header_cfg = {
+	.id = V4L2_CID_IPU_STORE_CSI2_HEADER,
+	.name = "Store CSI-2 Headers",
+	.type = V4L2_CTRL_TYPE_BOOLEAN,
+	.min = 0,
+	.max = 1,
+	.step = 1,
+	.def = 1,
+};
+
+static void ipu_isys_tpg_init_controls(struct v4l2_subdev *sd)
+{
+	struct ipu_isys_tpg *tpg = to_ipu_isys_tpg(sd);
+	int hblank;
+	u64 default_pixel_rate;
+
+	hblank = 1024;
+
+	tpg->hblank = v4l2_ctrl_new_std(&tpg->asd.ctrl_handler,
+					&ipu_isys_tpg_ctrl_ops,
+					V4L2_CID_HBLANK, 8, 65535, 1, hblank);
+
+	tpg->vblank = v4l2_ctrl_new_std(&tpg->asd.ctrl_handler,
+					&ipu_isys_tpg_ctrl_ops,
+					V4L2_CID_VBLANK, 8, 65535, 1, 1024);
+
+	default_pixel_rate = ipu_isys_tpg_rate(tpg, 8);
+	tpg->pixel_rate = v4l2_ctrl_new_std(&tpg->asd.ctrl_handler,
+					    &ipu_isys_tpg_ctrl_ops,
+					    V4L2_CID_PIXEL_RATE,
+					    default_pixel_rate,
+					    default_pixel_rate,
+					    1, default_pixel_rate);
+	if (tpg->pixel_rate) {
+		tpg->pixel_rate->cur.val = default_pixel_rate;
+		tpg->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+	}
+
+	v4l2_ctrl_new_custom(&tpg->asd.ctrl_handler, &tpg_mode, NULL);
+	tpg->store_csi2_header =
+		v4l2_ctrl_new_custom(&tpg->asd.ctrl_handler,
+				     &csi2_header_cfg, NULL);
+}
+
+static void tpg_set_ffmt(struct v4l2_subdev *sd,
+			 struct v4l2_subdev_state *sd_state,
+			 struct v4l2_subdev_format *fmt)
+{
+	fmt->format.field = V4L2_FIELD_NONE;
+	*__ipu_isys_get_ffmt(sd, sd_state, fmt->pad, fmt->which) = fmt->format;
+}
+
+static int ipu_isys_tpg_set_ffmt(struct v4l2_subdev *sd,
+				 struct v4l2_subdev_state *sd_state,
+				 struct v4l2_subdev_format *fmt)
+{
+	struct ipu_isys_tpg *tpg = to_ipu_isys_tpg(sd);
+	__u32 code = tpg->asd.ffmt[TPG_PAD_SOURCE].code;
+	unsigned int bpp = ipu_isys_mbus_code_to_bpp(code);
+	s64 tpg_rate = ipu_isys_tpg_rate(tpg, bpp);
+	int rval;
+
+	mutex_lock(&tpg->asd.mutex);
+	rval = __ipu_isys_subdev_set_ffmt(sd, sd_state, fmt);
+	mutex_unlock(&tpg->asd.mutex);
+
+	if (rval || fmt->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+		return rval;
+
+	v4l2_ctrl_s_ctrl_int64(tpg->pixel_rate, tpg_rate);
+
+	return 0;
+}
+
+static const struct ipu_isys_pixelformat *
+ipu_isys_tpg_try_fmt(struct ipu_isys_video *av,
+		     struct v4l2_pix_format_mplane *mpix)
+{
+	struct media_link *link = list_first_entry(&av->vdev.entity.links,
+						   struct media_link, list);
+	struct v4l2_subdev *sd =
+		media_entity_to_v4l2_subdev(link->source->entity);
+	struct ipu_isys_tpg *tpg;
+
+	if (!sd)
+		return NULL;
+
+	tpg = to_ipu_isys_tpg(sd);
+
+	return ipu_isys_video_try_fmt_vid_mplane(av, mpix,
+		v4l2_ctrl_g_ctrl(tpg->store_csi2_header));
+}
+
+static const struct v4l2_subdev_pad_ops tpg_sd_pad_ops = {
+	.get_fmt = ipu_isys_subdev_get_ffmt,
+	.set_fmt = ipu_isys_tpg_set_ffmt,
+	.enum_mbus_code = ipu_isys_subdev_enum_mbus_code,
+};
+
+static int subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+			   struct v4l2_event_subscription *sub)
+{
+	switch (sub->type) {
+#ifdef IPU_TPG_FRAME_SYNC
+	case V4L2_EVENT_FRAME_SYNC:
+		return v4l2_event_subscribe(fh, sub, 10, NULL);
+#endif
+	case V4L2_EVENT_CTRL:
+		return v4l2_ctrl_subscribe_event(fh, sub);
+	default:
+		return -EINVAL;
+	}
+};
+
+/* V4L2 subdev core operations */
+static const struct v4l2_subdev_core_ops tpg_sd_core_ops = {
+	.subscribe_event = subscribe_event,
+	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
+};
+
+static struct v4l2_subdev_ops tpg_sd_ops = {
+	.core = &tpg_sd_core_ops,
+	.video = &tpg_sd_video_ops,
+	.pad = &tpg_sd_pad_ops,
+};
+
+static struct media_entity_operations tpg_entity_ops = {
+	.link_validate = v4l2_subdev_link_validate,
+};
+
+void ipu_isys_tpg_cleanup(struct ipu_isys_tpg *tpg)
+{
+	v4l2_device_unregister_subdev(&tpg->asd.sd);
+	ipu_isys_subdev_cleanup(&tpg->asd);
+	ipu_isys_video_cleanup(&tpg->av);
+}
+
+int ipu_isys_tpg_init(struct ipu_isys_tpg *tpg,
+		      struct ipu_isys *isys,
+		      void __iomem *base, void __iomem *sel,
+		      unsigned int index)
+{
+	struct v4l2_subdev_format fmt = {
+		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
+		.pad = TPG_PAD_SOURCE,
+		.format = {
+			   .width = 4096,
+			   .height = 3072,
+			   },
+	};
+	int rval;
+
+	tpg->isys = isys;
+	tpg->base = base;
+	tpg->sel = sel;
+	tpg->index = index;
+
+	tpg->asd.sd.entity.ops = &tpg_entity_ops;
+	tpg->asd.ctrl_init = ipu_isys_tpg_init_controls;
+	tpg->asd.isys = isys;
+
+	rval = ipu_isys_subdev_init(&tpg->asd, &tpg_sd_ops, 5,
+				    NR_OF_TPG_PADS,
+				    NR_OF_TPG_SOURCE_PADS,
+				    NR_OF_TPG_SINK_PADS,
+				    V4L2_SUBDEV_FL_HAS_EVENTS);
+	if (rval)
+		return rval;
+
+	tpg->asd.sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+	tpg->asd.pad[TPG_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+
+	tpg->asd.source = IPU_FW_ISYS_STREAM_SRC_MIPIGEN_PORT0 + index;
+	tpg->asd.supported_codes = tpg_supported_codes;
+	tpg->asd.set_ffmt = tpg_set_ffmt;
+	ipu_isys_subdev_set_ffmt(&tpg->asd.sd, NULL, &fmt);
+
+	tpg->asd.sd.internal_ops = &tpg_sd_internal_ops;
+	snprintf(tpg->asd.sd.name, sizeof(tpg->asd.sd.name),
+		 IPU_ISYS_ENTITY_PREFIX " TPG %u", index);
+	v4l2_set_subdevdata(&tpg->asd.sd, &tpg->asd);
+	rval = v4l2_device_register_subdev(&isys->v4l2_dev, &tpg->asd.sd);
+	if (rval) {
+		dev_info(&isys->adev->dev, "can't register v4l2 subdev\n");
+		goto fail;
+	}
+
+	snprintf(tpg->av.vdev.name, sizeof(tpg->av.vdev.name),
+		 IPU_ISYS_ENTITY_PREFIX " TPG %u capture", index);
+	tpg->av.isys = isys;
+	tpg->av.aq.css_pin_type = IPU_FW_ISYS_PIN_TYPE_MIPI;
+	tpg->av.pfmts = ipu_isys_pfmts_packed;
+	tpg->av.try_fmt_vid_mplane = ipu_isys_tpg_try_fmt;
+	tpg->av.prepare_fw_stream =
+	    ipu_isys_prepare_fw_cfg_default;
+	tpg->av.packed = true;
+	tpg->av.line_header_length = IPU_ISYS_CSI2_LONG_PACKET_HEADER_SIZE;
+	tpg->av.line_footer_length = IPU_ISYS_CSI2_LONG_PACKET_FOOTER_SIZE;
+	tpg->av.aq.buf_prepare = ipu_isys_buf_prepare;
+	tpg->av.aq.fill_frame_buff_set_pin =
+	    ipu_isys_buffer_to_fw_frame_buff_pin;
+	tpg->av.aq.link_fmt_validate = ipu_isys_link_fmt_validate;
+	tpg->av.aq.vbq.buf_struct_size = sizeof(struct ipu_isys_video_buffer);
+
+	rval = ipu_isys_video_init(&tpg->av, &tpg->asd.sd.entity,
+				   TPG_PAD_SOURCE, MEDIA_PAD_FL_SINK, 0);
+	if (rval) {
+		dev_info(&isys->adev->dev, "can't init video node\n");
+		goto fail;
+	}
+
+	return 0;
+
+fail:
+	ipu_isys_tpg_cleanup(tpg);
+
+	return rval;
+}
diff --git a/drivers/media/pci/intel/ipu-isys-tpg.h b/drivers/media/pci/intel/ipu-isys-tpg.h
new file mode 100644
index 000000000000..332f087ed774
--- /dev/null
+++ b/drivers/media/pci/intel/ipu-isys-tpg.h
@@ -0,0 +1,99 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2013 - 2020 Intel Corporation */
+
+#ifndef IPU_ISYS_TPG_H
+#define IPU_ISYS_TPG_H
+
+#include <media/media-entity.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+
+#include "ipu-isys-subdev.h"
+#include "ipu-isys-video.h"
+#include "ipu-isys-queue.h"
+
+struct ipu_isys_tpg_pdata;
+struct ipu_isys;
+
+#define TPG_PAD_SOURCE			0
+#define NR_OF_TPG_PADS			1
+#define NR_OF_TPG_SOURCE_PADS		1
+#define NR_OF_TPG_SINK_PADS		0
+#define NR_OF_TPG_STREAMS		1
+
+/*
+ * PPC is 4 pixels for clock for RAW8, RAW10 and RAW12.
+ * Source: FW validation test code.
+ */
+#define MIPI_GEN_PPC		4
+
+#define MIPI_GEN_REG_COM_ENABLE				0x0
+#define MIPI_GEN_REG_COM_DTYPE				0x4
+/* RAW8, RAW10 or RAW12 */
+#define MIPI_GEN_COM_DTYPE_RAW(n)			(((n) - 8) / 2)
+#define MIPI_GEN_REG_COM_VTYPE				0x8
+#define MIPI_GEN_REG_COM_VCHAN				0xc
+#define MIPI_GEN_REG_COM_WCOUNT				0x10
+#define MIPI_GEN_REG_PRBS_RSTVAL0			0x14
+#define MIPI_GEN_REG_PRBS_RSTVAL1			0x18
+#define MIPI_GEN_REG_SYNG_FREE_RUN			0x1c
+#define MIPI_GEN_REG_SYNG_PAUSE				0x20
+#define MIPI_GEN_REG_SYNG_NOF_FRAMES			0x24
+#define MIPI_GEN_REG_SYNG_NOF_PIXELS			0x28
+#define MIPI_GEN_REG_SYNG_NOF_LINES			0x2c
+#define MIPI_GEN_REG_SYNG_HBLANK_CYC			0x30
+#define MIPI_GEN_REG_SYNG_VBLANK_CYC			0x34
+#define MIPI_GEN_REG_SYNG_STAT_HCNT			0x38
+#define MIPI_GEN_REG_SYNG_STAT_VCNT			0x3c
+#define MIPI_GEN_REG_SYNG_STAT_FCNT			0x40
+#define MIPI_GEN_REG_SYNG_STAT_DONE			0x44
+#define MIPI_GEN_REG_TPG_MODE				0x48
+#define MIPI_GEN_REG_TPG_HCNT_MASK			0x4c
+#define MIPI_GEN_REG_TPG_VCNT_MASK			0x50
+#define MIPI_GEN_REG_TPG_XYCNT_MASK			0x54
+#define MIPI_GEN_REG_TPG_HCNT_DELTA			0x58
+#define MIPI_GEN_REG_TPG_VCNT_DELTA			0x5c
+#define MIPI_GEN_REG_TPG_R1				0x60
+#define MIPI_GEN_REG_TPG_G1				0x64
+#define MIPI_GEN_REG_TPG_B1				0x68
+#define MIPI_GEN_REG_TPG_R2				0x6c
+#define MIPI_GEN_REG_TPG_G2				0x70
+#define MIPI_GEN_REG_TPG_B2				0x74
+
+/*
+ * struct ipu_isys_tpg
+ *
+ * @nlanes: number of lanes in the receiver
+ */
+struct ipu_isys_tpg {
+	struct ipu_isys_tpg_pdata *pdata;
+	struct ipu_isys *isys;
+	struct ipu_isys_subdev asd;
+	struct ipu_isys_video av;
+
+	void __iomem *base;
+	void __iomem *sel;
+	unsigned int index;
+	int streaming;
+
+	struct v4l2_ctrl *hblank;
+	struct v4l2_ctrl *vblank;
+	struct v4l2_ctrl *pixel_rate;
+	struct v4l2_ctrl *store_csi2_header;
+};
+
+#define to_ipu_isys_tpg(sd)		\
+	container_of(to_ipu_isys_subdev(sd), \
+	struct ipu_isys_tpg, asd)
+#ifdef IPU_TPG_FRAME_SYNC
+void ipu_isys_tpg_sof_event(struct ipu_isys_tpg *tpg);
+void ipu_isys_tpg_eof_event(struct ipu_isys_tpg *tpg);
+#endif
+int ipu_isys_tpg_init(struct ipu_isys_tpg *tpg,
+		      struct ipu_isys *isys,
+		      void __iomem *base, void __iomem *sel,
+		      unsigned int index);
+void ipu_isys_tpg_cleanup(struct ipu_isys_tpg *tpg);
+int tpg_set_stream(struct v4l2_subdev *sd, int enable);
+
+#endif /* IPU_ISYS_TPG_H */
diff --git a/drivers/media/pci/intel/ipu-isys.c b/drivers/media/pci/intel/ipu-isys.c
index d7c493228c69..69df93bf7b02 100644
--- a/drivers/media/pci/intel/ipu-isys.c
+++ b/drivers/media/pci/intel/ipu-isys.c
@@ -946,7 +946,6 @@ void ipu_put_fw_mgs_buf(struct ipu_isys *isys, u64 data)
 	list_move(&msg->head, &isys->framebuflist);
 	spin_unlock_irqrestore(&isys->listlock, flags);
 }
-EXPORT_SYMBOL_GPL(ipu_put_fw_mgs_buf);
 
 static int isys_probe(struct ipu_bus_device *adev)
 {
@@ -1314,34 +1313,6 @@ int isys_isr_one(struct ipu_bus_device *adev)
 	return 0;
 }
 
-static void isys_isr_poll(struct ipu_bus_device *adev)
-{
-	struct ipu_isys *isys = ipu_bus_get_drvdata(adev);
-
-	if (!isys->fwcom) {
-		dev_dbg(&isys->adev->dev,
-			"got interrupt but device not configured yet\n");
-		return;
-	}
-
-	mutex_lock(&isys->mutex);
-	isys_isr(adev);
-	mutex_unlock(&isys->mutex);
-}
-
-int ipu_isys_isr_run(void *ptr)
-{
-	struct ipu_isys *isys = ptr;
-
-	while (!kthread_should_stop()) {
-		usleep_range(500, 1000);
-		if (isys->stream_opened)
-			isys_isr_poll(isys->adev);
-	}
-
-	return 0;
-}
-
 static struct ipu_bus_driver isys_driver = {
 	.probe = isys_probe,
 	.remove = isys_remove,
@@ -1359,7 +1330,8 @@ module_ipu_bus_driver(isys_driver);
 static const struct pci_device_id ipu_pci_tbl[] = {
 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, IPU6_PCI_ID)},
 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, IPU6SE_PCI_ID)},
-	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, IPU6EP_PCI_ID)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, IPU6EP_ADL_P_PCI_ID)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, IPU6EP_ADL_N_PCI_ID)},
 	{0,}
 };
 MODULE_DEVICE_TABLE(pci, ipu_pci_tbl);
diff --git a/drivers/media/pci/intel/ipu-isys.h b/drivers/media/pci/intel/ipu-isys.h
index 57bc4b55bf26..8b1228febdf6 100644
--- a/drivers/media/pci/intel/ipu-isys.h
+++ b/drivers/media/pci/intel/ipu-isys.h
@@ -219,7 +219,6 @@ extern const struct v4l2_ioctl_ops ipu_isys_ioctl_ops;
 
 void isys_setup_hw(struct ipu_isys *isys);
 int isys_isr_one(struct ipu_bus_device *adev);
-int ipu_isys_isr_run(void *ptr);
 irqreturn_t isys_isr(struct ipu_bus_device *adev);
 #ifdef IPU_ISYS_GPC
 int ipu_isys_gpc_init_debugfs(struct ipu_isys *isys);
diff --git a/drivers/media/pci/intel/ipu-mmu.c b/drivers/media/pci/intel/ipu-mmu.c
index ad84c7b63441..7d38529820b1 100644
--- a/drivers/media/pci/intel/ipu-mmu.c
+++ b/drivers/media/pci/intel/ipu-mmu.c
@@ -785,7 +785,7 @@ static void ipu_mmu_destroy(struct ipu_mmu *mmu)
 	}
 
 	free_dummy_page(mmu_info);
-	dma_unmap_single(mmu_info->dev, mmu_info->l1_pt_dma,
+	dma_unmap_single(mmu_info->dev, mmu_info->l1_pt_dma << ISP_PADDR_SHIFT,
 			 PAGE_SIZE, DMA_BIDIRECTIONAL);
 	free_page((unsigned long)mmu_info->dummy_l2_pt);
 	free_page((unsigned long)mmu_info->l1_pt);
@@ -840,7 +840,6 @@ struct ipu_mmu *ipu_mmu_init(struct device *dev,
 
 	return mmu;
 }
-EXPORT_SYMBOL(ipu_mmu_init);
 
 void ipu_mmu_cleanup(struct ipu_mmu *mmu)
 {
@@ -852,7 +851,6 @@ void ipu_mmu_cleanup(struct ipu_mmu *mmu)
 	put_iova_domain(&dmap->iovad);
 	kfree(dmap);
 }
-EXPORT_SYMBOL(ipu_mmu_cleanup);
 
 MODULE_AUTHOR("Sakari Ailus <sakari.ailus at linux.intel.com>");
 MODULE_AUTHOR("Samu Onkalo <samu.onkalo at intel.com>");
diff --git a/drivers/media/pci/intel/ipu-psys-compat32.c b/drivers/media/pci/intel/ipu-psys-compat32.c
index ba13127d946e..763ebc2c1a9f 100644
--- a/drivers/media/pci/intel/ipu-psys-compat32.c
+++ b/drivers/media/pci/intel/ipu-psys-compat32.c
@@ -223,4 +223,3 @@ long ipu_psys_compat_ioctl32(struct file *file, unsigned int cmd,
 	}
 	return err;
 }
-EXPORT_SYMBOL_GPL(ipu_psys_compat_ioctl32);
diff --git a/drivers/media/pci/intel/ipu-psys.c b/drivers/media/pci/intel/ipu-psys.c
index d0c71c86928f..0774ebc8bc9c 100644
--- a/drivers/media/pci/intel/ipu-psys.c
+++ b/drivers/media/pci/intel/ipu-psys.c
@@ -1340,7 +1340,6 @@ static int ipu_psys_probe(struct ipu_bus_device *adev)
 	INIT_LIST_HEAD(&psys->fhs);
 	INIT_LIST_HEAD(&psys->pgs);
 	INIT_LIST_HEAD(&psys->started_kcmds_list);
-	INIT_WORK(&psys->watchdog_work, ipu_psys_watchdog_work);
 
 	init_waitqueue_head(&psys->sched_cmd_wq);
 	atomic_set(&psys->wakeup_count, 0);
@@ -1360,18 +1359,11 @@ static int ipu_psys_probe(struct ipu_bus_device *adev)
 
 	ipu_bus_set_drvdata(adev, psys);
 
-	rval = ipu_psys_resource_pool_init(&psys->resource_pool_started);
-	if (rval < 0) {
-		dev_err(&psys->dev,
-			"unable to alloc process group resources\n");
-		goto out_mutex_destroy;
-	}
-
 	rval = ipu_psys_resource_pool_init(&psys->resource_pool_running);
 	if (rval < 0) {
 		dev_err(&psys->dev,
 			"unable to alloc process group resources\n");
-		goto out_resources_started_free;
+		goto out_mutex_destroy;
 	}
 
 	ipu6_psys_hw_res_variant_init();
@@ -1459,8 +1451,6 @@ static int ipu_psys_probe(struct ipu_bus_device *adev)
 	}
 
 	ipu_psys_resource_pool_cleanup(&psys->resource_pool_running);
-out_resources_started_free:
-	ipu_psys_resource_pool_cleanup(&psys->resource_pool_started);
 out_mutex_destroy:
 	mutex_destroy(&psys->mutex);
 	cdev_del(&psys->cdev);
@@ -1514,7 +1504,6 @@ static void ipu_psys_remove(struct ipu_bus_device *adev)
 
 	ipu_trace_uninit(&adev->dev);
 
-	ipu_psys_resource_pool_cleanup(&psys->resource_pool_started);
 	ipu_psys_resource_pool_cleanup(&psys->resource_pool_running);
 
 	device_unregister(&psys->dev);
@@ -1608,7 +1597,8 @@ static void __exit ipu_psys_exit(void)
 static const struct pci_device_id ipu_pci_tbl[] = {
 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, IPU6_PCI_ID)},
 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, IPU6SE_PCI_ID)},
-	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, IPU6EP_PCI_ID)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, IPU6EP_ADL_P_PCI_ID)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, IPU6EP_ADL_N_PCI_ID)},
 	{0,}
 };
 MODULE_DEVICE_TABLE(pci, ipu_pci_tbl);
diff --git a/drivers/media/pci/intel/ipu-psys.h b/drivers/media/pci/intel/ipu-psys.h
index b5ddf50791d7..80d70f2ef3ce 100644
--- a/drivers/media/pci/intel/ipu-psys.h
+++ b/drivers/media/pci/intel/ipu-psys.h
@@ -60,6 +60,8 @@ struct ipu_psys_resource_pool {
 	struct ipu_resource ext_memory[32];
 	struct ipu_resource dfms[16];
 	DECLARE_BITMAP(cmd_queues, 32);
+	/* Protects cmd_queues bitmap */
+	spinlock_t queues_lock;
 };
 
 /*
@@ -95,7 +97,6 @@ struct ipu_psys {
 	struct ia_css_syscom_config *syscom_config;
 	struct ia_css_psys_server_init *server_init;
 	struct task_struct *sched_cmd_thread;
-	struct work_struct watchdog_work;
 	wait_queue_head_t sched_cmd_wq;
 	atomic_t wakeup_count;  /* Psys schedule thread wakeup count */
 #ifdef CONFIG_DEBUG_FS
@@ -104,7 +105,6 @@ struct ipu_psys {
 
 	/* Resources needed to be managed for process groups */
 	struct ipu_psys_resource_pool resource_pool_running;
-	struct ipu_psys_resource_pool resource_pool_started;
 
 	const struct firmware *fw;
 	struct sg_table fw_sgt;
@@ -198,7 +198,6 @@ void ipu_psys_subdomains_power(struct ipu_psys *psys, bool on);
 void ipu_psys_handle_events(struct ipu_psys *psys);
 int ipu_psys_kcmd_new(struct ipu_psys_command *cmd, struct ipu_psys_fh *fh);
 void ipu_psys_run_next(struct ipu_psys *psys);
-void ipu_psys_watchdog_work(struct work_struct *work);
 struct ipu_psys_pg *__get_pg_buf(struct ipu_psys *psys, size_t pg_size);
 struct ipu_psys_kbuffer *
 ipu_psys_lookup_kbuffer(struct ipu_psys_fh *fh, int fd);
diff --git a/drivers/media/pci/intel/ipu.c b/drivers/media/pci/intel/ipu.c
index f7826d07ea54..691907561e9a 100644
--- a/drivers/media/pci/intel/ipu.c
+++ b/drivers/media/pci/intel/ipu.c
@@ -415,7 +415,8 @@ static int ipu_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 		ipu_ver = IPU_VER_6SE;
 		isp->cpd_fw_name = IPU6SE_FIRMWARE_NAME;
 		break;
-	case IPU6EP_PCI_ID:
+	case IPU6EP_ADL_P_PCI_ID:
+	case IPU6EP_ADL_N_PCI_ID:
 		ipu_ver = IPU_VER_6EP;
 		isp->cpd_fw_name = IPU6EP_FIRMWARE_NAME;
 		break;
@@ -750,7 +751,8 @@ static const struct dev_pm_ops ipu_pm_ops = {
 static const struct pci_device_id ipu_pci_tbl[] = {
 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, IPU6_PCI_ID)},
 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, IPU6SE_PCI_ID)},
-	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, IPU6EP_PCI_ID)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, IPU6EP_ADL_P_PCI_ID)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, IPU6EP_ADL_N_PCI_ID)},
 	{0,}
 };
 MODULE_DEVICE_TABLE(pci, ipu_pci_tbl);
diff --git a/drivers/media/pci/intel/ipu.h b/drivers/media/pci/intel/ipu.h
index 2b8758ccab9b..4ef08954dcea 100644
--- a/drivers/media/pci/intel/ipu.h
+++ b/drivers/media/pci/intel/ipu.h
@@ -16,7 +16,8 @@
 
 #define IPU6_PCI_ID	0x9a19
 #define IPU6SE_PCI_ID	0x4e19
-#define IPU6EP_PCI_ID	0x465d
+#define IPU6EP_ADL_P_PCI_ID	0x465d
+#define IPU6EP_ADL_N_PCI_ID	0x462e
 
 enum ipu_version {
 	IPU_VER_INVALID = 0,
diff --git a/drivers/media/pci/intel/ipu6/ipu-resources.c b/drivers/media/pci/intel/ipu6/ipu-resources.c
index b246fc037890..dfe4fde7e83f 100644
--- a/drivers/media/pci/intel/ipu6/ipu-resources.c
+++ b/drivers/media/pci/intel/ipu6/ipu-resources.c
@@ -141,15 +141,14 @@ static void ipu_resource_cleanup(struct ipu_resource *res)
 }
 
 /********** IPU PSYS-specific resource handling **********/
-static DEFINE_SPINLOCK(cq_bitmap_lock);
-int ipu_psys_resource_pool_init(struct ipu_psys_resource_pool
-				*pool)
+int ipu_psys_resource_pool_init(struct ipu_psys_resource_pool *pool)
 {
 	int i, j, k, ret;
 	const struct ipu_fw_resource_definitions *res_defs;
 
 	res_defs = get_res();
 
+	spin_lock_init(&pool->queues_lock);
 	pool->cells = 0;
 
 	for (i = 0; i < res_defs->num_dev_channels; i++) {
@@ -172,14 +171,14 @@ int ipu_psys_resource_pool_init(struct ipu_psys_resource_pool
 			goto dfm_error;
 	}
 
-	spin_lock(&cq_bitmap_lock);
+	spin_lock(&pool->queues_lock);
 	if (ipu_ver == IPU_VER_6SE)
 		bitmap_zero(pool->cmd_queues,
 			    IPU6SE_FW_PSYS_N_PSYS_CMD_QUEUE_ID);
 	else
 		bitmap_zero(pool->cmd_queues,
 			    IPU6_FW_PSYS_N_PSYS_CMD_QUEUE_ID);
-	spin_unlock(&cq_bitmap_lock);
+	spin_unlock(&pool->queues_lock);
 
 	return 0;
 
@@ -272,17 +271,6 @@ static int __alloc_one_resrc(const struct device *dev,
 	return 0;
 }
 
-static inline unsigned int bit_count(unsigned int n)
-{
-	unsigned int counter = 0;
-
-	while (n) {
-		counter++;
-		n &= (n - 1);
-	}
-	return counter;
-}
-
 static int ipu_psys_allocate_one_dfm(const struct device *dev,
 				     struct ipu_fw_psys_process *process,
 				     struct ipu_resource *resource,
@@ -316,7 +304,7 @@ static int ipu_psys_allocate_one_dfm(const struct device *dev,
 		}
 		*resource->bitmap |= dfm_bitmap_req;
 	} else {
-		unsigned int n = bit_count(dfm_bitmap_req);
+		unsigned int n = hweight32(dfm_bitmap_req);
 
 		p = bitmap_find_next_zero_area(resource->bitmap,
 					       resource->elements, 0, n, 0);
@@ -398,17 +386,17 @@ int ipu_psys_allocate_cmd_queue_resource(struct ipu_psys_resource_pool *pool)
 		start = IPU6SE_FW_PSYS_CMD_QUEUE_PPG0_COMMAND_ID;
 	}
 
-	spin_lock(&cq_bitmap_lock);
+	spin_lock(&pool->queues_lock);
 	/* find available cmd queue from ppg0_cmd_id */
 	p = bitmap_find_next_zero_area(pool->cmd_queues, size, start, 1, 0);
 
 	if (p >= size) {
-		spin_unlock(&cq_bitmap_lock);
+		spin_unlock(&pool->queues_lock);
 		return -ENOSPC;
 	}
 
 	bitmap_set(pool->cmd_queues, p, 1);
-	spin_unlock(&cq_bitmap_lock);
+	spin_unlock(&pool->queues_lock);
 
 	return p;
 }
@@ -416,9 +404,9 @@ int ipu_psys_allocate_cmd_queue_resource(struct ipu_psys_resource_pool *pool)
 void ipu_psys_free_cmd_queue_resource(struct ipu_psys_resource_pool *pool,
 				      u8 queue_id)
 {
-	spin_lock(&cq_bitmap_lock);
+	spin_lock(&pool->queues_lock);
 	bitmap_clear(pool->cmd_queues, queue_id, 1);
-	spin_unlock(&cq_bitmap_lock);
+	spin_unlock(&pool->queues_lock);
 }
 
 int ipu_psys_try_allocate_resources(struct device *dev,
diff --git a/drivers/media/pci/intel/ipu6/ipu6-fw-resources.c b/drivers/media/pci/intel/ipu6/ipu6-fw-resources.c
index 9569a146e739..338e90d8f29b 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-fw-resources.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-fw-resources.c
@@ -13,7 +13,7 @@
 /*
  * Cell types by cell IDs
  */
-const u8 ipu6_fw_psys_cell_types[IPU6_FW_PSYS_N_CELL_ID] = {
+static const u8 ipu6_fw_psys_cell_types[IPU6_FW_PSYS_N_CELL_ID] = {
 	IPU6_FW_PSYS_SP_CTRL_TYPE_ID,
 	IPU6_FW_PSYS_VP_TYPE_ID,
 	IPU6_FW_PSYS_ACC_PSA_TYPE_ID,
@@ -48,7 +48,7 @@ const u8 ipu6_fw_psys_cell_types[IPU6_FW_PSYS_N_CELL_ID] = {
 	IPU6_FW_PSYS_TNR_TYPE_ID,
 };
 
-const u16 ipu6_fw_num_dev_channels[IPU6_FW_PSYS_N_DEV_CHN_ID] = {
+static const u16 ipu6_fw_num_dev_channels[IPU6_FW_PSYS_N_DEV_CHN_ID] = {
 	IPU6_FW_PSYS_DEV_CHN_DMA_EXT0_MAX_SIZE,
 	IPU6_FW_PSYS_DEV_CHN_DMA_EXT1_READ_MAX_SIZE,
 	IPU6_FW_PSYS_DEV_CHN_DMA_EXT1_WRITE_MAX_SIZE,
@@ -56,7 +56,7 @@ const u16 ipu6_fw_num_dev_channels[IPU6_FW_PSYS_N_DEV_CHN_ID] = {
 	IPU6_FW_PSYS_DEV_CHN_DMA_ISA_MAX_SIZE,
 };
 
-const u16 ipu6_fw_psys_mem_size[IPU6_FW_PSYS_N_MEM_ID] = {
+static const u16 ipu6_fw_psys_mem_size[IPU6_FW_PSYS_N_MEM_ID] = {
 	IPU6_FW_PSYS_VMEM0_MAX_SIZE,
 	IPU6_FW_PSYS_TRANSFER_VMEM0_MAX_SIZE,
 	IPU6_FW_PSYS_TRANSFER_VMEM1_MAX_SIZE,
@@ -69,7 +69,7 @@ const u16 ipu6_fw_psys_mem_size[IPU6_FW_PSYS_N_MEM_ID] = {
 	IPU6_FW_PSYS_PMEM0_MAX_SIZE
 };
 
-const u16 ipu6_fw_psys_dfms[IPU6_FW_PSYS_N_DEV_DFM_ID] = {
+static const u16 ipu6_fw_psys_dfms[IPU6_FW_PSYS_N_DEV_DFM_ID] = {
 	IPU6_FW_PSYS_DEV_DFM_BB_FULL_PORT_ID_MAX_SIZE,
 	IPU6_FW_PSYS_DEV_DFM_BB_EMPTY_PORT_ID_MAX_SIZE,
 	IPU6_FW_PSYS_DEV_DFM_ISL_FULL_PORT_ID_MAX_SIZE,
@@ -78,7 +78,7 @@ const u16 ipu6_fw_psys_dfms[IPU6_FW_PSYS_N_DEV_DFM_ID] = {
 	IPU6_FW_PSYS_DEV_DFM_LB_EMPTY_PORT_ID_MAX_SIZE,
 };
 
-const u8
+static const u8
 ipu6_fw_psys_c_mem[IPU6_FW_PSYS_N_CELL_ID][IPU6_FW_PSYS_N_MEM_TYPE_ID] = {
 	{
 		/* IPU6_FW_PSYS_SP0_ID */
@@ -539,6 +539,8 @@ int ipu6_fw_psys_get_program_manifest_by_process(
 	return 0;
 }
 
+#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG) || \
+	(defined(CONFIG_DYNAMIC_DEBUG_CORE) && defined(DYNAMIC_DEBUG_MODULE))
 void ipu6_fw_psys_pg_dump(struct ipu_psys *psys,
 			  struct ipu_psys_kcmd *kcmd, const char *note)
 {
@@ -593,3 +595,14 @@ void ipu6_fw_psys_pg_dump(struct ipu_psys *psys,
 		}
 	}
 }
+#else
+void ipu6_fw_psys_pg_dump(struct ipu_psys *psys,
+			  struct ipu_psys_kcmd *kcmd, const char *note)
+{
+	if (ipu_ver == IPU_VER_6SE || ipu_ver == IPU_VER_6 ||
+	    ipu_ver == IPU_VER_6EP)
+		return;
+
+	WARN(1, "%s ipu_ver:[%u] is unsupported!\n", __func__, ipu_ver);
+}
+#endif
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-gpc.c b/drivers/media/pci/intel/ipu6/ipu6-isys-gpc.c
index bd8044255efe..a305c0c3e2cf 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-gpc.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-gpc.c
@@ -173,10 +173,8 @@ int ipu_isys_gpc_init_debugfs(struct ipu_isys *isys)
 		if (IS_ERR(dir))
 			goto err;
 
-		file = debugfs_create_bool("enable", 0600, dir,
-					   &isys_gpcs->gpc[i].enable);
-		if (IS_ERR(file))
-			goto err;
+		debugfs_create_bool("enable", 0600, dir,
+				    &isys_gpcs->gpc[i].enable);
 
 		debugfs_create_u32("source", 0600, dir,
 				   &isys_gpcs->gpc[i].source);
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-phy.c b/drivers/media/pci/intel/ipu6/ipu6-isys-phy.c
index a1165e718def..c26780106c78 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-phy.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-phy.c
@@ -25,7 +25,7 @@ struct phy_reg {
 	u32 val;
 };
 
-struct phy_reg common_init_regs[] = {
+static const struct phy_reg common_init_regs[] = {
 	/* for TGL-U, use 0x80000000 */
 	{0x00000040, 0x80000000},
 	{0x00000044, 0x00a80880},
@@ -45,7 +45,7 @@ struct phy_reg common_init_regs[] = {
 	{0x00001944, 0xfa4401e2}
 };
 
-struct phy_reg x1_port0_config_regs[] = {
+static const struct phy_reg x1_port0_config_regs[] = {
 	{0x00000694, 0xc80060fa},
 	{0x00000680, 0x3d4f78ea},
 	{0x00000690, 0x10a0140b},
@@ -69,7 +69,7 @@ struct phy_reg x1_port0_config_regs[] = {
 	{0x00000000, 0x00000000}
 };
 
-struct phy_reg x1_port1_config_regs[] = {
+static const struct phy_reg x1_port1_config_regs[] = {
 	{0x00000c94, 0xc80060fa},
 	{0x00000c80, 0xcf47abea},
 	{0x00000c90, 0x10a0840b},
@@ -93,7 +93,7 @@ struct phy_reg x1_port1_config_regs[] = {
 	{0x00000000, 0x00000000}
 };
 
-struct phy_reg x1_port2_config_regs[] = {
+static const struct phy_reg x1_port2_config_regs[] = {
 	{0x00001294, 0x28f000fa},
 	{0x00001280, 0x08130cea},
 	{0x00001290, 0x10a0140b},
@@ -117,7 +117,7 @@ struct phy_reg x1_port2_config_regs[] = {
 	{0x00000000, 0x00000000}
 };
 
-struct phy_reg x1_port3_config_regs[] = {
+static const struct phy_reg x1_port3_config_regs[] = {
 	{0x00001894, 0xc80060fa},
 	{0x00001880, 0x0f90fd6a},
 	{0x00001890, 0x10a0840b},
@@ -141,7 +141,7 @@ struct phy_reg x1_port3_config_regs[] = {
 	{0x00000000, 0x00000000}
 };
 
-struct phy_reg x2_port0_config_regs[] = {
+static const struct phy_reg x2_port0_config_regs[] = {
 	{0x00000694, 0xc80060fa},
 	{0x00000680, 0x3d4f78ea},
 	{0x00000690, 0x10a0140b},
@@ -175,7 +175,7 @@ struct phy_reg x2_port0_config_regs[] = {
 	{0x00000000, 0x00000000}
 };
 
-struct phy_reg x2_port1_config_regs[] = {
+static const struct phy_reg x2_port1_config_regs[] = {
 	{0x00000c94, 0xc80060fa},
 	{0x00000c80, 0xcf47abea},
 	{0x00000c90, 0x10a0840b},
@@ -209,7 +209,7 @@ struct phy_reg x2_port1_config_regs[] = {
 	{0x00000000, 0x00000000}
 };
 
-struct phy_reg x2_port2_config_regs[] = {
+static const struct phy_reg x2_port2_config_regs[] = {
 	{0x00001294, 0xc80060fa},
 	{0x00001280, 0x08130cea},
 	{0x00001290, 0x10a0140b},
@@ -242,7 +242,7 @@ struct phy_reg x2_port2_config_regs[] = {
 	{0x00000000, 0x00000000}
 };
 
-struct phy_reg x2_port3_config_regs[] = {
+static const struct phy_reg x2_port3_config_regs[] = {
 	{0x00001894, 0xc80060fa},
 	{0x00001880, 0x0f90fd6a},
 	{0x00001890, 0x10a0840b},
@@ -276,7 +276,7 @@ struct phy_reg x2_port3_config_regs[] = {
 	{0x00000000, 0x00000000}
 };
 
-struct phy_reg x4_port0_config_regs[] = {
+static const struct phy_reg x4_port0_config_regs[] = {
 	{0x00000694, 0xc80060fa},
 	{0x00000680, 0x3d4f78fa},
 	{0x00000690, 0x10a0140b},
@@ -330,11 +330,11 @@ struct phy_reg x4_port0_config_regs[] = {
 	{0x00000000, 0x00000000}
 };
 
-struct phy_reg x4_port1_config_regs[] = {
+static const struct phy_reg x4_port1_config_regs[] = {
 	{0x00000000, 0x00000000}
 };
 
-struct phy_reg x4_port2_config_regs[] = {
+static const struct phy_reg x4_port2_config_regs[] = {
 	{0x00001294, 0x28f000fa},
 	{0x00001280, 0x08130cfa},
 	{0x00001290, 0x10c0140b},
@@ -388,32 +388,32 @@ struct phy_reg x4_port2_config_regs[] = {
 	{0x00000000, 0x00000000}
 };
 
-struct phy_reg x4_port3_config_regs[] = {
+static const struct phy_reg x4_port3_config_regs[] = {
 	{0x00000000, 0x00000000}
 };
 
-struct phy_reg *x1_config_regs[4] = {
+static const struct phy_reg *x1_config_regs[4] = {
 	x1_port0_config_regs,
 	x1_port1_config_regs,
 	x1_port2_config_regs,
 	x1_port3_config_regs
 };
 
-struct phy_reg *x2_config_regs[4] = {
+static const struct phy_reg *x2_config_regs[4] = {
 	x2_port0_config_regs,
 	x2_port1_config_regs,
 	x2_port2_config_regs,
 	x2_port3_config_regs
 };
 
-struct phy_reg *x4_config_regs[4] = {
+static const struct phy_reg *x4_config_regs[4] = {
 	x4_port0_config_regs,
 	x4_port1_config_regs,
 	x4_port2_config_regs,
 	x4_port3_config_regs
 };
 
-struct phy_reg **config_regs[3] = {
+static const struct phy_reg **config_regs[3] = {
 	x1_config_regs,
 	x2_config_regs,
 	x4_config_regs,
@@ -561,7 +561,7 @@ int ipu6_isys_phy_config(struct ipu_isys *isys)
 	struct ipu_bus_device *adev = to_ipu_bus_device(&isys->adev->dev);
 	struct ipu_device *isp = adev->isp;
 	void __iomem *isp_base = isp->base;
-	struct phy_reg **phy_config_regs;
+	const struct phy_reg **phy_config_regs;
 	struct v4l2_async_subdev *asd;
 	struct sensor_async_subdev *s_asd;
 	struct ipu_isys_csi2_config cfg;
diff --git a/drivers/media/pci/intel/ipu6/ipu6-ppg.c b/drivers/media/pci/intel/ipu6/ipu6-ppg.c
index c6acf9cb70ef..8f6f413c0393 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-ppg.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-ppg.c
@@ -97,12 +97,14 @@ ipu_psys_create_buffer_set(struct ipu_psys_kcmd *kcmd,
 	buf_set_size = ipu_fw_psys_ppg_get_buffer_set_size(kcmd);
 
 	kbuf_set = __get_buf_set(fh, buf_set_size);
-	if (!kbuf_set)
-		goto error;
+	if (!kbuf_set) {
+		dev_err(&psys->adev->dev, "failed to create buffer set\n");
+		return NULL;
+	}
 
 	kbuf_set->buf_set = ipu_fw_psys_ppg_create_buffer_set(kcmd,
 							      kbuf_set->kaddr,
-	0);
+							      0);
 
 	ipu_fw_psys_ppg_buffer_set_vaddress(kbuf_set->buf_set,
 					    kbuf_set->dma_addr);
@@ -111,9 +113,6 @@ ipu_psys_create_buffer_set(struct ipu_psys_kcmd *kcmd,
 							    keb);
 
 	return kbuf_set;
-error:
-	dev_err(&psys->adev->dev, "failed to create buffer set\n");
-	return NULL;
 }
 
 int ipu_psys_ppg_get_bufset(struct ipu_psys_kcmd *kcmd,
diff --git a/drivers/media/pci/intel/ipu6/ipu6-psys-gpc.c b/drivers/media/pci/intel/ipu6/ipu6-psys-gpc.c
index 3bf35d245a4f..b6b850a68398 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-psys-gpc.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-psys-gpc.c
@@ -180,10 +180,8 @@ int ipu_psys_gpc_init_debugfs(struct ipu_psys *psys)
 		if (IS_ERR(dir))
 			goto err;
 
-		file = debugfs_create_bool("enable", 0600, dir,
-					   &psys_gpcs->gpc[idx].enable);
-		if (IS_ERR(file))
-			goto err;
+		debugfs_create_bool("enable", 0600, dir,
+				    &psys_gpcs->gpc[idx].enable);
 
 		debugfs_create_u32("source", 0600, dir,
 				   &psys_gpcs->gpc[idx].source);
diff --git a/drivers/media/pci/intel/ipu6/ipu6-psys.c b/drivers/media/pci/intel/ipu6/ipu6-psys.c
index 06560b91948b..294a6f1638e5 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-psys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-psys.c
@@ -20,10 +20,6 @@
 #include "ipu-platform-regs.h"
 #include "ipu-trace.h"
 
-#define is_ppg_kcmd(kcmd) (ipu_fw_psys_pg_get_protocol(	\
-			(struct ipu_psys_kcmd *)kcmd)	\
-			== IPU_FW_PSYS_PROCESS_GROUP_PROTOCOL_PPG)
-
 static bool early_pg_transfer;
 module_param(early_pg_transfer, bool, 0664);
 MODULE_PARM_DESC(early_pg_transfer,
@@ -501,7 +497,7 @@ int ipu_psys_kcmd_start(struct ipu_psys *psys, struct ipu_psys_kcmd *kcmd)
 	ret = ipu_fw_psys_pg_start(kcmd);
 	if (ret) {
 		dev_err(&psys->adev->dev, "failed to start kcmd!\n");
-		goto error;
+		return ret;
 	}
 
 	ipu_fw_psys_pg_dump(psys, kcmd, "run");
@@ -509,29 +505,10 @@ int ipu_psys_kcmd_start(struct ipu_psys *psys, struct ipu_psys_kcmd *kcmd)
 	ret = ipu_fw_psys_pg_disown(kcmd);
 	if (ret) {
 		dev_err(&psys->adev->dev, "failed to start kcmd!\n");
-		goto error;
+		return ret;
 	}
 
 	return 0;
-
-error:
-	dev_err(&psys->adev->dev, "failed to start process group\n");
-	return ret;
-}
-
-void ipu_psys_watchdog_work(struct work_struct *work)
-{
-	struct ipu_psys *psys = container_of(work,
-					     struct ipu_psys, watchdog_work);
-	dev_dbg(&psys->adev->dev, "watchdog for ppg not implemented yet!\n");
-}
-
-static void ipu_psys_watchdog(struct timer_list *t)
-{
-	struct ipu_psys_kcmd *kcmd = from_timer(kcmd, t, watchdog);
-	struct ipu_psys *psys = kcmd->fh->psys;
-
-	queue_work(IPU_PSYS_WORK_QUEUE, &psys->watchdog_work);
 }
 
 static int ipu_psys_kcmd_send_to_ppg_start(struct ipu_psys_kcmd *kcmd)
@@ -702,14 +679,13 @@ int ipu_psys_kcmd_new(struct ipu_psys_command *cmd, struct ipu_psys_fh *fh)
 		goto error;
 	}
 
-	if (!is_ppg_kcmd(kcmd)) {
+	if (ipu_fw_psys_pg_get_protocol(kcmd) !=
+			IPU_FW_PSYS_PROCESS_GROUP_PROTOCOL_PPG) {
 		dev_err(&psys->adev->dev, "No support legacy pg now\n");
 		ret = -EINVAL;
 		goto error;
 	}
 
-	timer_setup(&kcmd->watchdog, ipu_psys_watchdog, 0);
-
 	if (cmd->min_psys_freq) {
 		kcmd->constraint.min_freq = cmd->min_psys_freq;
 		ipu_buttress_add_psys_constraint(psys->adev->isp,
diff --git a/drivers/media/pci/intel/ipu6/ipu6ep-fw-resources.c b/drivers/media/pci/intel/ipu6/ipu6ep-fw-resources.c
index ca2ab3967e5c..7b1ee7c6dc4e 100644
--- a/drivers/media/pci/intel/ipu6/ipu6ep-fw-resources.c
+++ b/drivers/media/pci/intel/ipu6/ipu6ep-fw-resources.c
@@ -14,7 +14,7 @@
 /*
  * Cell types by cell IDs
  */
-const u8 ipu6ep_fw_psys_cell_types[IPU6EP_FW_PSYS_N_CELL_ID] = {
+static const u8 ipu6ep_fw_psys_cell_types[IPU6EP_FW_PSYS_N_CELL_ID] = {
 	IPU6_FW_PSYS_SP_CTRL_TYPE_ID,
 	IPU6_FW_PSYS_VP_TYPE_ID,
 	IPU6_FW_PSYS_ACC_PSA_TYPE_ID,
@@ -46,7 +46,7 @@ const u8 ipu6ep_fw_psys_cell_types[IPU6EP_FW_PSYS_N_CELL_ID] = {
 	IPU6_FW_PSYS_TNR_TYPE_ID,
 };
 
-const u16 ipu6ep_fw_num_dev_channels[IPU6_FW_PSYS_N_DEV_CHN_ID] = {
+static const u16 ipu6ep_fw_num_dev_channels[IPU6_FW_PSYS_N_DEV_CHN_ID] = {
 	IPU6_FW_PSYS_DEV_CHN_DMA_EXT0_MAX_SIZE,
 	IPU6_FW_PSYS_DEV_CHN_DMA_EXT1_READ_MAX_SIZE,
 	IPU6_FW_PSYS_DEV_CHN_DMA_EXT1_WRITE_MAX_SIZE,
@@ -54,7 +54,7 @@ const u16 ipu6ep_fw_num_dev_channels[IPU6_FW_PSYS_N_DEV_CHN_ID] = {
 	IPU6_FW_PSYS_DEV_CHN_DMA_ISA_MAX_SIZE,
 };
 
-const u16 ipu6ep_fw_psys_mem_size[IPU6_FW_PSYS_N_MEM_ID] = {
+static const u16 ipu6ep_fw_psys_mem_size[IPU6_FW_PSYS_N_MEM_ID] = {
 	IPU6_FW_PSYS_VMEM0_MAX_SIZE,
 	IPU6_FW_PSYS_TRANSFER_VMEM0_MAX_SIZE,
 	IPU6_FW_PSYS_TRANSFER_VMEM1_MAX_SIZE,
@@ -67,7 +67,7 @@ const u16 ipu6ep_fw_psys_mem_size[IPU6_FW_PSYS_N_MEM_ID] = {
 	IPU6_FW_PSYS_PMEM0_MAX_SIZE
 };
 
-const u16 ipu6ep_fw_psys_dfms[IPU6_FW_PSYS_N_DEV_DFM_ID] = {
+static const u16 ipu6ep_fw_psys_dfms[IPU6_FW_PSYS_N_DEV_DFM_ID] = {
 	IPU6_FW_PSYS_DEV_DFM_BB_FULL_PORT_ID_MAX_SIZE,
 	IPU6_FW_PSYS_DEV_DFM_BB_EMPTY_PORT_ID_MAX_SIZE,
 	IPU6_FW_PSYS_DEV_DFM_ISL_FULL_PORT_ID_MAX_SIZE,
@@ -76,7 +76,7 @@ const u16 ipu6ep_fw_psys_dfms[IPU6_FW_PSYS_N_DEV_DFM_ID] = {
 	IPU6_FW_PSYS_DEV_DFM_LB_EMPTY_PORT_ID_MAX_SIZE,
 };
 
-const u8
+static const u8
 ipu6ep_fw_psys_c_mem[IPU6EP_FW_PSYS_N_CELL_ID][IPU6_FW_PSYS_N_MEM_TYPE_ID] = {
 	{
 		/* IPU6_FW_PSYS_SP0_ID */
-- 
2.33.1




More information about the kernel-team mailing list