diff --git a/drivers/media/i2c/hm11b1.c b/drivers/media/i2c/hm11b1.c
new file mode 100644
index 000000000000..9c1662b842de
--- /dev/null
+++ b/drivers/media/i2c/hm11b1.c
@@ -0,0 +1,1360 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2020 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 <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
+
+#define HM11B1_LINK_FREQ_384MHZ		384000000ULL
+#define HM11B1_SCLK			72000000LL
+#define HM11B1_MCLK			19200000
+#define HM11B1_DATA_LANES		1
+#define HM11B1_RGB_DEPTH		10
+
+#define HM11B1_REG_CHIP_ID		0x0000
+#define HM11B1_CHIP_ID			0x11B1
+
+#define HM11B1_REG_MODE_SELECT		0x0100
+#define HM11B1_MODE_STANDBY		0x00
+#define HM11B1_MODE_STREAMING		0x01
+
+/* vertical-timings from sensor */
+#define HM11B1_REG_VTS			0x3402
+#define HM11B1_VTS_DEF			0x037d
+#define HM11B1_VTS_MIN			0x0346
+#define HM11B1_VTS_MAX			0xffff
+
+/* horizontal-timings from sensor */
+#define HM11B1_REG_HTS			0x3404
+
+/* Exposure controls from sensor */
+#define HM11B1_REG_EXPOSURE		0x0202
+#define HM11B1_EXPOSURE_MIN		2
+#define HM11B1_EXPOSURE_MAX_MARGIN	2
+#define HM11B1_EXPOSURE_STEP		1
+
+/* Analog gain controls from sensor */
+#define HM11B1_REG_ANALOG_GAIN		0x0205
+#define HM11B1_ANAL_GAIN_MIN		0
+#define HM11B1_ANAL_GAIN_MAX		0x50
+#define HM11B1_ANAL_GAIN_STEP		1
+
+/* Digital gain controls from sensor */
+#define HM11B1_REG_DGTL_GAIN		0x0207
+#define HM11B1_DGTL_GAIN_MIN		0x0
+#define HM11B1_DGTL_GAIN_MAX		0x0200
+#define HM11B1_DGTL_GAIN_STEP		1
+#define HM11B1_DGTL_GAIN_DEFAULT	0x0100
+
+/* Test Pattern Control */
+#define HM11B1_REG_TEST_PATTERN		0x0601
+#define HM11B1_TEST_PATTERN_ENABLE	1
+#define HM11B1_TEST_PATTERN_BAR_SHIFT	1
+
+enum {
+	HM11B1_LINK_FREQ_384MHZ_INDEX,
+};
+
+struct hm11b1_reg {
+	u16 address;
+	u8 val;
+};
+
+struct hm11b1_reg_list {
+	u32 num_of_regs;
+	const struct hm11b1_reg *regs;
+};
+
+struct hm11b1_link_freq_config {
+	const struct hm11b1_reg_list reg_list;
+};
+
+struct hm11b1_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 hm11b1_reg_list reg_list;
+};
+
+static const struct hm11b1_reg mipi_data_rate_384mbps[] = {
+};
+
+//RAW 10bit 1292x800_30fps_MIPI 384Mbps/lane
+static const struct hm11b1_reg sensor_1292x800_30fps_setting[] = {
+	{0x0103, 0x00},
+	{0x0102, 0x01},
+	{0x0202, 0x03},
+	{0x0203, 0x7C},
+	{0x0205, 0x20},
+	{0x0207, 0x01},
+	{0x0208, 0x00},
+	{0x0209, 0x01},
+	{0x020A, 0x00},
+	{0x0300, 0x91},
+	{0x0301, 0x0A},
+	{0x0302, 0x02},
+	{0x0303, 0x2E},
+	{0x0304, 0x43},
+	{0x0306, 0x00},
+	{0x0307, 0x00},
+	{0x0340, 0x03},
+	{0x0341, 0x60},
+	{0x0342, 0x05},
+	{0x0343, 0xA0},
+	{0x0344, 0x00},
+	{0x0345, 0x00},
+	{0x0346, 0x03},
+	{0x0347, 0x2F},
+	{0x0350, 0xFF},
+	{0x0351, 0x00},
+	{0x0352, 0x00},
+	{0x0370, 0x00},
+	{0x0371, 0x00},
+	{0x0380, 0x00},
+	{0x0381, 0x00},
+	{0x0382, 0x00},
+	{0x1000, 0xC3},
+	{0x1001, 0xD0},
+	{0x100A, 0x13},
+	{0x2000, 0x00},
+	{0x2061, 0x01},
+	{0x2062, 0x00},
+	{0x2063, 0xC8},
+	{0x2100, 0x03},
+	{0x2101, 0xF0},
+	{0x2102, 0xF0},
+	{0x2103, 0x01},
+	{0x2104, 0x10},
+	{0x2105, 0x10},
+	{0x2106, 0x02},
+	{0x2107, 0x0A},
+	{0x2108, 0x10},
+	{0x2109, 0x15},
+	{0x210A, 0x1A},
+	{0x210B, 0x20},
+	{0x210C, 0x08},
+	{0x210D, 0x0A},
+	{0x210E, 0x0F},
+	{0x210F, 0x12},
+	{0x2110, 0x1C},
+	{0x2111, 0x20},
+	{0x2112, 0x23},
+	{0x2113, 0x2A},
+	{0x2114, 0x30},
+	{0x2115, 0x10},
+	{0x2116, 0x00},
+	{0x2117, 0x01},
+	{0x2118, 0x00},
+	{0x2119, 0x06},
+	{0x211A, 0x00},
+	{0x211B, 0x00},
+	{0x2615, 0x08},
+	{0x2616, 0x00},
+	{0x2700, 0x01},
+	{0x2711, 0x01},
+	{0x272F, 0x01},
+	{0x2800, 0x29},
+	{0x2821, 0xCE},
+	{0x2839, 0x27},
+	{0x283A, 0x01},
+	{0x2842, 0x01},
+	{0x2843, 0x00},
+	{0x3022, 0x11},
+	{0x3024, 0x30},
+	{0x3025, 0x12},
+	{0x3026, 0x00},
+	{0x3027, 0x81},
+	{0x3028, 0x01},
+	{0x3029, 0x00},
+	{0x302A, 0x30},
+	{0x3030, 0x00},
+	{0x3032, 0x00},
+	{0x3035, 0x01},
+	{0x303E, 0x00},
+	{0x3051, 0x00},
+	{0x3082, 0x0E},
+	{0x3084, 0x0D},
+	{0x30A8, 0x03},
+	{0x30C4, 0xA0},
+	{0x30D5, 0xC1},
+	{0x30D8, 0x00},
+	{0x30D9, 0x0D},
+	{0x30DB, 0xC2},
+	{0x30DE, 0x25},
+	{0x30E1, 0xC3},
+	{0x30E4, 0x25},
+	{0x30E7, 0xC4},
+	{0x30EA, 0x25},
+	{0x30ED, 0xC5},
+	{0x30F0, 0x25},
+	{0x30F2, 0x0C},
+	{0x30F3, 0x85},
+	{0x30F6, 0x25},
+	{0x30F8, 0x0C},
+	{0x30F9, 0x05},
+	{0x30FB, 0x40},
+	{0x30FC, 0x25},
+	{0x30FD, 0x54},
+	{0x30FE, 0x0C},
+	{0x3100, 0xC2},
+	{0x3103, 0x00},
+	{0x3104, 0x2B},
+	{0x3106, 0xC3},
+	{0x3109, 0x25},
+	{0x310C, 0xC4},
+	{0x310F, 0x25},
+	{0x3112, 0xC5},
+	{0x3115, 0x25},
+	{0x3117, 0x0C},
+	{0x3118, 0x85},
+	{0x311B, 0x25},
+	{0x311D, 0x0C},
+	{0x311E, 0x05},
+	{0x3121, 0x25},
+	{0x3123, 0x0C},
+	{0x3124, 0x0D},
+	{0x3126, 0x40},
+	{0x3127, 0x25},
+	{0x3128, 0x54},
+	{0x3129, 0x0C},
+	{0x3130, 0x20},
+	{0x3134, 0x60},
+	{0x3135, 0xC2},
+	{0x3139, 0x12},
+	{0x313A, 0x07},
+	{0x313F, 0x52},
+	{0x3140, 0x34},
+	{0x3141, 0x2E},
+	{0x314F, 0x07},
+	{0x3151, 0x47},
+	{0x3153, 0xB0},
+	{0x3154, 0x4A},
+	{0x3155, 0xC0},
+	{0x3157, 0x55},
+	{0x3158, 0x01},
+	{0x3165, 0xFF},
+	{0x316B, 0x12},
+	{0x316E, 0x12},
+	{0x3176, 0x12},
+	{0x3178, 0x01},
+	{0x317C, 0x10},
+	{0x317D, 0x05},
+	{0x317F, 0x07},
+	{0x3182, 0x07},
+	{0x3183, 0x11},
+	{0x3184, 0x88},
+	{0x3186, 0x28},
+	{0x3191, 0x00},
+	{0x3192, 0x20},
+	{0x3400, 0x48},
+	{0x3401, 0x00},
+	{0x3402, 0x06},
+	{0x3403, 0xFA},
+	{0x3404, 0x05},
+	{0x3405, 0x40},
+	{0x3406, 0x00},
+	{0x3407, 0x00},
+	{0x3408, 0x03},
+	{0x3409, 0x2F},
+	{0x340A, 0x00},
+	{0x340B, 0x00},
+	{0x340C, 0x00},
+	{0x340D, 0x00},
+	{0x340E, 0x00},
+	{0x340F, 0x00},
+	{0x3410, 0x00},
+	{0x3411, 0x01},
+	{0x3412, 0x00},
+	{0x3413, 0x03},
+	{0x3414, 0xB0},
+	{0x3415, 0x4A},
+	{0x3416, 0xC0},
+	{0x3418, 0x55},
+	{0x3419, 0x03},
+	{0x341B, 0x7D},
+	{0x341C, 0x00},
+	{0x341F, 0x03},
+	{0x3420, 0x00},
+	{0x3421, 0x02},
+	{0x3422, 0x00},
+	{0x3423, 0x02},
+	{0x3424, 0x01},
+	{0x3425, 0x02},
+	{0x3426, 0x00},
+	{0x3427, 0xA2},
+	{0x3428, 0x01},
+	{0x3429, 0x06},
+	{0x342A, 0xF8},
+	{0x3440, 0x01},
+	{0x3441, 0xBE},
+	{0x3442, 0x02},
+	{0x3443, 0x18},
+	{0x3444, 0x03},
+	{0x3445, 0x0C},
+	{0x3446, 0x06},
+	{0x3447, 0x18},
+	{0x3448, 0x09},
+	{0x3449, 0x24},
+	{0x344A, 0x08},
+	{0x344B, 0x08},
+	{0x345C, 0x00},
+	{0x345D, 0x44},
+	{0x345E, 0x02},
+	{0x345F, 0x43},
+	{0x3460, 0x04},
+	{0x3461, 0x3B},
+	{0x3466, 0xF8},
+	{0x3467, 0x43},
+	{0x347D, 0x02},
+	{0x3483, 0x05},
+	{0x3484, 0x0C},
+	{0x3485, 0x03},
+	{0x3486, 0x20},
+	{0x3487, 0x00},
+	{0x3488, 0x00},
+	{0x3489, 0x00},
+	{0x348A, 0x09},
+	{0x348B, 0x00},
+	{0x348C, 0x00},
+	{0x348D, 0x02},
+	{0x348E, 0x01},
+	{0x348F, 0x40},
+	{0x3490, 0x00},
+	{0x3491, 0xC8},
+	{0x3492, 0x00},
+	{0x3493, 0x02},
+	{0x3494, 0x00},
+	{0x3495, 0x02},
+	{0x3496, 0x02},
+	{0x3497, 0x06},
+	{0x3498, 0x05},
+	{0x3499, 0x04},
+	{0x349A, 0x09},
+	{0x349B, 0x05},
+	{0x349C, 0x17},
+	{0x349D, 0x05},
+	{0x349E, 0x00},
+	{0x349F, 0x00},
+	{0x34A0, 0x00},
+	{0x34A1, 0x00},
+	{0x34A2, 0x08},
+	{0x34A3, 0x08},
+	{0x34A4, 0x00},
+	{0x34A5, 0x0B},
+	{0x34A6, 0x0C},
+	{0x34A7, 0x32},
+	{0x34A8, 0x10},
+	{0x34A9, 0xE0},
+	{0x34AA, 0x52},
+	{0x34AB, 0x00},
+	{0x34AC, 0x60},
+	{0x34AD, 0x2B},
+	{0x34AE, 0x25},
+	{0x34AF, 0x48},
+	{0x34B1, 0x06},
+	{0x34B2, 0xF8},
+	{0x34C3, 0xB0},
+	{0x34C4, 0x4A},
+	{0x34C5, 0xC0},
+	{0x34C7, 0x55},
+	{0x34C8, 0x03},
+	{0x34CB, 0x00},
+	{0x353A, 0x00},
+	{0x355E, 0x48},
+	{0x3572, 0xB0},
+	{0x3573, 0x4A},
+	{0x3574, 0xC0},
+	{0x3576, 0x55},
+	{0x3577, 0x03},
+	{0x357A, 0x00},
+	{0x35DA, 0x00},
+	{0x4003, 0x02},
+	{0x4004, 0x02},
+};
+
+//RAW 10bit 1292x800_60fps_MIPI 384Mbps/lane
+static const struct hm11b1_reg sensor_1292x800_60fps_setting[] = {
+	{0x0103, 0x00},
+	{0x0102, 0x01},
+	{0x0202, 0x03},
+	{0x0203, 0x7C},
+	{0x0205, 0x20},
+	{0x0207, 0x01},
+	{0x0208, 0x00},
+	{0x0209, 0x01},
+	{0x020A, 0x00},
+	{0x0300, 0x91},
+	{0x0301, 0x0A},
+	{0x0302, 0x02},
+	{0x0303, 0x2E},
+	{0x0304, 0x43},
+	{0x0306, 0x00},
+	{0x0307, 0x00},
+	{0x0340, 0x03},
+	{0x0341, 0x60},
+	{0x0342, 0x05},
+	{0x0343, 0xA0},
+	{0x0344, 0x00},
+	{0x0345, 0x00},
+	{0x0346, 0x03},
+	{0x0347, 0x2F},
+	{0x0350, 0xFF},
+	{0x0351, 0x00},
+	{0x0352, 0x00},
+	{0x0370, 0x00},
+	{0x0371, 0x00},
+	{0x0380, 0x00},
+	{0x0381, 0x00},
+	{0x0382, 0x00},
+	{0x1000, 0xC3},
+	{0x1001, 0xD0},
+	{0x100A, 0x13},
+	{0x2000, 0x00},
+	{0x2061, 0x01},
+	{0x2062, 0x00},
+	{0x2063, 0xC8},
+	{0x2100, 0x03},
+	{0x2101, 0xF0},
+	{0x2102, 0xF0},
+	{0x2103, 0x01},
+	{0x2104, 0x10},
+	{0x2105, 0x10},
+	{0x2106, 0x02},
+	{0x2107, 0x0A},
+	{0x2108, 0x10},
+	{0x2109, 0x15},
+	{0x210A, 0x1A},
+	{0x210B, 0x20},
+	{0x210C, 0x08},
+	{0x210D, 0x0A},
+	{0x210E, 0x0F},
+	{0x210F, 0x12},
+	{0x2110, 0x1C},
+	{0x2111, 0x20},
+	{0x2112, 0x23},
+	{0x2113, 0x2A},
+	{0x2114, 0x30},
+	{0x2115, 0x10},
+	{0x2116, 0x00},
+	{0x2117, 0x01},
+	{0x2118, 0x00},
+	{0x2119, 0x06},
+	{0x211A, 0x00},
+	{0x211B, 0x00},
+	{0x2615, 0x08},
+	{0x2616, 0x00},
+	{0x2700, 0x01},
+	{0x2711, 0x01},
+	{0x272F, 0x01},
+	{0x2800, 0x29},
+	{0x2821, 0xCE},
+	{0x2839, 0x27},
+	{0x283A, 0x01},
+	{0x2842, 0x01},
+	{0x2843, 0x00},
+	{0x3022, 0x11},
+	{0x3024, 0x30},
+	{0x3025, 0x12},
+	{0x3026, 0x00},
+	{0x3027, 0x81},
+	{0x3028, 0x01},
+	{0x3029, 0x00},
+	{0x302A, 0x30},
+	{0x3030, 0x00},
+	{0x3032, 0x00},
+	{0x3035, 0x01},
+	{0x303E, 0x00},
+	{0x3051, 0x00},
+	{0x3082, 0x0E},
+	{0x3084, 0x0D},
+	{0x30A8, 0x03},
+	{0x30C4, 0xA0},
+	{0x30D5, 0xC1},
+	{0x30D8, 0x00},
+	{0x30D9, 0x0D},
+	{0x30DB, 0xC2},
+	{0x30DE, 0x25},
+	{0x30E1, 0xC3},
+	{0x30E4, 0x25},
+	{0x30E7, 0xC4},
+	{0x30EA, 0x25},
+	{0x30ED, 0xC5},
+	{0x30F0, 0x25},
+	{0x30F2, 0x0C},
+	{0x30F3, 0x85},
+	{0x30F6, 0x25},
+	{0x30F8, 0x0C},
+	{0x30F9, 0x05},
+	{0x30FB, 0x40},
+	{0x30FC, 0x25},
+	{0x30FD, 0x54},
+	{0x30FE, 0x0C},
+	{0x3100, 0xC2},
+	{0x3103, 0x00},
+	{0x3104, 0x2B},
+	{0x3106, 0xC3},
+	{0x3109, 0x25},
+	{0x310C, 0xC4},
+	{0x310F, 0x25},
+	{0x3112, 0xC5},
+	{0x3115, 0x25},
+	{0x3117, 0x0C},
+	{0x3118, 0x85},
+	{0x311B, 0x25},
+	{0x311D, 0x0C},
+	{0x311E, 0x05},
+	{0x3121, 0x25},
+	{0x3123, 0x0C},
+	{0x3124, 0x0D},
+	{0x3126, 0x40},
+	{0x3127, 0x25},
+	{0x3128, 0x54},
+	{0x3129, 0x0C},
+	{0x3130, 0x20},
+	{0x3134, 0x60},
+	{0x3135, 0xC2},
+	{0x3139, 0x12},
+	{0x313A, 0x07},
+	{0x313F, 0x52},
+	{0x3140, 0x34},
+	{0x3141, 0x2E},
+	{0x314F, 0x07},
+	{0x3151, 0x47},
+	{0x3153, 0xB0},
+	{0x3154, 0x4A},
+	{0x3155, 0xC0},
+	{0x3157, 0x55},
+	{0x3158, 0x01},
+	{0x3165, 0xFF},
+	{0x316B, 0x12},
+	{0x316E, 0x12},
+	{0x3176, 0x12},
+	{0x3178, 0x01},
+	{0x317C, 0x10},
+	{0x317D, 0x05},
+	{0x317F, 0x07},
+	{0x3182, 0x07},
+	{0x3183, 0x11},
+	{0x3184, 0x88},
+	{0x3186, 0x28},
+	{0x3191, 0x00},
+	{0x3192, 0x20},
+	{0x3400, 0x48},
+	{0x3401, 0x00},
+	{0x3402, 0x03},
+	{0x3403, 0x7D},
+	{0x3404, 0x05},
+	{0x3405, 0x40},
+	{0x3406, 0x00},
+	{0x3407, 0x00},
+	{0x3408, 0x03},
+	{0x3409, 0x2F},
+	{0x340A, 0x00},
+	{0x340B, 0x00},
+	{0x340C, 0x00},
+	{0x340D, 0x00},
+	{0x340E, 0x00},
+	{0x340F, 0x00},
+	{0x3410, 0x00},
+	{0x3411, 0x01},
+	{0x3412, 0x00},
+	{0x3413, 0x03},
+	{0x3414, 0xB0},
+	{0x3415, 0x4A},
+	{0x3416, 0xC0},
+	{0x3418, 0x55},
+	{0x3419, 0x03},
+	{0x341B, 0x7D},
+	{0x341C, 0x00},
+	{0x341F, 0x03},
+	{0x3420, 0x00},
+	{0x3421, 0x02},
+	{0x3422, 0x00},
+	{0x3423, 0x02},
+	{0x3424, 0x01},
+	{0x3425, 0x02},
+	{0x3426, 0x00},
+	{0x3427, 0xA2},
+	{0x3428, 0x01},
+	{0x3429, 0x06},
+	{0x342A, 0xF8},
+	{0x3440, 0x01},
+	{0x3441, 0xBE},
+	{0x3442, 0x02},
+	{0x3443, 0x18},
+	{0x3444, 0x03},
+	{0x3445, 0x0C},
+	{0x3446, 0x06},
+	{0x3447, 0x18},
+	{0x3448, 0x09},
+	{0x3449, 0x24},
+	{0x344A, 0x08},
+	{0x344B, 0x08},
+	{0x345C, 0x00},
+	{0x345D, 0x44},
+	{0x345E, 0x02},
+	{0x345F, 0x43},
+	{0x3460, 0x04},
+	{0x3461, 0x3B},
+	{0x3466, 0xF8},
+	{0x3467, 0x43},
+	{0x347D, 0x02},
+	{0x3483, 0x05},
+	{0x3484, 0x0C},
+	{0x3485, 0x03},
+	{0x3486, 0x20},
+	{0x3487, 0x00},
+	{0x3488, 0x00},
+	{0x3489, 0x00},
+	{0x348A, 0x09},
+	{0x348B, 0x00},
+	{0x348C, 0x00},
+	{0x348D, 0x02},
+	{0x348E, 0x01},
+	{0x348F, 0x40},
+	{0x3490, 0x00},
+	{0x3491, 0xC8},
+	{0x3492, 0x00},
+	{0x3493, 0x02},
+	{0x3494, 0x00},
+	{0x3495, 0x02},
+	{0x3496, 0x02},
+	{0x3497, 0x06},
+	{0x3498, 0x05},
+	{0x3499, 0x04},
+	{0x349A, 0x09},
+	{0x349B, 0x05},
+	{0x349C, 0x17},
+	{0x349D, 0x05},
+	{0x349E, 0x00},
+	{0x349F, 0x00},
+	{0x34A0, 0x00},
+	{0x34A1, 0x00},
+	{0x34A2, 0x08},
+	{0x34A3, 0x08},
+	{0x34A4, 0x00},
+	{0x34A5, 0x0B},
+	{0x34A6, 0x0C},
+	{0x34A7, 0x32},
+	{0x34A8, 0x10},
+	{0x34A9, 0xE0},
+	{0x34AA, 0x52},
+	{0x34AB, 0x00},
+	{0x34AC, 0x60},
+	{0x34AD, 0x2B},
+	{0x34AE, 0x25},
+	{0x34AF, 0x48},
+	{0x34B1, 0x06},
+	{0x34B2, 0xF8},
+	{0x34C3, 0xB0},
+	{0x34C4, 0x4A},
+	{0x34C5, 0xC0},
+	{0x34C7, 0x55},
+	{0x34C8, 0x03},
+	{0x34CB, 0x00},
+	{0x353A, 0x00},
+	{0x355E, 0x48},
+	{0x3572, 0xB0},
+	{0x3573, 0x4A},
+	{0x3574, 0xC0},
+	{0x3576, 0x55},
+	{0x3577, 0x03},
+	{0x357A, 0x00},
+	{0x35DA, 0x00},
+	{0x4003, 0x02},
+	{0x4004, 0x02},
+};
+
+static const char * const hm11b1_test_pattern_menu[] = {
+	"Disabled",
+	"Solid Color",
+	"Color Bar",
+	"Color Bar Blending",
+	"PN11",
+};
+
+static const s64 link_freq_menu_items[] = {
+	HM11B1_LINK_FREQ_384MHZ,
+};
+
+static const struct hm11b1_link_freq_config link_freq_configs[] = {
+	[HM11B1_LINK_FREQ_384MHZ_INDEX] = {
+		.reg_list = {
+			.num_of_regs = ARRAY_SIZE(mipi_data_rate_384mbps),
+			.regs = mipi_data_rate_384mbps,
+		}
+	},
+};
+
+static const struct hm11b1_mode supported_modes[] = {
+	{
+		.width = 1292,
+		.height = 800,
+		.hts = 1344,
+		.vts_def = HM11B1_VTS_DEF,
+		.vts_min = HM11B1_VTS_MIN,
+		.reg_list = {
+			.num_of_regs =
+				ARRAY_SIZE(sensor_1292x800_30fps_setting),
+			.regs = sensor_1292x800_30fps_setting,
+		},
+		.link_freq_index = HM11B1_LINK_FREQ_384MHZ_INDEX,
+	},
+};
+
+struct hm11b1 {
+	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 hm11b1_mode *cur_mode;
+
+	/* To serialize asynchronus callbacks */
+	struct mutex mutex;
+
+	/* Streaming on/off */
+	bool streaming;
+};
+
+static inline struct hm11b1 *to_hm11b1(struct v4l2_subdev *subdev)
+{
+	return container_of(subdev, struct hm11b1, sd);
+}
+
+static u64 to_pixel_rate(u32 f_index)
+{
+	u64 pixel_rate = link_freq_menu_items[f_index] * 2 * HM11B1_DATA_LANES;
+
+	do_div(pixel_rate, HM11B1_RGB_DEPTH);
+
+	return pixel_rate;
+}
+
+static u64 to_pixels_per_line(u32 hts, u32 f_index)
+{
+	u64 ppl = hts * to_pixel_rate(f_index);
+
+	do_div(ppl, HM11B1_SCLK);
+
+	return ppl;
+}
+
+static int hm11b1_read_reg(struct hm11b1 *hm11b1, u16 reg, u16 len, u32 *val)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&hm11b1->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 hm11b1_write_reg(struct hm11b1 *hm11b1, u16 reg, u16 len, u32 val)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&hm11b1->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 hm11b1_write_reg_list(struct hm11b1 *hm11b1,
+				 const struct hm11b1_reg_list *r_list)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&hm11b1->sd);
+	unsigned int i;
+	int ret = 0;
+
+	for (i = 0; i < r_list->num_of_regs; i++) {
+		ret = hm11b1_write_reg(hm11b1, 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 hm11b1_update_digital_gain(struct hm11b1 *hm11b1, u32 d_gain)
+{
+	return hm11b1_write_reg(hm11b1, HM11B1_REG_DGTL_GAIN, 2, d_gain);
+}
+
+static int hm11b1_test_pattern(struct hm11b1 *hm11b1, u32 pattern)
+{
+	if (pattern)
+		pattern = pattern << HM11B1_TEST_PATTERN_BAR_SHIFT |
+			  HM11B1_TEST_PATTERN_ENABLE;
+
+	return hm11b1_write_reg(hm11b1, HM11B1_REG_TEST_PATTERN, 1, pattern);
+}
+
+static int hm11b1_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct hm11b1 *hm11b1 = container_of(ctrl->handler,
+					     struct hm11b1, ctrl_handler);
+	struct i2c_client *client = v4l2_get_subdevdata(&hm11b1->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 = hm11b1->cur_mode->height + ctrl->val -
+			       HM11B1_EXPOSURE_MAX_MARGIN;
+		__v4l2_ctrl_modify_range(hm11b1->exposure,
+					 hm11b1->exposure->minimum,
+					 exposure_max, hm11b1->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 = hm11b1_write_reg(hm11b1, HM11B1_REG_ANALOG_GAIN, 1,
+				       ctrl->val);
+		break;
+
+	case V4L2_CID_DIGITAL_GAIN:
+		ret = hm11b1_update_digital_gain(hm11b1, ctrl->val);
+		break;
+
+	case V4L2_CID_EXPOSURE:
+		/* 4 least significant bits of expsoure are fractional part */
+		ret = hm11b1_write_reg(hm11b1, HM11B1_REG_EXPOSURE, 2,
+				       ctrl->val);
+		break;
+
+	case V4L2_CID_VBLANK:
+		ret = hm11b1_write_reg(hm11b1, HM11B1_REG_VTS, 2,
+				       hm11b1->cur_mode->height + ctrl->val);
+		break;
+
+	case V4L2_CID_TEST_PATTERN:
+		ret = hm11b1_test_pattern(hm11b1, ctrl->val);
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	pm_runtime_put(&client->dev);
+
+	return ret;
+}
+
+static const struct v4l2_ctrl_ops hm11b1_ctrl_ops = {
+	.s_ctrl = hm11b1_set_ctrl,
+};
+
+static int hm11b1_init_controls(struct hm11b1 *hm11b1)
+{
+	struct v4l2_ctrl_handler *ctrl_hdlr;
+	const struct hm11b1_mode *cur_mode;
+	s64 exposure_max, h_blank, pixel_rate;
+	u32 vblank_min, vblank_max, vblank_default;
+	int size;
+	int ret = 0;
+
+	ctrl_hdlr = &hm11b1->ctrl_handler;
+	ret = v4l2_ctrl_handler_init(ctrl_hdlr, 8);
+	if (ret)
+		return ret;
+
+	ctrl_hdlr->lock = &hm11b1->mutex;
+	cur_mode = hm11b1->cur_mode;
+	size = ARRAY_SIZE(link_freq_menu_items);
+
+	hm11b1->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &hm11b1_ctrl_ops,
+						   V4L2_CID_LINK_FREQ,
+						   size - 1, 0,
+						   link_freq_menu_items);
+	if (hm11b1->link_freq)
+		hm11b1->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+	pixel_rate = to_pixel_rate(HM11B1_LINK_FREQ_384MHZ_INDEX);
+	hm11b1->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &hm11b1_ctrl_ops,
+					       V4L2_CID_PIXEL_RATE, 0,
+					       pixel_rate, 1, pixel_rate);
+
+	vblank_min = cur_mode->vts_min - cur_mode->height;
+	vblank_max = HM11B1_VTS_MAX - cur_mode->height;
+	vblank_default = cur_mode->vts_def - cur_mode->height;
+	hm11b1->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &hm11b1_ctrl_ops,
+					   V4L2_CID_VBLANK, vblank_min,
+					   vblank_max, 1, vblank_default);
+
+	h_blank = to_pixels_per_line(cur_mode->hts, cur_mode->link_freq_index);
+	h_blank -= cur_mode->width;
+	hm11b1->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &hm11b1_ctrl_ops,
+					   V4L2_CID_HBLANK, h_blank, h_blank, 1,
+					   h_blank);
+	if (hm11b1->hblank)
+		hm11b1->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+	v4l2_ctrl_new_std(ctrl_hdlr, &hm11b1_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
+			  HM11B1_ANAL_GAIN_MIN, HM11B1_ANAL_GAIN_MAX,
+			  HM11B1_ANAL_GAIN_STEP, HM11B1_ANAL_GAIN_MIN);
+	v4l2_ctrl_new_std(ctrl_hdlr, &hm11b1_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
+			  HM11B1_DGTL_GAIN_MIN, HM11B1_DGTL_GAIN_MAX,
+			  HM11B1_DGTL_GAIN_STEP, HM11B1_DGTL_GAIN_DEFAULT);
+	exposure_max = cur_mode->vts_def - HM11B1_EXPOSURE_MAX_MARGIN;
+	hm11b1->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &hm11b1_ctrl_ops,
+					     V4L2_CID_EXPOSURE,
+					     HM11B1_EXPOSURE_MIN, exposure_max,
+					     HM11B1_EXPOSURE_STEP,
+					     exposure_max);
+	v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &hm11b1_ctrl_ops,
+				     V4L2_CID_TEST_PATTERN,
+				     ARRAY_SIZE(hm11b1_test_pattern_menu) - 1,
+				     0, 0, hm11b1_test_pattern_menu);
+	if (ctrl_hdlr->error)
+		return ctrl_hdlr->error;
+
+	hm11b1->sd.ctrl_handler = ctrl_hdlr;
+
+	return 0;
+}
+
+static void hm11b1_update_pad_format(const struct hm11b1_mode *mode,
+				     struct v4l2_mbus_framefmt *fmt)
+{
+	fmt->width = mode->width;
+	fmt->height = mode->height;
+	fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
+	fmt->field = V4L2_FIELD_NONE;
+}
+
+static int hm11b1_start_streaming(struct hm11b1 *hm11b1)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&hm11b1->sd);
+	const struct hm11b1_reg_list *reg_list;
+	int link_freq_index;
+	int ret = 0;
+
+	link_freq_index = hm11b1->cur_mode->link_freq_index;
+	reg_list = &link_freq_configs[link_freq_index].reg_list;
+	ret = hm11b1_write_reg_list(hm11b1, reg_list);
+	if (ret) {
+		dev_err(&client->dev, "failed to set plls");
+		return ret;
+	}
+
+	reg_list = &hm11b1->cur_mode->reg_list;
+	ret = hm11b1_write_reg_list(hm11b1, reg_list);
+	if (ret) {
+		dev_err(&client->dev, "failed to set mode");
+		return ret;
+	}
+
+	ret = __v4l2_ctrl_handler_setup(hm11b1->sd.ctrl_handler);
+	if (ret)
+		return ret;
+
+	ret = hm11b1_write_reg(hm11b1, HM11B1_REG_MODE_SELECT, 1,
+			       HM11B1_MODE_STREAMING);
+	if (ret)
+		dev_err(&client->dev, "failed to start streaming");
+
+	return ret;
+}
+
+static void hm11b1_stop_streaming(struct hm11b1 *hm11b1)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&hm11b1->sd);
+
+	if (hm11b1_write_reg(hm11b1, HM11B1_REG_MODE_SELECT, 1,
+			     HM11B1_MODE_STANDBY))
+		dev_err(&client->dev, "failed to stop streaming");
+}
+
+static int hm11b1_set_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct hm11b1 *hm11b1 = to_hm11b1(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int ret = 0;
+
+	if (hm11b1->streaming == enable)
+		return 0;
+
+	mutex_lock(&hm11b1->mutex);
+	if (enable) {
+		ret = pm_runtime_get_sync(&client->dev);
+		if (ret < 0) {
+			pm_runtime_put_noidle(&client->dev);
+			mutex_unlock(&hm11b1->mutex);
+			return ret;
+		}
+
+		ret = hm11b1_start_streaming(hm11b1);
+		if (ret) {
+			enable = 0;
+			hm11b1_stop_streaming(hm11b1);
+			pm_runtime_put(&client->dev);
+		}
+	} else {
+		hm11b1_stop_streaming(hm11b1);
+		pm_runtime_put(&client->dev);
+	}
+
+	hm11b1->streaming = enable;
+	mutex_unlock(&hm11b1->mutex);
+
+	return ret;
+}
+
+static int __maybe_unused hm11b1_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct hm11b1 *hm11b1 = to_hm11b1(sd);
+
+	mutex_lock(&hm11b1->mutex);
+	if (hm11b1->streaming)
+		hm11b1_stop_streaming(hm11b1);
+
+	mutex_unlock(&hm11b1->mutex);
+
+	return 0;
+}
+
+static int __maybe_unused hm11b1_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct hm11b1 *hm11b1 = to_hm11b1(sd);
+	int ret = 0;
+
+	mutex_lock(&hm11b1->mutex);
+	if (!hm11b1->streaming)
+		goto exit;
+
+	ret = hm11b1_start_streaming(hm11b1);
+	if (ret) {
+		hm11b1->streaming = false;
+		hm11b1_stop_streaming(hm11b1);
+	}
+
+exit:
+	mutex_unlock(&hm11b1->mutex);
+	return ret;
+}
+
+static int hm11b1_set_format(struct v4l2_subdev *sd,
+			     struct v4l2_subdev_pad_config *cfg,
+			     struct v4l2_subdev_format *fmt)
+{
+	struct hm11b1 *hm11b1 = to_hm11b1(sd);
+	const struct hm11b1_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(&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;
+	} else {
+		hm11b1->cur_mode = mode;
+		__v4l2_ctrl_s_ctrl(hm11b1->link_freq, mode->link_freq_index);
+		__v4l2_ctrl_s_ctrl_int64(hm11b1->pixel_rate,
+					 to_pixel_rate(mode->link_freq_index));
+
+		/* Update limits and set FPS to default */
+		vblank_def = mode->vts_def - mode->height;
+		__v4l2_ctrl_modify_range(hm11b1->vblank,
+					 mode->vts_min - mode->height,
+					 HM11B1_VTS_MAX - mode->height, 1,
+					 vblank_def);
+		__v4l2_ctrl_s_ctrl(hm11b1->vblank, vblank_def);
+		h_blank = to_pixels_per_line(mode->hts, mode->link_freq_index) -
+			  mode->width;
+		__v4l2_ctrl_modify_range(hm11b1->hblank, h_blank, h_blank, 1,
+					 h_blank);
+	}
+	mutex_unlock(&hm11b1->mutex);
+
+	return 0;
+}
+
+static int hm11b1_get_format(struct v4l2_subdev *sd,
+			     struct v4l2_subdev_pad_config *cfg,
+			     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);
+	else
+		hm11b1_update_pad_format(hm11b1->cur_mode, &fmt->format);
+
+	mutex_unlock(&hm11b1->mutex);
+
+	return 0;
+}
+
+static int hm11b1_enum_mbus_code(struct v4l2_subdev *sd,
+				 struct v4l2_subdev_pad_config *cfg,
+				 struct v4l2_subdev_mbus_code_enum *code)
+{
+	if (code->index > 0)
+		return -EINVAL;
+
+	code->code = MEDIA_BUS_FMT_SGRBG10_1X10;
+
+	return 0;
+}
+
+static int hm11b1_enum_frame_size(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_pad_config *cfg,
+				  struct v4l2_subdev_frame_size_enum *fse)
+{
+	if (fse->index >= ARRAY_SIZE(supported_modes))
+		return -EINVAL;
+
+	if (fse->code != MEDIA_BUS_FMT_SGRBG10_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 hm11b1_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	struct hm11b1 *hm11b1 = to_hm11b1(sd);
+
+	mutex_lock(&hm11b1->mutex);
+	hm11b1_update_pad_format(&supported_modes[0],
+				 v4l2_subdev_get_try_format(sd, fh->pad, 0));
+	mutex_unlock(&hm11b1->mutex);
+
+	return 0;
+}
+
+static const struct v4l2_subdev_video_ops hm11b1_video_ops = {
+	.s_stream = hm11b1_set_stream,
+};
+
+static const struct v4l2_subdev_pad_ops hm11b1_pad_ops = {
+	.set_fmt = hm11b1_set_format,
+	.get_fmt = hm11b1_get_format,
+	.enum_mbus_code = hm11b1_enum_mbus_code,
+	.enum_frame_size = hm11b1_enum_frame_size,
+};
+
+static const struct v4l2_subdev_ops hm11b1_subdev_ops = {
+	.video = &hm11b1_video_ops,
+	.pad = &hm11b1_pad_ops,
+};
+
+static const struct media_entity_operations hm11b1_subdev_entity_ops = {
+	.link_validate = v4l2_subdev_link_validate,
+};
+
+static const struct v4l2_subdev_internal_ops hm11b1_internal_ops = {
+	.open = hm11b1_open,
+};
+
+static int hm11b1_identify_module(struct hm11b1 *hm11b1)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&hm11b1->sd);
+	int ret;
+	u32 val;
+
+	ret = hm11b1_read_reg(hm11b1, HM11B1_REG_CHIP_ID, 2, &val);
+	if (ret)
+		return ret;
+
+	if (val != HM11B1_CHIP_ID) {
+		dev_err(&client->dev, "chip id mismatch: %x!=%x",
+			HM11B1_CHIP_ID, val);
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+static int hm11b1_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct hm11b1 *hm11b1 = to_hm11b1(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(&hm11b1->mutex);
+
+	return 0;
+}
+
+static int hm11b1_probe(struct i2c_client *client)
+{
+	struct hm11b1 *hm11b1;
+	int ret = 0;
+
+	hm11b1 = devm_kzalloc(&client->dev, sizeof(*hm11b1), GFP_KERNEL);
+	if (!hm11b1)
+		return -ENOMEM;
+
+	v4l2_i2c_subdev_init(&hm11b1->sd, client, &hm11b1_subdev_ops);
+	ret = hm11b1_identify_module(hm11b1);
+	if (ret) {
+		dev_err(&client->dev, "failed to find sensor: %d", ret);
+		return ret;
+	}
+
+	mutex_init(&hm11b1->mutex);
+	hm11b1->cur_mode = &supported_modes[0];
+	ret = hm11b1_init_controls(hm11b1);
+	if (ret) {
+		dev_err(&client->dev, "failed to init controls: %d", ret);
+		goto probe_error_v4l2_ctrl_handler_free;
+	}
+
+	hm11b1->sd.internal_ops = &hm11b1_internal_ops;
+	hm11b1->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	hm11b1->sd.entity.ops = &hm11b1_subdev_entity_ops;
+	hm11b1->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+	hm11b1->pad.flags = MEDIA_PAD_FL_SOURCE;
+	ret = media_entity_pads_init(&hm11b1->sd.entity, 1, &hm11b1->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_common(&hm11b1->sd);
+	if (ret < 0) {
+		dev_err(&client->dev, "failed to register V4L2 subdev: %d",
+			ret);
+		goto probe_error_media_entity_cleanup;
+	}
+
+	/*
+	 * 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(&hm11b1->sd.entity);
+
+probe_error_v4l2_ctrl_handler_free:
+	v4l2_ctrl_handler_free(hm11b1->sd.ctrl_handler);
+	mutex_destroy(&hm11b1->mutex);
+
+	return ret;
+}
+
+static const struct dev_pm_ops hm11b1_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(hm11b1_suspend, hm11b1_resume)
+};
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id hm11b1_acpi_ids[] = {
+	{"HM11B1"},
+	{}
+};
+
+MODULE_DEVICE_TABLE(acpi, hm11b1_acpi_ids);
+#endif
+
+static struct i2c_driver hm11b1_i2c_driver = {
+	.driver = {
+		.name = "hm11b1",
+		.pm = &hm11b1_pm_ops,
+		.acpi_match_table = ACPI_PTR(hm11b1_acpi_ids),
+	},
+	.probe_new = hm11b1_probe,
+	.remove = hm11b1_remove,
+};
+
+module_i2c_driver(hm11b1_i2c_driver);
+
+MODULE_AUTHOR("Qiu, Tianshu <tian.shu.qiu@intel.com>");
+MODULE_AUTHOR("Shawn Tu <shawnx.tu@intel.com>");
+MODULE_AUTHOR("Bingbu Cao <bingbu.cao@intel.com>");
+MODULE_AUTHOR("Lai, Jim <jim.lai@intel.com>");
+MODULE_DESCRIPTION("Himax HM11B1 sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/ov01a1s.c b/drivers/media/i2c/ov01a1s.c
index 44c991053b12..1d05b75347a1 100644
--- a/drivers/media/i2c/ov01a1s.c
+++ b/drivers/media/i2c/ov01a1s.c
@@ -11,8 +11,8 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-fwnode.h>
 
-#define OV01A1S_LINK_FREQ_400MHZ	400000000ULL
-#define OV01A1S_SCLK			72000000LL
+#define OV01A1S_LINK_FREQ_400MHZ		400000000ULL
+#define OV01A1S_SCLK			40000000LL
 #define OV01A1S_MCLK			19200000
 #define OV01A1S_DATA_LANES		1
 #define OV01A1S_RGB_DEPTH		10
@@ -46,7 +46,7 @@
 #define OV01A1S_ANAL_GAIN_STEP		1
 
 /* Digital gain controls from sensor */
-#define OV01A1S_REG_DGTL_GAIN		0x350A //24bits
+#define OV01A1S_REG_DGTL_GAIN		0x350A
 #define OV01A1S_DGTL_GAIN_MIN		0
 #define OV01A1S_DGTL_GAIN_MAX		0xfff
 #define OV01A1S_DGTL_GAIN_STEP		1
@@ -101,7 +101,6 @@ struct ov01a1s_mode {
 static const struct ov01a1s_reg mipi_data_rate_720mbps[] = {
 };
 
-//RAW 10bit 1296x736_30fps_MIPI 480Mbps/lane
 static const struct ov01a1s_reg sensor_1296x800_setting[] = {
 	{0x0103, 0x01},
 	{0x0302, 0x00},
@@ -214,12 +213,10 @@ static const struct ov01a1s_reg sensor_1296x800_setting[] = {
 	{0x4301, 0x00},
 	{0x4302, 0x0f},
 	{0x4503, 0x00},
-    //{DATA_8BITS, {0x4601, 0x20},
-	{0x4601, 0x50},  // PC
+	{0x4601, 0x50},
 	{0x481f, 0x34},
 	{0x4825, 0x33},
-    //{DATA_8BITS, {0x4837, 0x11},
-	{0x4837, 0x14},   // PC
+	{0x4837, 0x14},
 	{0x4881, 0x40},
 	{0x4883, 0x01},
 	{0x4890, 0x00},
@@ -229,32 +226,25 @@ static const struct ov01a1s_reg sensor_1296x800_setting[] = {
 	{0x4b0d, 0x00},
 	{0x450a, 0x04},
 	{0x450b, 0x00},
-    //{DATA_8BITS, {0x5000, 0x75},
 	{0x5000, 0x65},
 	{0x5004, 0x00},
 	{0x5080, 0x40},
 	{0x5200, 0x18},
 	{0x4837, 0x14},
-
-    // key setting for 19.2Mhz, 1296x736
 	{0x0305, 0xf4},
-    //{DATA_8BITS, {0x0323, 0x05},
-    //{DATA_8BITS, {0x0325, 0x2c},
-	{0x0325, 0xc2},                     //   PC
+	{0x0325, 0xc2},
 	{0x3808, 0x05},
-	{0x3809, 0x10},  //00
-	{0x380a, 0x03},//{DATA_8BITS, {0x380a, 0x02},  //03
-	{0x380b, 0x20},//{DATA_8BITS, {0x380b, 0xe0},  //20
-	{0x380c, 0x05},  //02
-	{0x380d, 0xd0},  //e8
+	{0x3809, 0x10},
+	{0x380a, 0x03},
+	{0x380b, 0x20},
+	{0x380c, 0x02},
+	{0x380d, 0xe8},
 	{0x380e, 0x03},
 	{0x380f, 0x80},
 	{0x3810, 0x00},
-	{0x3811, 0x00},  //09
+	{0x3811, 0x00},
 	{0x3812, 0x00},
-    //	{DATA_8BITS, {0x3813, 0x08},
-	{0x3813, 0x08}, // for demo
-
+	{0x3813, 0x09},
 	{0x3820, 0x88},
 	{0x373d, 0x24},
 };
@@ -264,7 +254,7 @@ static const char * const ov01a1s_test_pattern_menu[] = {
 	"Color Bar",
 	"Top-Bottom Darker Color Bar",
 	"Right-Left Darker Color Bar",
-	"Bottom-Top Darker Color Bar",
+	"Color Bar type 4",
 };
 
 static const s64 link_freq_menu_items[] = {
@@ -284,7 +274,7 @@ static const struct ov01a1s_mode supported_modes[] = {
 	{
 		.width = 1296,
 		.height = 800,
-		.hts = 1080,
+		.hts = 744,
 		.vts_def = OV01A1S_VTS_DEF,
 		.vts_min = OV01A1S_VTS_MIN,
 		.reg_list = {
@@ -390,7 +380,7 @@ static int ov01a1s_write_reg(struct ov01a1s *ov01a1s, u16 reg, u16 len, u32 val)
 }
 
 static int ov01a1s_write_reg_list(struct ov01a1s *ov01a1s,
-				 const struct ov01a1s_reg_list *r_list)
+				  const struct ov01a1s_reg_list *r_list)
 {
 	struct i2c_client *client = v4l2_get_subdevdata(&ov01a1s->sd);
 	unsigned int i;
@@ -398,7 +388,7 @@ static int ov01a1s_write_reg_list(struct ov01a1s *ov01a1s,
 
 	for (i = 0; i < r_list->num_of_regs; i++) {
 		ret = ov01a1s_write_reg(ov01a1s, r_list->regs[i].address, 1,
-				       r_list->regs[i].val);
+					r_list->regs[i].val);
 		if (ret) {
 			dev_err_ratelimited(&client->dev,
 					    "write reg 0x%4.4x return err = %d",
@@ -412,8 +402,7 @@ static int ov01a1s_write_reg_list(struct ov01a1s *ov01a1s,
 
 static int ov01a1s_update_digital_gain(struct ov01a1s *ov01a1s, u32 d_gain)
 {
-	// set digital gain
-	u32 real = d_gain; // (1024 << 6) = 1X DG
+	u32 real = d_gain;
 
 	real = (real << 6);
 
@@ -423,7 +412,7 @@ static int ov01a1s_update_digital_gain(struct ov01a1s *ov01a1s, u32 d_gain)
 static int ov01a1s_test_pattern(struct ov01a1s *ov01a1s, u32 pattern)
 {
 	if (pattern)
-		pattern = pattern << OV01A1S_TEST_PATTERN_BAR_SHIFT |
+		pattern = (pattern - 1) << OV01A1S_TEST_PATTERN_BAR_SHIFT |
 			  OV01A1S_TEST_PATTERN_ENABLE;
 
 	return ov01a1s_write_reg(ov01a1s, OV01A1S_REG_TEST_PATTERN, 1, pattern);
@@ -455,7 +444,7 @@ static int ov01a1s_set_ctrl(struct v4l2_ctrl *ctrl)
 	switch (ctrl->id) {
 	case V4L2_CID_ANALOGUE_GAIN:
 		ret = ov01a1s_write_reg(ov01a1s, OV01A1S_REG_ANALOG_GAIN, 2,
-				       ctrl->val << 4);
+					ctrl->val << 4);
 		break;
 
 	case V4L2_CID_DIGITAL_GAIN:
@@ -464,12 +453,12 @@ static int ov01a1s_set_ctrl(struct v4l2_ctrl *ctrl)
 
 	case V4L2_CID_EXPOSURE:
 		ret = ov01a1s_write_reg(ov01a1s, OV01A1S_REG_EXPOSURE, 2,
-				       ctrl->val);
+					ctrl->val);
 		break;
 
 	case V4L2_CID_VBLANK:
 		ret = ov01a1s_write_reg(ov01a1s, OV01A1S_REG_VTS, 2,
-				       ov01a1s->cur_mode->height + ctrl->val);
+					ov01a1s->cur_mode->height + ctrl->val);
 		break;
 
 	case V4L2_CID_TEST_PATTERN:
@@ -508,30 +497,31 @@ static int ov01a1s_init_controls(struct ov01a1s *ov01a1s)
 	cur_mode = ov01a1s->cur_mode;
 	size = ARRAY_SIZE(link_freq_menu_items);
 
-	ov01a1s->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &ov01a1s_ctrl_ops,
-						   V4L2_CID_LINK_FREQ,
-						   size - 1, 0,
-						   link_freq_menu_items);
+	ov01a1s->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr,
+						    &ov01a1s_ctrl_ops,
+						    V4L2_CID_LINK_FREQ,
+						    size - 1, 0,
+						    link_freq_menu_items);
 	if (ov01a1s->link_freq)
 		ov01a1s->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
 
 	pixel_rate = to_pixel_rate(OV01A1S_LINK_FREQ_400MHZ_INDEX);
 	ov01a1s->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &ov01a1s_ctrl_ops,
-					       V4L2_CID_PIXEL_RATE, 0,
-					       pixel_rate, 1, pixel_rate);
+						V4L2_CID_PIXEL_RATE, 0,
+						pixel_rate, 1, pixel_rate);
 
 	vblank_min = cur_mode->vts_min - cur_mode->height;
 	vblank_max = OV01A1S_VTS_MAX - cur_mode->height;
 	vblank_default = cur_mode->vts_def - cur_mode->height;
 	ov01a1s->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov01a1s_ctrl_ops,
-					   V4L2_CID_VBLANK, vblank_min,
-					   vblank_max, 1, vblank_default);
+					    V4L2_CID_VBLANK, vblank_min,
+					    vblank_max, 1, vblank_default);
 
 	h_blank = to_pixels_per_line(cur_mode->hts, cur_mode->link_freq_index);
 	h_blank -= cur_mode->width;
 	ov01a1s->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov01a1s_ctrl_ops,
-					   V4L2_CID_HBLANK, h_blank, h_blank, 1,
-					   h_blank);
+					    V4L2_CID_HBLANK, h_blank, h_blank,
+					    1, h_blank);
 	if (ov01a1s->hblank)
 		ov01a1s->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
 
@@ -543,10 +533,11 @@ static int ov01a1s_init_controls(struct ov01a1s *ov01a1s)
 			  OV01A1S_DGTL_GAIN_STEP, OV01A1S_DGTL_GAIN_DEFAULT);
 	exposure_max = cur_mode->vts_def - OV01A1S_EXPOSURE_MAX_MARGIN;
 	ov01a1s->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &ov01a1s_ctrl_ops,
-					     V4L2_CID_EXPOSURE,
-					     OV01A1S_EXPOSURE_MIN, exposure_max,
-					     OV01A1S_EXPOSURE_STEP,
-					     exposure_max);
+					      V4L2_CID_EXPOSURE,
+					      OV01A1S_EXPOSURE_MIN,
+					      exposure_max,
+					      OV01A1S_EXPOSURE_STEP,
+					      exposure_max);
 	v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &ov01a1s_ctrl_ops,
 				     V4L2_CID_TEST_PATTERN,
 				     ARRAY_SIZE(ov01a1s_test_pattern_menu) - 1,
@@ -560,7 +551,7 @@ static int ov01a1s_init_controls(struct ov01a1s *ov01a1s)
 }
 
 static void ov01a1s_update_pad_format(const struct ov01a1s_mode *mode,
-				     struct v4l2_mbus_framefmt *fmt)
+				      struct v4l2_mbus_framefmt *fmt)
 {
 	fmt->width = mode->width;
 	fmt->height = mode->height;
@@ -595,7 +586,7 @@ static int ov01a1s_start_streaming(struct ov01a1s *ov01a1s)
 		return ret;
 
 	ret = ov01a1s_write_reg(ov01a1s, OV01A1S_REG_MODE_SELECT, 1,
-			       OV01A1S_MODE_STREAMING);
+				OV01A1S_MODE_STREAMING);
 	if (ret)
 		dev_err(&client->dev, "failed to start streaming");
 
@@ -605,9 +596,11 @@ static int ov01a1s_start_streaming(struct ov01a1s *ov01a1s)
 static void ov01a1s_stop_streaming(struct ov01a1s *ov01a1s)
 {
 	struct i2c_client *client = v4l2_get_subdevdata(&ov01a1s->sd);
+	int ret = 0;
 
-	if (ov01a1s_write_reg(ov01a1s, OV01A1S_REG_MODE_SELECT, 1,
-			     OV01A1S_MODE_STANDBY))
+	ret = ov01a1s_write_reg(ov01a1s, OV01A1S_REG_MODE_SELECT, 1,
+				OV01A1S_MODE_STANDBY);
+	if (ret)
 		dev_err(&client->dev, "failed to stop streaming");
 }
 
@@ -684,8 +677,8 @@ 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_format *fmt)
+			      struct v4l2_subdev_pad_config *cfg,
+			      struct v4l2_subdev_format *fmt)
 {
 	struct ov01a1s *ov01a1s = to_ov01a1s(sd);
 	const struct ov01a1s_mode *mode;
@@ -724,8 +717,8 @@ 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_format *fmt)
+			      struct v4l2_subdev_pad_config *cfg,
+			      struct v4l2_subdev_format *fmt)
 {
 	struct ov01a1s *ov01a1s = to_ov01a1s(sd);
 
@@ -742,8 +735,8 @@ 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_mbus_code_enum *code)
+				  struct v4l2_subdev_pad_config *cfg,
+				  struct v4l2_subdev_mbus_code_enum *code)
 {
 	if (code->index > 0)
 		return -EINVAL;
@@ -754,8 +747,8 @@ 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_frame_size_enum *fse)
+				   struct v4l2_subdev_pad_config *cfg,
+				   struct v4l2_subdev_frame_size_enum *fse)
 {
 	if (fse->index >= ARRAY_SIZE(supported_modes))
 		return -EINVAL;
@@ -777,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->pad, 0));
 	mutex_unlock(&ov01a1s->mutex);
 
 	return 0;
@@ -908,7 +901,7 @@ static const struct dev_pm_ops ov01a1s_pm_ops = {
 
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id ov01a1s_acpi_ids[] = {
-	{"OVTI01AF"}, /* OVTI01AF*/
+	{ "OVTI01AF" },
 	{}
 };
 
@@ -917,7 +910,7 @@ MODULE_DEVICE_TABLE(acpi, ov01a1s_acpi_ids);
 
 static struct i2c_driver ov01a1s_i2c_driver = {
 	.driver = {
-		.name = "ov01a1s", /* ov01a1s*/
+		.name = "ov01a1s",
 		.pm = &ov01a1s_pm_ops,
 		.acpi_match_table = ACPI_PTR(ov01a1s_acpi_ids),
 	},
@@ -927,6 +920,7 @@ static struct i2c_driver ov01a1s_i2c_driver = {
 
 module_i2c_driver(ov01a1s_i2c_driver);
 
+MODULE_AUTHOR("Xu, Chongyang <chongyang.xu@intel.com>");
 MODULE_AUTHOR("Lai, Jim <jim.lai@intel.com>");
 MODULE_AUTHOR("Qiu, Tianshu <tian.shu.qiu@intel.com>");
 MODULE_AUTHOR("Shawn Tu <shawnx.tu@intel.com>");
diff --git a/drivers/media/pci/intel/Kconfig b/drivers/media/pci/intel/Kconfig
index eb19872b1df0..8ea99271932b 100644
--- a/drivers/media/pci/intel/Kconfig
+++ b/drivers/media/pci/intel/Kconfig
@@ -30,4 +30,28 @@ config VIDEO_INTEL_IPU6
 	  To compile this driver, say Y here!
 endchoice
 
+config VIDEO_INTEL_IPU_TPG
+	bool "Compile for TPG driver"
+	help
+	  If selected, TPG device nodes would be created.
+
+	  Recommended for driver developers only.
+
+	  If you want to the TPG devices exposed to user as media entity,
+	  you must select this option, otherwise no.
+
+config VIDEO_INTEL_IPU_WERROR
+	bool "Force GCC to throw an error instead of a warning when compiling"
+	depends on VIDEO_INTEL_IPU
+	depends on EXPERT
+	depends on !COMPILE_TEST
+	default n
+	help
+	  Add -Werror to the build flags for (and only for) intel ipu module.
+	  Do not enable this unless you are writing code for the ipu module.
+
+	  Recommended for driver developers only.
+
+	  If in doubt, say "N".
+
 source "drivers/media/pci/intel/ipu3/Kconfig"
diff --git a/drivers/media/pci/intel/ipu-bus.c b/drivers/media/pci/intel/ipu-bus.c
index 3bc7277ae16b..1c671535fe27 100644
--- a/drivers/media/pci/intel/ipu-bus.c
+++ b/drivers/media/pci/intel/ipu-bus.c
@@ -196,6 +196,7 @@ void ipu_bus_del_devices(struct pci_dev *pdev)
 	mutex_lock(&ipu_bus_mutex);
 
 	list_for_each_entry_safe(adev, save, &isp->devices, list) {
+		pm_runtime_disable(&adev->dev);
 		list_del(&adev->list);
 		device_unregister(&adev->dev);
 	}
diff --git a/drivers/media/pci/intel/ipu-buttress.c b/drivers/media/pci/intel/ipu-buttress.c
index 77cf8556dc00..2ee8a9e554b6 100644
--- a/drivers/media/pci/intel/ipu-buttress.c
+++ b/drivers/media/pci/intel/ipu-buttress.c
@@ -39,6 +39,7 @@
 #define BUTTRESS_CSE_FWRESET_TIMEOUT		100000
 
 #define BUTTRESS_IPC_TX_TIMEOUT			1000
+#define BUTTRESS_IPC_RESET_TIMEOUT		2000
 #define BUTTRESS_IPC_RX_TIMEOUT			1000
 #define BUTTRESS_IPC_VALIDITY_TIMEOUT		1000000
 #define BUTTRESS_TSC_SYNC_TIMEOUT		5000
@@ -74,8 +75,7 @@ static const u32 ipu_adev_irq_mask[] = {
 int ipu_buttress_ipc_reset(struct ipu_device *isp, struct ipu_buttress_ipc *ipc)
 {
 	struct ipu_buttress *b = &isp->buttress;
-	unsigned long tout_jfs;
-	unsigned int tout = 500;
+	unsigned int timeout = BUTTRESS_IPC_RESET_TIMEOUT;
 	u32 val = 0, csr_in_clr;
 
 	if (!isp->secure_mode) {
@@ -91,7 +91,6 @@ int ipu_buttress_ipc_reset(struct ipu_device *isp, struct ipu_buttress_ipc *ipc)
 
 	/* Set peer CSR bit IPC_PEER_COMP_ACTIONS_RST_PHASE1 */
 	writel(ENTRY, isp->base + ipc->csr_out);
-
 	/*
 	 * Clear-by-1 all CSR bits EXCEPT following
 	 * bits:
@@ -104,53 +103,43 @@ int ipu_buttress_ipc_reset(struct ipu_device *isp, struct ipu_buttress_ipc *ipc)
 		BUTTRESS_IU2CSECSR_IPC_PEER_ACKED_REG_VALID |
 		BUTTRESS_IU2CSECSR_IPC_PEER_ASSERTED_REG_VALID_REQ | QUERY;
 
-	/*
-	 * How long we should wait here?
-	 */
-	tout_jfs = jiffies + msecs_to_jiffies(tout);
-	do {
+	while (timeout--) {
+		usleep_range(400, 500);
 		val = readl(isp->base + ipc->csr_in);
-		dev_dbg(&isp->pdev->dev, "%s: csr_in = %x\n", __func__, val);
-		if (val & ENTRY) {
-			if (val & EXIT) {
-				dev_dbg(&isp->pdev->dev,
-					"%s:%s & %s\n", __func__,
-					"IPC_PEER_COMP_ACTIONS_RST_PHASE1",
-					"IPC_PEER_COMP_ACTIONS_RST_PHASE2");
-				/*
-				 * 1) Clear-by-1 CSR bits
-				 * (IPC_PEER_COMP_ACTIONS_RST_PHASE1,
-				 * IPC_PEER_COMP_ACTIONS_RST_PHASE2).
-				 * 2) Set peer CSR bit
-				 * IPC_PEER_QUERIED_IP_COMP_ACTIONS_RST_PHASE.
-				 */
-				writel(ENTRY | EXIT,
-				       isp->base + ipc->csr_in);
-
-				writel(QUERY, isp->base + ipc->csr_out);
-
-				tout_jfs = jiffies + msecs_to_jiffies(tout);
-				continue;
-			} else {
-				dev_dbg(&isp->pdev->dev,
-					"%s:IPC_PEER_COMP_ACTIONS_RST_PHASE1\n",
-					__func__);
-				/*
-				 * 1) Clear-by-1 CSR bits
-				 * (IPC_PEER_COMP_ACTIONS_RST_PHASE1,
-				 * IPC_PEER_QUERIED_IP_COMP_ACTIONS_RST_PHASE).
-				 * 2) Set peer CSR bit
-				 * IPC_PEER_COMP_ACTIONS_RST_PHASE1.
-				 */
-				writel(ENTRY | QUERY,
-				       isp->base + ipc->csr_in);
-
-				writel(ENTRY, isp->base + ipc->csr_out);
-
-				tout_jfs = jiffies + msecs_to_jiffies(tout);
-				continue;
-			}
-		} else if (val & EXIT) {
+		switch (val) {
+		case (ENTRY | EXIT):
+		case (ENTRY | EXIT | QUERY):
+			dev_dbg(&isp->pdev->dev,
+				"%s:%s & %s\n", __func__,
+				"IPC_PEER_COMP_ACTIONS_RST_PHASE1",
+				"IPC_PEER_COMP_ACTIONS_RST_PHASE2");
+			/*
+			 * 1) Clear-by-1 CSR bits
+			 * (IPC_PEER_COMP_ACTIONS_RST_PHASE1,
+			 * IPC_PEER_COMP_ACTIONS_RST_PHASE2).
+			 * 2) Set peer CSR bit
+			 * IPC_PEER_QUERIED_IP_COMP_ACTIONS_RST_PHASE.
+			 */
+			writel(ENTRY | EXIT, isp->base + ipc->csr_in);
+			writel(QUERY, isp->base + ipc->csr_out);
+			break;
+		case ENTRY:
+		case ENTRY | QUERY:
+			dev_dbg(&isp->pdev->dev,
+				"%s:IPC_PEER_COMP_ACTIONS_RST_PHASE1\n",
+				__func__);
+			/*
+			 * 1) Clear-by-1 CSR bits
+			 * (IPC_PEER_COMP_ACTIONS_RST_PHASE1,
+			 * IPC_PEER_QUERIED_IP_COMP_ACTIONS_RST_PHASE).
+			 * 2) Set peer CSR bit
+			 * IPC_PEER_COMP_ACTIONS_RST_PHASE1.
+			 */
+			writel(ENTRY | QUERY, isp->base + ipc->csr_in);
+			writel(ENTRY, isp->base + ipc->csr_out);
+			break;
+		case EXIT:
+		case EXIT | QUERY:
 			dev_dbg(&isp->pdev->dev,
 				"%s: IPC_PEER_COMP_ACTIONS_RST_PHASE2\n",
 				__func__);
@@ -168,30 +157,25 @@ int ipu_buttress_ipc_reset(struct ipu_device *isp, struct ipu_buttress_ipc *ipc)
 			 * IPC_PEER_COMP_ACTIONS_RST_PHASE2.
 			 */
 			writel(EXIT, isp->base + ipc->csr_in);
-
 			writel(0, isp->base + ipc->db0_in);
-
 			writel(csr_in_clr, isp->base + ipc->csr_in);
-
 			writel(EXIT, isp->base + ipc->csr_out);
 
 			/*
 			 * Read csr_in again to make sure if RST_PHASE2 is done.
 			 * If csr_in is QUERY, it should be handled again.
 			 */
-			usleep_range(100, 500);
+			usleep_range(200, 300);
 			val = readl(isp->base + ipc->csr_in);
 			if (val & QUERY) {
 				dev_dbg(&isp->pdev->dev,
 					"%s: RST_PHASE2 retry csr_in = %x\n",
 					__func__, val);
-				continue;
+				break;
 			}
-
 			mutex_unlock(&b->ipc_mutex);
-
 			return 0;
-		} else if (val & QUERY) {
+		case QUERY:
 			dev_dbg(&isp->pdev->dev,
 				"%s: %s\n", __func__,
 				"IPC_PEER_QUERIED_IP_COMP_ACTIONS_RST_PHASE");
@@ -202,17 +186,18 @@ int ipu_buttress_ipc_reset(struct ipu_device *isp, struct ipu_buttress_ipc *ipc)
 			 * IPC_PEER_COMP_ACTIONS_RST_PHASE1
 			 */
 			writel(QUERY, isp->base + ipc->csr_in);
-
 			writel(ENTRY, isp->base + ipc->csr_out);
-
-			tout_jfs = jiffies + msecs_to_jiffies(tout);
+			break;
+		default:
+			dev_dbg_ratelimited(&isp->pdev->dev,
+					    "%s: unexpected CSR 0x%x\n",
+					    __func__, val);
+			break;
 		}
-		usleep_range(100, 500);
-	} while (!time_after(jiffies, tout_jfs));
+	}
 
 	mutex_unlock(&b->ipc_mutex);
-
-	dev_err(&isp->pdev->dev, "Timed out while waiting for CSE!\n");
+	dev_err(&isp->pdev->dev, "Timed out while waiting for CSE\n");
 
 	return -ETIMEDOUT;
 }
@@ -244,7 +229,7 @@ ipu_buttress_ipc_validity_open(struct ipu_device *isp,
 	ret = readl_poll_timeout(addr, val, val & mask, 200, tout);
 	if (ret) {
 		val = readl(addr);
-		dev_err(&isp->pdev->dev, "CSE validity timeout 0x%x!\n", val);
+		dev_err(&isp->pdev->dev, "CSE validity timeout 0x%x\n", val);
 		ipu_buttress_ipc_validity_close(isp, ipc);
 	}
 
@@ -346,7 +331,7 @@ static int ipu_buttress_ipc_send_bulk(struct ipu_device *isp,
 		}
 	}
 
-	dev_dbg(&isp->pdev->dev, "bulk IPC commands completed\n");
+	dev_dbg(&isp->pdev->dev, "bulk IPC commands done\n");
 
 out:
 	ipu_buttress_ipc_validity_close(isp, ipc);
@@ -717,10 +702,10 @@ int ipu_buttress_reset_authentication(struct ipu_device *isp)
 				 BUTTRESS_CSE_FWRESET_TIMEOUT);
 	if (ret) {
 		dev_err(&isp->pdev->dev,
-			"Timed out while resetting authentication state!\n");
+			"Time out while resetting authentication state\n");
 	} else {
 		dev_info(&isp->pdev->dev,
-			 "FW reset for authentication done!\n");
+			 "FW reset for authentication done\n");
 		writel(0, isp->base + BUTTRESS_REG_FW_RESET_CTL);
 		/* leave some time for HW restore */
 		usleep_range(800, 1000);
@@ -843,7 +828,7 @@ int ipu_buttress_authenticate(struct ipu_device *isp)
 				   (data & mask) == fail), 500,
 				  BUTTRESS_CSE_BOOTLOAD_TIMEOUT);
 	if (rval) {
-		dev_err(&isp->pdev->dev, "CSE boot_load timeout.\n");
+		dev_err(&isp->pdev->dev, "CSE boot_load timeout\n");
 		goto iunit_power_off;
 	}
 
@@ -858,7 +843,7 @@ int ipu_buttress_authenticate(struct ipu_device *isp)
 				  data, data == BOOTLOADER_MAGIC_KEY, 500,
 				  BUTTRESS_CSE_BOOTLOAD_TIMEOUT);
 	if (rval) {
-		dev_err(&isp->pdev->dev, "Expect magic number timeout 0x%x.\n",
+		dev_err(&isp->pdev->dev, "Expect magic number timeout 0x%x\n",
 			data);
 		goto iunit_power_off;
 	}
@@ -918,7 +903,7 @@ static int ipu_buttress_send_tsc_request(struct ipu_device *isp)
 	val = readl(isp->base + BUTTRESS_REG_PWR_STATE);
 	val = (val & mask) >> shift;
 	if (val == BUTTRESS_PWR_STATE_HH_STATE_ERR) {
-		dev_err(&isp->pdev->dev, "Start tsc sync failed!\n");
+		dev_err(&isp->pdev->dev, "Start tsc sync failed\n");
 		return -EINVAL;
 	}
 
@@ -927,7 +912,7 @@ static int ipu_buttress_send_tsc_request(struct ipu_device *isp)
 				 ((val & mask) >> shift == done), 500,
 				 BUTTRESS_TSC_SYNC_TIMEOUT);
 	if (ret)
-		dev_err(&isp->pdev->dev, "Start tsc sync timeout!\n");
+		dev_err(&isp->pdev->dev, "Start tsc sync timeout\n");
 
 	return ret;
 }
@@ -955,7 +940,7 @@ int ipu_buttress_start_tsc_sync(struct ipu_device *isp)
 		return ret;
 	}
 
-	dev_err(&isp->pdev->dev, "TSC sync failed(timeout).\n");
+	dev_err(&isp->pdev->dev, "TSC sync failed(timeout)\n");
 
 	return -ETIMEDOUT;
 }
@@ -1440,7 +1425,7 @@ int ipu_buttress_init(struct ipu_device *isp)
 	ipu_buttress_set_secure_mode(isp);
 	isp->secure_mode = ipu_buttress_get_secure_mode(isp);
 	if (isp->secure_mode != secure_mode_enable)
-		dev_warn(&isp->pdev->dev, "Unable to set secure mode!\n");
+		dev_warn(&isp->pdev->dev, "Unable to set secure mode\n");
 
 	dev_info(&isp->pdev->dev, "IPU in %s mode\n",
 		 isp->secure_mode ? "secure" : "non-secure");
@@ -1477,10 +1462,10 @@ int ipu_buttress_init(struct ipu_device *isp)
 	do {
 		rval = ipu_buttress_ipc_reset(isp, &b->cse);
 		if (rval) {
-			dev_err(&isp->pdev->dev,
-				"IPC reset protocol failed, retry!\n");
+			dev_warn(&isp->pdev->dev,
+				 "IPC reset protocol failed, retrying\n");
 		} else {
-			dev_dbg(&isp->pdev->dev, "IPC reset completed!\n");
+			dev_info(&isp->pdev->dev, "IPC reset done\n");
 			return 0;
 		}
 	} while (ipc_reset_retry--);
diff --git a/drivers/media/pci/intel/ipu-isys-csi2.c b/drivers/media/pci/intel/ipu-isys-csi2.c
index 4838537b0c40..bf0aba76c6ae 100644
--- a/drivers/media/pci/intel/ipu-isys-csi2.c
+++ b/drivers/media/pci/intel/ipu-isys-csi2.c
@@ -595,12 +595,15 @@ void ipu_isys_csi2_eof_event(struct ipu_isys_csi2 *csi2)
 
 	if (ip) {
 		frame_sequence = atomic_read(&ip->sequence);
+		spin_unlock_irqrestore(&csi2->isys->lock, flags);
 
-	spin_unlock_irqrestore(&csi2->isys->lock, flags);
-
-	dev_dbg(&csi2->isys->adev->dev, "eof_event::csi2-%i sequence: %i\n",
-		csi2->index, frame_sequence);
+		dev_dbg(&csi2->isys->adev->dev,
+			"eof_event::csi2-%i sequence: %i\n",
+			csi2->index, frame_sequence);
+		return;
 	}
+
+	spin_unlock_irqrestore(&csi2->isys->lock, flags);
 }
 
 /* Call this function only _after_ the sensor has been stopped */
diff --git a/drivers/media/pci/intel/ipu-isys-queue.c b/drivers/media/pci/intel/ipu-isys-queue.c
index 46d29d311098..10498dddaf09 100644
--- a/drivers/media/pci/intel/ipu-isys-queue.c
+++ b/drivers/media/pci/intel/ipu-isys-queue.c
@@ -359,14 +359,9 @@ ipu_isys_buffer_to_fw_frame_buff(struct ipu_fw_isys_frame_buff_set_abi *set,
 
 	set->send_irq_sof = 1;
 	set->send_resp_sof = 1;
-
 	set->send_irq_eof = 0;
 	set->send_resp_eof = 0;
-	/*
-	 * In tpg case, the stream start timeout if the capture ack irq
-	 * disabled. So keep it active while starting the stream, then close
-	 * it after the stream start succeed.
-	 */
+
 	if (ip->streaming)
 		set->send_irq_capture_ack = 0;
 	else
diff --git a/drivers/media/pci/intel/ipu-isys-video.c b/drivers/media/pci/intel/ipu-isys-video.c
index 709f1aa6dfad..a4088b30c144 100644
--- a/drivers/media/pci/intel/ipu-isys-video.c
+++ b/drivers/media/pci/intel/ipu-isys-video.c
@@ -508,7 +508,9 @@ static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
 static bool is_external(struct ipu_isys_video *av, struct media_entity *entity)
 {
 	struct v4l2_subdev *sd;
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
 	unsigned int i;
+#endif
 
 	/* All video nodes are ours. */
 	if (!is_media_entity_v4l2_subdev(entity))
@@ -519,10 +521,12 @@ static bool is_external(struct ipu_isys_video *av, struct media_entity *entity)
 		    strlen(IPU_ISYS_ENTITY_PREFIX)) != 0)
 		return true;
 
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
 	for (i = 0; i < av->isys->pdata->ipdata->tpg.ntpgs &&
 	     av->isys->tpg[i].isys; i++)
 		if (entity == &av->isys->tpg[i].asd.sd.entity)
 			return true;
+#endif
 
 	return false;
 }
@@ -922,9 +926,11 @@ static int start_stream_firmware(struct ipu_isys_video *av,
 	if (ip->csi2 && !v4l2_ctrl_g_ctrl(ip->csi2->store_csi2_header))
 		stream_cfg->input_pins[0].mipi_store_mode =
 		    IPU_FW_ISYS_MIPI_STORE_MODE_DISCARD_LONG_HEADER;
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
 	else if (ip->tpg && !v4l2_ctrl_g_ctrl(ip->tpg->store_csi2_header))
 		stream_cfg->input_pins[0].mipi_store_mode =
 		    IPU_FW_ISYS_MIPI_STORE_MODE_DISCARD_LONG_HEADER;
+#endif
 
 	stream_cfg->src = ip->source;
 	stream_cfg->vc = 0;
@@ -1238,7 +1244,9 @@ int ipu_isys_video_prepare_streaming(struct ipu_isys_video *av,
 	ip->csi2_be = NULL;
 	ip->csi2_be_soc = NULL;
 	ip->csi2 = NULL;
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
 	ip->tpg = NULL;
+#endif
 	ip->seq_index = 0;
 	memset(ip->seq, 0, sizeof(ip->seq));
 
diff --git a/drivers/media/pci/intel/ipu-isys-video.h b/drivers/media/pci/intel/ipu-isys-video.h
index ebfc30a5fae9..455b534b41f7 100644
--- a/drivers/media/pci/intel/ipu-isys-video.h
+++ b/drivers/media/pci/intel/ipu-isys-video.h
@@ -54,7 +54,10 @@ struct ipu_isys_pipeline {
 	struct ipu_isys_csi2_be *csi2_be;
 	struct ipu_isys_csi2_be_soc *csi2_be_soc;
 	struct ipu_isys_csi2 *csi2;
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
 	struct ipu_isys_tpg *tpg;
+#endif
+
 	/*
 	 * Number of capture queues, write access serialised using struct
 	 * ipu_isys.stream_mutex
diff --git a/drivers/media/pci/intel/ipu-isys.c b/drivers/media/pci/intel/ipu-isys.c
index c1657ed95599..69043915fd43 100644
--- a/drivers/media/pci/intel/ipu-isys.c
+++ b/drivers/media/pci/intel/ipu-isys.c
@@ -29,7 +29,9 @@
 #include "ipu-dma.h"
 #include "ipu-isys.h"
 #include "ipu-isys-csi2.h"
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
 #include "ipu-isys-tpg.h"
+#endif
 #include "ipu-isys-video.h"
 #include "ipu-platform-regs.h"
 #include "ipu-buttress.h"
@@ -45,7 +47,7 @@
 
 /* LTR & DID value are 10 bit at most */
 #define LTR_DID_VAL_MAX		1023
-#define LTR_DEFAULT_VALUE	0x64503C19
+#define LTR_DEFAULT_VALUE	0x70503C19
 #define FILL_TIME_DEFAULT_VALUE 0xFFF0783C
 #define LTR_DID_PKGC_2R		20
 #define LTR_DID_PKGC_8		100
@@ -131,8 +133,10 @@ isys_complete_ext_device_registration(struct ipu_isys *isys,
 
 static void isys_unregister_subdevices(struct ipu_isys *isys)
 {
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
 	const struct ipu_isys_internal_tpg_pdata *tpg =
 	    &isys->pdata->ipdata->tpg;
+#endif
 	const struct ipu_isys_internal_csi2_pdata *csi2 =
 	    &isys->pdata->ipdata->csi2;
 	unsigned int i;
@@ -141,8 +145,10 @@ static void isys_unregister_subdevices(struct ipu_isys *isys)
 	for (i = 0; i < NR_OF_CSI2_BE_SOC_DEV; i++)
 		ipu_isys_csi2_be_soc_cleanup(&isys->csi2_be_soc[i]);
 
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
 	for (i = 0; i < tpg->ntpgs; i++)
 		ipu_isys_tpg_cleanup(&isys->tpg[i]);
+#endif
 
 	for (i = 0; i < csi2->nports; i++)
 		ipu_isys_csi2_cleanup(&isys->csi2[i]);
@@ -150,8 +156,10 @@ static void isys_unregister_subdevices(struct ipu_isys *isys)
 
 static int isys_register_subdevices(struct ipu_isys *isys)
 {
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
 	const struct ipu_isys_internal_tpg_pdata *tpg =
 	    &isys->pdata->ipdata->tpg;
+#endif
 	const struct ipu_isys_internal_csi2_pdata *csi2 =
 	    &isys->pdata->ipdata->csi2;
 	struct ipu_isys_csi2_be_soc *csi2_be_soc;
@@ -175,6 +183,7 @@ static int isys_register_subdevices(struct ipu_isys *isys)
 		isys->isr_csi2_bits |= IPU_ISYS_UNISPART_IRQ_CSI2(i);
 	}
 
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
 	isys->tpg = devm_kcalloc(&isys->adev->dev, tpg->ntpgs,
 				 sizeof(*isys->tpg), GFP_KERNEL);
 	if (!isys->tpg) {
@@ -191,6 +200,7 @@ static int isys_register_subdevices(struct ipu_isys *isys)
 		if (rval)
 			goto fail;
 	}
+#endif
 
 	for (k = 0; k < NR_OF_CSI2_BE_SOC_DEV; k++) {
 		rval = ipu_isys_csi2_be_soc_init(&isys->csi2_be_soc[k],
@@ -234,6 +244,7 @@ static int isys_register_subdevices(struct ipu_isys *isys)
 		}
 	}
 
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
 	for (i = 0; i < tpg->ntpgs; i++) {
 		rval = media_create_pad_link(&isys->tpg[i].asd.sd.entity,
 					     TPG_PAD_SOURCE,
@@ -259,6 +270,7 @@ static int isys_register_subdevices(struct ipu_isys *isys)
 			}
 		}
 	}
+#endif
 
 	return 0;
 
@@ -349,6 +361,8 @@ static void set_iwake_ltrdid(struct ipu_isys *isys,
 	fc.bits.ltr_scale = ltr_scale;
 	fc.bits.did_val = did_val;
 	fc.bits.did_scale = 2;
+	dev_dbg(&isys->adev->dev,
+		"%s ltr: %d  did: %d", __func__, ltr_val, did_val);
 	writel(fc.value, isp->base + IPU_BUTTRESS_FABIC_CONTROL);
 }
 
@@ -379,7 +393,8 @@ void update_watermark_setting(struct ipu_isys *isys)
 	struct video_stream_watermark *p_watermark;
 	struct ltr_did ltrdid;
 	u16 calc_fill_time_us = 0;
-	u16 ltr, did;
+	u16 ltr = 0;
+	u16 did = 0;
 	u32 iwake_threshold, iwake_critical_threshold;
 	u64 threshold_bytes;
 	u64 isys_pb_datarate_mbs = 0;
@@ -411,6 +426,7 @@ void update_watermark_setting(struct ipu_isys *isys)
 	mutex_unlock(&iwake_watermark->mutex);
 
 	if (!isys_pb_datarate_mbs) {
+		enable_iwake(isys, false);
 		set_iwake_ltrdid(isys, 0, 0, LTR_IWAKE_OFF);
 		mutex_lock(&iwake_watermark->mutex);
 		set_iwake_register(isys, GDA_IRQ_CRITICAL_THRESHOLD_INDEX,
@@ -448,6 +464,8 @@ void update_watermark_setting(struct ipu_isys *isys)
 		iwake_critical_threshold = iwake_threshold +
 			(IS_PIXEL_BUFFER_PAGES - iwake_threshold) / 2;
 
+		dev_dbg(&isys->adev->dev, "%s threshold: %u  critical: %u",
+			__func__, iwake_threshold, iwake_critical_threshold);
 		set_iwake_ltrdid(isys, ltr, did, LTR_IWAKE_ON);
 		mutex_lock(&iwake_watermark->mutex);
 		set_iwake_register(isys,
@@ -569,11 +587,17 @@ static int isys_notifier_init(struct ipu_isys *isys)
 							 asd_struct_size,
 							 isys_fwnode_parse);
 
-	if (ret < 0)
+	if (ret < 0) {
+		dev_err(&isys->adev->dev,
+			"v4l2 parse_fwnode_endpoints() failed: %d\n", ret);
 		return ret;
+	}
 
-	if (list_empty(&isys->notifier.asd_list))
-		return -ENODEV;	/* no endpoint */
+	if (list_empty(&isys->notifier.asd_list)) {
+		/* isys probe could continue with async subdevs missing */
+		dev_warn(&isys->adev->dev, "no subdev found in graph\n");
+		return 0;
+	}
 
 	isys->notifier.ops = &isys_async_ops;
 	ret = v4l2_async_notifier_register(&isys->v4l2_dev, &isys->notifier);
@@ -586,6 +610,12 @@ static int isys_notifier_init(struct ipu_isys *isys)
 	return ret;
 }
 
+static void isys_notifier_cleanup(struct ipu_isys *isys)
+{
+	v4l2_async_notifier_unregister(&isys->notifier);
+	v4l2_async_notifier_cleanup(&isys->notifier);
+}
+
 static struct media_device_ops isys_mdev_ops = {
 	.link_notify = v4l2_pipeline_link_notify,
 };
@@ -622,15 +652,19 @@ static int isys_register_devices(struct ipu_isys *isys)
 	rval = isys_register_subdevices(isys);
 	if (rval)
 		goto out_v4l2_device_unregister;
+
 	rval = isys_notifier_init(isys);
 	if (rval)
 		goto out_isys_unregister_subdevices;
 	rval = v4l2_device_register_subdev_nodes(&isys->v4l2_dev);
 	if (rval)
-		goto out_isys_unregister_subdevices;
+		goto out_isys_notifier_cleanup;
 
 	return 0;
 
+out_isys_notifier_cleanup:
+	isys_notifier_cleanup(isys);
+
 out_isys_unregister_subdevices:
 	isys_unregister_subdevices(isys);
 
@@ -774,6 +808,7 @@ static void isys_remove(struct ipu_bus_device *adev)
 	isys_iwake_watermark_cleanup(isys);
 
 	ipu_trace_uninit(&adev->dev);
+	isys_notifier_cleanup(isys);
 	isys_unregister_devices(isys);
 	pm_qos_remove_request(&isys->pm_qos);
 
@@ -1326,9 +1361,11 @@ int isys_isr_one(struct ipu_bus_device *adev)
 		if (pipe->csi2)
 			ipu_isys_csi2_sof_event(pipe->csi2);
 
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
 #ifdef IPU_TPG_FRAME_SYNC
 		if (pipe->tpg)
 			ipu_isys_tpg_sof_event(pipe->tpg);
+#endif
 #endif
 		pipe->seq[pipe->seq_index].sequence =
 		    atomic_read(&pipe->sequence) - 1;
@@ -1344,9 +1381,11 @@ int isys_isr_one(struct ipu_bus_device *adev)
 		if (pipe->csi2)
 			ipu_isys_csi2_eof_event(pipe->csi2);
 
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
 #ifdef IPU_TPG_FRAME_SYNC
 		if (pipe->tpg)
 			ipu_isys_tpg_eof_event(pipe->tpg);
+#endif
 #endif
 
 		dev_dbg(&adev->dev,
diff --git a/drivers/media/pci/intel/ipu-isys.h b/drivers/media/pci/intel/ipu-isys.h
index 5d82b934b453..343f0d773b9d 100644
--- a/drivers/media/pci/intel/ipu-isys.h
+++ b/drivers/media/pci/intel/ipu-isys.h
@@ -16,7 +16,9 @@
 #include "ipu-isys-media.h"
 #include "ipu-isys-csi2.h"
 #include "ipu-isys-csi2-be.h"
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
 #include "ipu-isys-tpg.h"
+#endif
 #include "ipu-isys-video.h"
 #include "ipu-pdata.h"
 #include "ipu-fw-isys.h"
@@ -131,7 +133,9 @@ struct ipu_isys_sensor_info {
  * @lib_mutex: optional external library mutex
  * @pdata: platform data pointer
  * @csi2: CSI-2 receivers
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
  * @tpg: test pattern generators
+#endif
  * @csi2_be: CSI-2 back-ends
  * @fw: ISYS firmware binary (unsecure firmware)
  * @fw_sgt: fw scatterlist
@@ -171,7 +175,9 @@ struct ipu_isys {
 	struct ipu_isys_pdata *pdata;
 
 	struct ipu_isys_csi2 *csi2;
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
 	struct ipu_isys_tpg *tpg;
+#endif
 	struct ipu_isys_csi2_be csi2_be;
 	struct ipu_isys_csi2_be_soc csi2_be_soc[NR_OF_CSI2_BE_SOC_DEV];
 	const struct firmware *fw;
diff --git a/drivers/media/pci/intel/ipu-pdata.h b/drivers/media/pci/intel/ipu-pdata.h
index 575899746323..3dd7205994b4 100644
--- a/drivers/media/pci/intel/ipu-pdata.h
+++ b/drivers/media/pci/intel/ipu-pdata.h
@@ -207,11 +207,13 @@ struct ipu_isys_internal_csi2_pdata {
 	unsigned int *offsets;
 };
 
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
 struct ipu_isys_internal_tpg_pdata {
 	unsigned int ntpgs;
 	unsigned int *offsets;
 	unsigned int *sels;
 };
+#endif
 
 /*
  * One place to handle all the IPU HW variations
@@ -228,7 +230,9 @@ struct ipu_hw_variants {
 
 struct ipu_isys_internal_pdata {
 	struct ipu_isys_internal_csi2_pdata csi2;
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
 	struct ipu_isys_internal_tpg_pdata tpg;
+#endif
 	struct ipu_hw_variants hw_variant;
 	u32 num_parallel_streams;
 	u32 isys_dma_overshoot;
diff --git a/drivers/media/pci/intel/ipu-psys.c b/drivers/media/pci/intel/ipu-psys.c
index c8370659d61a..904884f244b3 100644
--- a/drivers/media/pci/intel/ipu-psys.c
+++ b/drivers/media/pci/intel/ipu-psys.c
@@ -105,8 +105,8 @@ struct ipu_psys_pg *__get_pg_buf(struct ipu_psys *psys, size_t pg_size)
 	return kpg;
 }
 
-static int ipu_psys_unmapbuf_with_lock(int fd, struct ipu_psys_fh *fh,
-				       struct ipu_psys_kbuffer *kbuf);
+static int ipu_psys_unmapbuf_locked(int fd, struct ipu_psys_fh *fh,
+				    struct ipu_psys_kbuffer *kbuf);
 struct ipu_psys_kbuffer *ipu_psys_lookup_kbuffer(struct ipu_psys_fh *fh, int fd)
 {
 	struct ipu_psys_kbuffer *kbuf;
@@ -436,6 +436,27 @@ static int ipu_psys_open(struct inode *inode, struct file *file)
 	return rval;
 }
 
+static inline void ipu_psys_kbuf_unmap(struct ipu_psys_kbuffer *kbuf)
+{
+	if (!kbuf)
+		return;
+
+	kbuf->valid = false;
+	if (kbuf->kaddr)
+		dma_buf_vunmap(kbuf->dbuf, kbuf->kaddr);
+	if (kbuf->sgt)
+		dma_buf_unmap_attachment(kbuf->db_attach,
+					 kbuf->sgt,
+					 DMA_BIDIRECTIONAL);
+	if (kbuf->db_attach)
+		dma_buf_detach(kbuf->dbuf, kbuf->db_attach);
+	dma_buf_put(kbuf->dbuf);
+
+	kbuf->db_attach = NULL;
+	kbuf->dbuf = NULL;
+	kbuf->sgt = NULL;
+}
+
 static int ipu_psys_release(struct inode *inode, struct file *file)
 {
 	struct ipu_psys *psys = inode_to_ipu_psys(inode);
@@ -452,19 +473,8 @@ static int ipu_psys_release(struct inode *inode, struct file *file)
 
 			/* Unmap and release buffers */
 			if (kbuf->dbuf && db_attach) {
-				struct dma_buf *dbuf;
-
-				kbuf->valid = false;
-				dma_buf_vunmap(kbuf->dbuf, kbuf->kaddr);
-				dma_buf_unmap_attachment(db_attach,
-							 kbuf->sgt,
-							 DMA_BIDIRECTIONAL);
-				dma_buf_detach(kbuf->dbuf, db_attach);
-				dbuf = kbuf->dbuf;
-				kbuf->dbuf = NULL;
-				db_attach = NULL;
-				kbuf->db_attach = NULL;
-				dma_buf_put(dbuf);
+
+				ipu_psys_kbuf_unmap(kbuf);
 			} else {
 				if (db_attach)
 					ipu_psys_put_userpages(db_attach->priv);
@@ -536,10 +546,10 @@ static int ipu_psys_getbuf(struct ipu_psys_buffer *buf, struct ipu_psys_fh *fh)
 	kbuf->flags = buf->flags |= IPU_BUFFER_FLAG_DMA_HANDLE;
 
 	mutex_lock(&fh->mutex);
-	list_add_tail(&kbuf->list, &fh->bufmap);
+	list_add(&kbuf->list, &fh->bufmap);
 	mutex_unlock(&fh->mutex);
 
-	dev_dbg(&psys->adev->dev, "IOC_GETBUF: userptr %p size %lu to fd %d",
+	dev_dbg(&psys->adev->dev, "IOC_GETBUF: userptr %p size %llu to fd %d",
 		buf->base.userptr, buf->len, buf->base.fd);
 
 	return 0;
@@ -550,8 +560,8 @@ static int ipu_psys_putbuf(struct ipu_psys_buffer *buf, struct ipu_psys_fh *fh)
 	return 0;
 }
 
-int ipu_psys_mapbuf_with_lock(int fd, struct ipu_psys_fh *fh,
-			      struct ipu_psys_kbuffer *kbuf)
+int ipu_psys_mapbuf_locked(int fd, struct ipu_psys_fh *fh,
+			   struct ipu_psys_kbuffer *kbuf)
 {
 	struct ipu_psys *psys = fh->psys;
 	struct dma_buf *dbuf;
@@ -567,10 +577,12 @@ int ipu_psys_mapbuf_with_lock(int fd, struct ipu_psys_fh *fh,
 		 * add this kbuf to bufmap list.
 		 */
 		kbuf = kzalloc(sizeof(*kbuf), GFP_KERNEL);
-		if (!kbuf)
-			return -ENOMEM;
+		if (!kbuf) {
+			ret = -ENOMEM;
+			goto mapbuf_fail;
+		}
 
-		list_add_tail(&kbuf->list, &fh->bufmap);
+		list_add(&kbuf->list, &fh->bufmap);
 	}
 
 	/* fd valid and found, need remap */
@@ -578,17 +590,19 @@ int ipu_psys_mapbuf_with_lock(int fd, struct ipu_psys_fh *fh,
 		dev_dbg(&psys->adev->dev,
 			"dmabuf fd %d with kbuf %p changed, need remap.\n",
 			fd, kbuf);
-		ret = ipu_psys_unmapbuf_with_lock(fd, fh, kbuf);
+		ret = ipu_psys_unmapbuf_locked(fd, fh, kbuf);
 		if (ret)
-			return ret;
+			goto mapbuf_fail;
 
 		kbuf = ipu_psys_lookup_kbuffer(fh, fd);
 		/* changed external dmabuf */
 		if (!kbuf) {
 			kbuf = kzalloc(sizeof(*kbuf), GFP_KERNEL);
-			if (!kbuf)
-				return -ENOMEM;
-			list_add_tail(&kbuf->list, &fh->bufmap);
+			if (!kbuf) {
+				ret = -ENOMEM;
+				goto mapbuf_fail;
+			}
+			list_add(&kbuf->list, &fh->bufmap);
 		}
 	}
 
@@ -608,15 +622,16 @@ int ipu_psys_mapbuf_with_lock(int fd, struct ipu_psys_fh *fh,
 	kbuf->db_attach = dma_buf_attach(kbuf->dbuf, &psys->adev->dev);
 	if (IS_ERR(kbuf->db_attach)) {
 		ret = PTR_ERR(kbuf->db_attach);
-		goto error_put;
+		dev_dbg(&psys->adev->dev, "dma buf attach failed\n");
+		goto kbuf_map_fail;
 	}
 
 	kbuf->sgt = dma_buf_map_attachment(kbuf->db_attach, DMA_BIDIRECTIONAL);
 	if (IS_ERR_OR_NULL(kbuf->sgt)) {
 		ret = -EINVAL;
 		kbuf->sgt = NULL;
-		dev_dbg(&psys->adev->dev, "map attachment failed\n");
-		goto error_detach;
+		dev_dbg(&psys->adev->dev, "dma buf map attachment failed\n");
+		goto kbuf_map_fail;
 	}
 
 	kbuf->dma_addr = sg_dma_address(kbuf->sgt->sgl);
@@ -624,10 +639,11 @@ int ipu_psys_mapbuf_with_lock(int fd, struct ipu_psys_fh *fh,
 	kbuf->kaddr = dma_buf_vmap(kbuf->dbuf);
 	if (!kbuf->kaddr) {
 		ret = -EINVAL;
-		goto error_unmap;
+		dev_dbg(&psys->adev->dev, "dma buf vmap failed\n");
+		goto kbuf_map_fail;
 	}
 
-	dev_dbg(&psys->adev->dev, "%s kbuf %p fd %d with len %lu mapped\n",
+	dev_dbg(&psys->adev->dev, "%s kbuf %p fd %d with len %llu mapped\n",
 		__func__, kbuf, fd, kbuf->len);
 mapbuf_end:
 
@@ -635,20 +651,18 @@ int ipu_psys_mapbuf_with_lock(int fd, struct ipu_psys_fh *fh,
 
 	return 0;
 
-error_unmap:
-	dma_buf_unmap_attachment(kbuf->db_attach, kbuf->sgt, DMA_BIDIRECTIONAL);
-error_detach:
-	dma_buf_detach(kbuf->dbuf, kbuf->db_attach);
-	kbuf->db_attach = NULL;
-error_put:
-	list_del(&kbuf->list);
+kbuf_map_fail:
+	ipu_psys_kbuf_unmap(kbuf);
 
+	list_del(&kbuf->list);
 	if (!kbuf->userptr)
 		kfree(kbuf);
+	return ret;
 
+mapbuf_fail:
 	dma_buf_put(dbuf);
 
-	dev_err(&psys->adev->dev, "%s failed\n", __func__);
+	dev_err(&psys->adev->dev, "%s failed for fd %d\n", __func__, fd);
 	return ret;
 }
 
@@ -659,7 +673,7 @@ static long ipu_psys_mapbuf(int fd, struct ipu_psys_fh *fh)
 
 	mutex_lock(&fh->mutex);
 	kbuf = ipu_psys_lookup_kbuffer(fh, fd);
-	ret = ipu_psys_mapbuf_with_lock(fd, fh, kbuf);
+	ret = ipu_psys_mapbuf_locked(fd, fh, kbuf);
 	mutex_unlock(&fh->mutex);
 
 	dev_dbg(&fh->psys->adev->dev, "IOC_MAPBUF ret %ld\n", ret);
@@ -667,11 +681,10 @@ static long ipu_psys_mapbuf(int fd, struct ipu_psys_fh *fh)
 	return ret;
 }
 
-static int ipu_psys_unmapbuf_with_lock(int fd, struct ipu_psys_fh *fh,
-				       struct ipu_psys_kbuffer *kbuf)
+static int ipu_psys_unmapbuf_locked(int fd, struct ipu_psys_fh *fh,
+				    struct ipu_psys_kbuffer *kbuf)
 {
 	struct ipu_psys *psys = fh->psys;
-	struct dma_buf *dmabuf;
 
 	if (!kbuf || fd != kbuf->fd) {
 		dev_err(&psys->adev->dev, "invalid kbuffer\n");
@@ -679,26 +692,13 @@ static int ipu_psys_unmapbuf_with_lock(int fd, struct ipu_psys_fh *fh,
 	}
 
 	/* From now on it is not safe to use this kbuffer */
-	kbuf->valid = false;
-
-	dma_buf_vunmap(kbuf->dbuf, kbuf->kaddr);
-	dma_buf_unmap_attachment(kbuf->db_attach, kbuf->sgt, DMA_BIDIRECTIONAL);
-
-	dma_buf_detach(kbuf->dbuf, kbuf->db_attach);
-
-	dmabuf = kbuf->dbuf;
-
-	kbuf->db_attach = NULL;
-	kbuf->dbuf = NULL;
-	kbuf->sgt = NULL;
+	ipu_psys_kbuf_unmap(kbuf);
 
 	list_del(&kbuf->list);
 
 	if (!kbuf->userptr)
 		kfree(kbuf);
 
-	dma_buf_put(dmabuf);
-
 	dev_dbg(&psys->adev->dev, "%s fd %d unmapped\n", __func__, fd);
 
 	return 0;
@@ -717,7 +717,7 @@ static long ipu_psys_unmapbuf(int fd, struct ipu_psys_fh *fh)
 		mutex_unlock(&fh->mutex);
 		return -EINVAL;
 	}
-	ret = ipu_psys_unmapbuf_with_lock(fd, fh, kbuf);
+	ret = ipu_psys_unmapbuf_locked(fd, fh, kbuf);
 	mutex_unlock(&fh->mutex);
 
 	dev_dbg(&fh->psys->adev->dev, "IOC_UNMAPBUF\n");
@@ -1500,15 +1500,6 @@ static void ipu_psys_remove(struct ipu_bus_device *adev)
 	if (psys->fwcom && ipu_fw_com_release(psys->fwcom, 1))
 		dev_err(&adev->dev, "fw com release failed.\n");
 
-	isp->pkg_dir = NULL;
-	isp->pkg_dir_dma_addr = 0;
-	isp->pkg_dir_size = 0;
-
-	ipu_cpd_free_pkg_dir(adev, psys->pkg_dir,
-			     psys->pkg_dir_dma_addr, psys->pkg_dir_size);
-
-	ipu_buttress_unmap_fw_image(adev, &psys->fw_sgt);
-
 	kfree(psys->server_init);
 	kfree(psys->syscom_config);
 
@@ -1538,13 +1529,8 @@ static irqreturn_t psys_isr_threaded(struct ipu_bus_device *adev)
 
 	mutex_lock(&psys->mutex);
 #ifdef CONFIG_PM
-	if (!READ_ONCE(psys->power)) {
-		mutex_unlock(&psys->mutex);
-		return IRQ_NONE;
-	}
-	r = pm_runtime_get_sync(&psys->adev->dev);
-	if (r < 0) {
-		pm_runtime_put(&psys->adev->dev);
+	r = pm_runtime_get_if_in_use(&psys->adev->dev);
+	if (!r || WARN_ON_ONCE(r < 0)) {
 		mutex_unlock(&psys->mutex);
 		return IRQ_NONE;
 	}
diff --git a/drivers/media/pci/intel/ipu-psys.h b/drivers/media/pci/intel/ipu-psys.h
index b227c2bc7415..61ff388f8458 100644
--- a/drivers/media/pci/intel/ipu-psys.h
+++ b/drivers/media/pci/intel/ipu-psys.h
@@ -202,8 +202,8 @@ 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);
-int ipu_psys_mapbuf_with_lock(int fd, struct ipu_psys_fh *fh,
-			      struct ipu_psys_kbuffer *kbuf);
+int ipu_psys_mapbuf_locked(int fd, struct ipu_psys_fh *fh,
+			   struct ipu_psys_kbuffer *kbuf);
 struct ipu_psys_kbuffer *
 ipu_psys_lookup_kbuffer_by_kaddr(struct ipu_psys_fh *fh, void *kaddr);
 #ifdef IPU_PSYS_GPC
diff --git a/drivers/media/pci/intel/ipu.c b/drivers/media/pci/intel/ipu.c
index 18b1ba01ebd6..84f301c72571 100644
--- a/drivers/media/pci/intel/ipu.c
+++ b/drivers/media/pci/intel/ipu.c
@@ -598,6 +598,15 @@ static void ipu_pci_remove(struct pci_dev *pdev)
 #endif
 	ipu_trace_release(isp);
 
+	ipu_cpd_free_pkg_dir(isp->psys, isp->pkg_dir, isp->pkg_dir_dma_addr,
+			     isp->pkg_dir_size);
+
+	ipu_buttress_unmap_fw_image(isp->psys, &isp->fw_sgt);
+
+	isp->pkg_dir = NULL;
+	isp->pkg_dir_dma_addr = 0;
+	isp->pkg_dir_size = 0;
+
 	ipu_bus_del_devices(pdev);
 
 	pm_runtime_forbid(&pdev->dev);
diff --git a/drivers/media/pci/intel/ipu6/Makefile b/drivers/media/pci/intel/ipu6/Makefile
index 0c45215ad991..d845028191e8 100644
--- a/drivers/media/pci/intel/ipu6/Makefile
+++ b/drivers/media/pci/intel/ipu6/Makefile
@@ -31,8 +31,11 @@ intel-ipu6-isys-objs			+= ../ipu-isys.o \
 					   ../ipu-fw-isys.o \
 					   ../ipu-isys-video.o \
 					   ../ipu-isys-queue.o \
-					   ../ipu-isys-subdev.o \
-					   ../ipu-isys-tpg.o
+					   ../ipu-isys-subdev.o
+
+ifdef CONFIG_VIDEO_INTEL_IPU_TPG
+intel-ipu6-isys-objs                    += ../ipu-isys-tpg.o
+endif
 
 obj-$(CONFIG_VIDEO_INTEL_IPU)		+= intel-ipu6-isys.o
 
diff --git a/drivers/media/pci/intel/ipu6/ipu-platform-psys.h b/drivers/media/pci/intel/ipu6/ipu-platform-psys.h
index e8483e9a325b..5573e617d2b9 100644
--- a/drivers/media/pci/intel/ipu6/ipu-platform-psys.h
+++ b/drivers/media/pci/intel/ipu6/ipu-platform-psys.h
@@ -69,7 +69,7 @@ struct ipu_psys_buffer_set {
 };
 
 int ipu_psys_kcmd_start(struct ipu_psys *psys, struct ipu_psys_kcmd *kcmd);
-void ipu_psys_kcmd_complete(struct ipu_psys *psys, struct ipu_psys_kcmd *kcmd,
+void ipu_psys_kcmd_complete(struct ipu_psys_ppg *kppg, struct ipu_psys_kcmd *kcmd,
 			    int error);
 int ipu_psys_fh_init(struct ipu_psys_fh *fh);
 int ipu_psys_fh_deinit(struct ipu_psys_fh *fh);
diff --git a/drivers/media/pci/intel/ipu6/ipu-platform-resources.h b/drivers/media/pci/intel/ipu6/ipu-platform-resources.h
index 642c5c6ca6c1..f59d5fa86b01 100644
--- a/drivers/media/pci/intel/ipu6/ipu-platform-resources.h
+++ b/drivers/media/pci/intel/ipu6/ipu-platform-resources.h
@@ -81,6 +81,10 @@ int ipu_psys_try_allocate_resources(struct device *dev,
 				    void *pg_manifest,
 				    struct ipu_psys_resource_pool *pool);
 
+void ipu_psys_reset_process_cell(const struct device *dev,
+				 struct ipu_fw_psys_process_group *pg,
+				 void *pg_manifest,
+				 int process_count);
 void ipu_psys_free_resources(struct ipu_psys_resource_alloc *alloc,
 			     struct ipu_psys_resource_pool *pool);
 
diff --git a/drivers/media/pci/intel/ipu6/ipu-resources.c b/drivers/media/pci/intel/ipu6/ipu-resources.c
index e5932287b7f3..418dd55c1e3a 100644
--- a/drivers/media/pci/intel/ipu6/ipu-resources.c
+++ b/drivers/media/pci/intel/ipu6/ipu-resources.c
@@ -19,7 +19,6 @@ void ipu6_psys_hw_res_variant_init(void)
 		hw_var.queue_num = IPU6SE_FW_PSYS_N_PSYS_CMD_QUEUE_ID;
 		hw_var.cell_num = IPU6SE_FW_PSYS_N_CELL_ID;
 		hw_var.set_proc_dev_chn = ipu6se_fw_psys_set_proc_dev_chn;
-		hw_var.set_proc_dev_chn = ipu6se_fw_psys_set_proc_dev_chn;
 		hw_var.set_proc_dfm_bitmap = ipu6se_fw_psys_set_proc_dfm_bitmap;
 		hw_var.set_proc_ext_mem = ipu6se_fw_psys_set_process_ext_mem;
 		hw_var.get_pgm_by_proc =
@@ -29,7 +28,6 @@ void ipu6_psys_hw_res_variant_init(void)
 		hw_var.queue_num = IPU6_FW_PSYS_N_PSYS_CMD_QUEUE_ID;
 		hw_var.cell_num = IPU6_FW_PSYS_N_CELL_ID;
 		hw_var.set_proc_dev_chn = ipu6_fw_psys_set_proc_dev_chn;
-		hw_var.set_proc_dev_chn = ipu6_fw_psys_set_proc_dev_chn;
 		hw_var.set_proc_dfm_bitmap = ipu6_fw_psys_set_proc_dfm_bitmap;
 		hw_var.set_proc_ext_mem = ipu6_fw_psys_set_process_ext_mem;
 		hw_var.get_pgm_by_proc =
@@ -142,7 +140,7 @@ 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)
 {
@@ -173,12 +171,14 @@ int ipu_psys_resource_pool_init(struct ipu_psys_resource_pool
 			goto dfm_error;
 	}
 
+	spin_lock(&cq_bitmap_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);
 
 	return 0;
 
@@ -399,13 +399,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);
 	/* find available cmd queue from ppg0_cmd_id */
 	p = bitmap_find_next_zero_area(pool->cmd_queues, size, start, 1, 0);
 
-	if (p >= size)
+	if (p >= size) {
+		spin_unlock(&cq_bitmap_lock);
 		return -ENOSPC;
+	}
 
 	bitmap_set(pool->cmd_queues, p, 1);
+	spin_unlock(&cq_bitmap_lock);
 
 	return p;
 }
@@ -413,7 +417,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);
 	bitmap_clear(pool->cmd_queues, queue_id, 1);
+	spin_unlock(&cq_bitmap_lock);
 }
 
 int ipu_psys_try_allocate_resources(struct device *dev,
@@ -706,32 +712,8 @@ int ipu_psys_allocate_resources(const struct device *dev,
 	return 0;
 
 free_out:
-	for (; i >= 0; i--) {
-		struct ipu_fw_psys_process *process =
-		    (struct ipu_fw_psys_process *)
-		    ((char *)pg + process_offset_table[i]);
-		struct ipu_fw_generic_program_manifest pm;
-		int retval;
-
-		if (!process)
-			break;
-
-		retval = ipu_fw_psys_get_program_manifest_by_process
-		    (&pm, pg_manifest, process);
-		if (retval < 0) {
-			dev_err(dev, "can not get manifest\n");
-			break;
-		}
-		if ((pm.cell_id != res_defs->num_cells &&
-		     pm.cell_type_id == res_defs->num_cells_type))
-			continue;
-		/* no return value check here because if finding free cell
-		 * failed, process cell would not set then calling clear_cell
-		 * will return non-zero.
-		 */
-		ipu_fw_psys_clear_process_cell(process);
-	}
 	dev_err(dev, "failed to allocate resources, ret %d\n", ret);
+	ipu_psys_reset_process_cell(dev, pg, pg_manifest, i + 1);
 	ipu_psys_free_resources(alloc, pool);
 	return ret;
 }
@@ -825,6 +807,48 @@ int ipu_psys_move_resources(const struct device *dev,
 	return 0;
 }
 
+void ipu_psys_reset_process_cell(const struct device *dev,
+				 struct ipu_fw_psys_process_group *pg,
+				 void *pg_manifest,
+				 int process_count)
+{
+	int i;
+	u16 *process_offset_table;
+	const struct ipu_fw_resource_definitions *res_defs;
+
+	if (!pg)
+		return;
+
+	res_defs = get_res();
+	process_offset_table = (u16 *)((u8 *)pg + pg->processes_offset);
+	for (i = 0; i < process_count; i++) {
+		struct ipu_fw_psys_process *process =
+		    (struct ipu_fw_psys_process *)
+		    ((char *)pg + process_offset_table[i]);
+		struct ipu_fw_generic_program_manifest pm;
+		int ret;
+
+		if (!process)
+			break;
+
+		ret = ipu_fw_psys_get_program_manifest_by_process(&pm,
+								  pg_manifest,
+								  process);
+		if (ret < 0) {
+			dev_err(dev, "can not get manifest\n");
+			break;
+		}
+		if ((pm.cell_id != res_defs->num_cells &&
+		     pm.cell_type_id == res_defs->num_cells_type))
+			continue;
+		/* no return value check here because if finding free cell
+		 * failed, process cell would not set then calling clear_cell
+		 * will return non-zero.
+		 */
+		ipu_fw_psys_clear_process_cell(process);
+	}
+}
+
 /* Free resources marked in `alloc' from `resources' */
 void ipu_psys_free_resources(struct ipu_psys_resource_alloc
 			     *alloc, struct ipu_psys_resource_pool *pool)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-fw-resources.c b/drivers/media/pci/intel/ipu6/ipu6-fw-resources.c
index 4ac195f2f95d..6c2885a3d564 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-fw-resources.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-fw-resources.c
@@ -444,30 +444,6 @@ int ipu6_fw_psys_set_process_cell_id(struct ipu_fw_psys_process *ptr, u8 index,
 	return 0;
 }
 
-u8 ipu6_fw_psys_get_process_cell_id(struct ipu_fw_psys_process *ptr, u8 index)
-{
-	return ptr->cells[index];
-}
-
-int ipu6_fw_psys_clear_process_cell(struct ipu_fw_psys_process *ptr)
-{
-	struct ipu_fw_psys_process_group *parent;
-	u8 cell_id = ipu6_fw_psys_get_process_cell_id(ptr, 0);
-	int retval = -1;
-
-	parent = (struct ipu_fw_psys_process_group *)((char *)ptr +
-						       ptr->parent_offset);
-	if ((1 << cell_id) != 0 &&
-	    ((1 << cell_id) & parent->resource_bitmap)) {
-		ipu6_fw_psys_set_process_cell_id(ptr, 0,
-						 IPU6_FW_PSYS_N_CELL_ID);
-		parent->resource_bitmap &= ~(1 << cell_id);
-		retval = 0;
-	}
-
-	return retval;
-}
-
 int ipu6_fw_psys_set_proc_dev_chn(struct ipu_fw_psys_process *ptr, u16 offset,
 				  u16 value)
 {
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c b/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c
index 1f917721b70e..afd84e5ca814 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c
@@ -92,24 +92,18 @@ static int ipu6_csi2_phy_power_set(struct ipu_isys *isys,
 		if (ret)
 			return ret;
 
-		dev_dbg(&isys->adev->dev, "phy reset assert\n");
 		ipu6_isys_phy_reset(isys, phy_id, 0);
-		dev_dbg(&isys->adev->dev, "phy common init\n");
 		ipu6_isys_phy_common_init(isys);
 
-		dev_dbg(&isys->adev->dev, "phy config\n");
 		ret = ipu6_isys_phy_config(isys);
 		if (ret)
 			return ret;
 
-		dev_dbg(&isys->adev->dev, "phy reset de-assert\n");
 		ipu6_isys_phy_reset(isys, phy_id, 1);
-		dev_dbg(&isys->adev->dev, "phy check ready\n");
 		ret = ipu6_isys_phy_ready(isys, phy_id);
 		if (ret)
 			return ret;
 
-		dev_dbg(&isys->adev->dev, "phy is ready now\n");
 		refcount_set(ref, 1);
 		return 0;
 	}
@@ -404,10 +398,8 @@ int ipu_isys_csi2_set_stream(struct v4l2_subdev *sd,
 	}
 
 	/* reset port reset */
-	dev_dbg(&isys->adev->dev, "csi port reset assert\n");
 	writel(0x1, csi2->base + CSI_REG_PORT_GPREG_SRST);
 	usleep_range(100, 200);
-	dev_dbg(&isys->adev->dev, "csi port reset de-assert\n");
 	writel(0x0, csi2->base + CSI_REG_PORT_GPREG_SRST);
 
 	/* Enable port clock */
@@ -472,11 +464,6 @@ int ipu_isys_csi2_set_stream(struct v4l2_subdev *sd,
 	writel(1, csi2->base + CSI_REG_PPI2CSI_ENABLE);
 	writel(1, csi2->base + CSI_REG_CSI_FE_ENABLE);
 
-	if (ipu_ver == IPU_VER_6SE)
-		return 0;
-
-	ipu6_isys_phy_ppi_tinit_done(isys, cfg);
-
 	return 0;
 }
 
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-phy.c b/drivers/media/pci/intel/ipu6/ipu6-isys-phy.c
index 6f4561ebb89f..82d457fc8d64 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-phy.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-phy.c
@@ -497,42 +497,6 @@ int ipu6_isys_phy_ready(struct ipu_isys *isys, unsigned int phy_id)
 	return -ETIMEDOUT;
 }
 
-int ipu6_isys_phy_ppi_tinit_done(struct ipu_isys *isys,
-				 struct ipu_isys_csi2_config *cfg)
-{
-	unsigned int i, j;
-	unsigned int port, phy_id;
-	u32 val;
-	void __iomem *phy_base;
-	struct ipu_bus_device *adev = to_ipu_bus_device(&isys->adev->dev);
-	struct ipu_device *isp = adev->isp;
-	void __iomem *isp_base = isp->base;
-
-	port = cfg->port;
-	phy_id = port / 4;
-	phy_base = isp_base + IPU6_ISYS_PHY_BASE(phy_id);
-	for (i = 0; i < 11; i++) {
-		/* ignore 5 as it is not needed */
-		if (i == 5)
-			continue;
-		for (j = 0; j < LOOP; j++) {
-			val = readl(phy_base + IPU6_ISYS_PHY_DBBS_UDLN(i) +
-				    PHY_DBBUDLN_PPI_STATUS);
-			if (val & PHY_DBBUDLN_TINIT_DONE) {
-				j = 0xffff;
-				continue;
-			}
-			usleep_range(10, 20);
-		}
-		if (j == LOOP)
-			dev_dbg(&isys->adev->dev,
-				"phy %d ppi %d tinit NOT done!",
-				phy_id, i);
-	}
-
-	return -ETIMEDOUT;
-}
-
 int ipu6_isys_phy_common_init(struct ipu_isys *isys)
 {
 	unsigned int phy_id;
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-phy.h b/drivers/media/pci/intel/ipu6/ipu6-isys-phy.h
index e8c063fcf452..10a1d88c3088 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-phy.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-phy.h
@@ -155,7 +155,5 @@ int ipu6_isys_phy_reset(struct ipu_isys *isys, unsigned int phy_id,
 			bool assert);
 int ipu6_isys_phy_ready(struct ipu_isys *isys, unsigned int phy_id);
 int ipu6_isys_phy_common_init(struct ipu_isys *isys);
-int ipu6_isys_phy_ppi_tinit_done(struct ipu_isys *isys,
-				 struct ipu_isys_csi2_config *cfg);
 int ipu6_isys_phy_config(struct ipu_isys *isys);
 #endif
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c
index e2891606a63d..28c45f433e2f 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c
@@ -8,7 +8,9 @@
 #include "ipu-platform-regs.h"
 #include "ipu-trace.h"
 #include "ipu-isys.h"
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
 #include "ipu-isys-tpg.h"
+#endif
 #include "ipu-platform-isys-csi2-reg.h"
 
 const struct ipu_isys_pixelformat ipu_isys_pfmts[] = {
@@ -173,6 +175,7 @@ irqreturn_t isys_isr(struct ipu_bus_device *adev)
 	return IRQ_HANDLED;
 }
 
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
 void ipu_isys_tpg_sof_event(struct ipu_isys_tpg *tpg)
 {
 	struct ipu_isys_pipeline *ip = NULL;
@@ -316,3 +319,4 @@ int tpg_set_stream(struct v4l2_subdev *sd, int enable)
 	writel(2, tpg->base + MIPI_GEN_REG_COM_ENABLE);
 	return 0;
 }
+#endif
diff --git a/drivers/media/pci/intel/ipu6/ipu6-l-scheduler.c b/drivers/media/pci/intel/ipu6/ipu6-l-scheduler.c
index 2c9cdc1c376b..eed5022b88d3 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-l-scheduler.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-l-scheduler.c
@@ -371,17 +371,13 @@ static void ipu_psys_update_ppg_state_by_kcmd(struct ipu_psys *psys,
 	    kppg->state == PPG_STATE_RESUMED ||
 	    kppg->state == PPG_STATE_RUNNING) {
 		if (kcmd->state == KCMD_STATE_PPG_START) {
-			dev_dbg(&psys->adev->dev, "ppg %p started!\n", kppg);
-			list_move_tail(&kcmd->list, &kppg->kcmds_finished_list);
-			ipu_psys_kcmd_complete(psys, kcmd, 0);
+			ipu_psys_kcmd_complete(kppg, kcmd, 0);
 		} else if (kcmd->state == KCMD_STATE_PPG_STOP) {
 			kppg->state = PPG_STATE_STOP;
 		}
 	} else if (kppg->state == PPG_STATE_SUSPENDED) {
 		if (kcmd->state == KCMD_STATE_PPG_START) {
-			dev_dbg(&psys->adev->dev, "ppg %p started!\n", kppg);
-			list_move_tail(&kcmd->list, &kppg->kcmds_finished_list);
-			ipu_psys_kcmd_complete(psys, kcmd, 0);
+			ipu_psys_kcmd_complete(kppg, kcmd, 0);
 		} else if (kcmd->state == KCMD_STATE_PPG_STOP) {
 			/*
 			 * Record the previous state
@@ -395,13 +391,10 @@ static void ipu_psys_update_ppg_state_by_kcmd(struct ipu_psys *psys,
 		if (kcmd->state == KCMD_STATE_PPG_START) {
 			kppg->state = PPG_STATE_START;
 		} else if (kcmd->state == KCMD_STATE_PPG_STOP) {
-			dev_dbg(&psys->adev->dev, "ppg %p stopped!\n", kppg);
-			list_move_tail(&kcmd->list, &kppg->kcmds_finished_list);
-			ipu_psys_kcmd_complete(psys, kcmd, 0);
+			ipu_psys_kcmd_complete(kppg, kcmd, 0);
 		} else if (kcmd->state == KCMD_STATE_PPG_ENQUEUE) {
 			dev_err(&psys->adev->dev, "ppg %p stopped!\n", kppg);
-			list_move_tail(&kcmd->list, &kppg->kcmds_finished_list);
-			ipu_psys_kcmd_complete(psys, kcmd, -EIO);
+			ipu_psys_kcmd_complete(kppg, kcmd, -EIO);
 		}
 	}
 
diff --git a/drivers/media/pci/intel/ipu6/ipu6-ppg.c b/drivers/media/pci/intel/ipu6/ipu6-ppg.c
index 4b8db1826eed..22b602306b4a 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-ppg.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-ppg.c
@@ -32,6 +32,8 @@ struct ipu_psys_kcmd *ipu_psys_ppg_get_stop_kcmd(struct ipu_psys_ppg *kppg)
 {
 	struct ipu_psys_kcmd *kcmd;
 
+	WARN(!mutex_is_locked(&kppg->mutex), "ppg locking error");
+
 	if (list_empty(&kppg->kcmds_processing_list))
 		return NULL;
 
@@ -235,14 +237,14 @@ int ipu_psys_ppg_start(struct ipu_psys_ppg *kppg)
 					       kcmd->buffers[i].len);
 		if (ret) {
 			dev_err(&psys->adev->dev, "Unable to set terminal\n");
-			goto error;
+			return ret;
 		}
 	}
 
 	ret = ipu_fw_psys_pg_submit(kcmd);
 	if (ret) {
 		dev_err(&psys->adev->dev, "failed to submit kcmd!\n");
-		goto error;
+		return ret;
 	}
 
 	ret = ipu_psys_allocate_resources(&psys->adev->dev,
@@ -258,26 +260,31 @@ int ipu_psys_ppg_start(struct ipu_psys_ppg *kppg)
 	ret = pm_runtime_get_sync(&psys->adev->dev);
 	if (ret < 0) {
 		dev_err(&psys->adev->dev, "failed to power on psys\n");
-		pm_runtime_put_noidle(&psys->adev->dev);
-		return ret;
+		goto error;
 	}
 
 	ret = ipu_psys_kcmd_start(psys, kcmd);
 	if (ret) {
-		list_move_tail(&kcmd->list, &kppg->kcmds_finished_list);
-		ipu_psys_kcmd_complete(psys, kcmd, -EIO);
-		return ret;
+		ipu_psys_kcmd_complete(kppg, kcmd, -EIO);
+		goto error;
 	}
 
 	dev_dbg(&psys->adev->dev, "s_change:%s: %p %d -> %d\n",
 		__func__, kppg, kppg->state, PPG_STATE_STARTED);
 	kppg->state = PPG_STATE_STARTED;
-	list_move_tail(&kcmd->list, &kppg->kcmds_finished_list);
-	ipu_psys_kcmd_complete(psys, kcmd, 0);
+	ipu_psys_kcmd_complete(kppg, kcmd, 0);
 
 	return 0;
 
 error:
+	pm_runtime_put_noidle(&psys->adev->dev);
+	ipu_psys_reset_process_cell(&psys->adev->dev,
+				    kcmd->kpg->pg,
+				    kcmd->pg_manifest,
+				    kcmd->kpg->pg->process_count);
+	ipu_psys_free_resources(&kppg->kpg->resource_alloc,
+				&psys->resource_pool_running);
+
 	dev_err(&psys->adev->dev, "failed to start ppg\n");
 	return ret;
 }
@@ -309,7 +316,7 @@ int ipu_psys_ppg_resume(struct ipu_psys_ppg *kppg)
 		ret = ipu_fw_psys_ppg_resume(&tmp_kcmd);
 		if (ret) {
 			dev_err(&psys->adev->dev, "failed to resume ppg\n");
-			return -EIO;
+			goto error;
 		}
 	} else {
 		kppg->kpg->pg->state = IPU_FW_PSYS_PROCESS_GROUP_READY;
@@ -332,13 +339,23 @@ int ipu_psys_ppg_resume(struct ipu_psys_ppg *kppg)
 		ret = ipu_psys_kcmd_start(psys, &tmp_kcmd);
 		if (ret) {
 			dev_err(&psys->adev->dev, "failed to start kcmd!\n");
-			return ret;
+			goto error;
 		}
 	}
 	dev_dbg(&psys->adev->dev, "s_change:%s: %p %d -> %d\n",
 		__func__, kppg, kppg->state, PPG_STATE_RESUMED);
 	kppg->state = PPG_STATE_RESUMED;
 
+	return 0;
+
+error:
+	ipu_psys_reset_process_cell(&psys->adev->dev,
+				    kppg->kpg->pg,
+				    kppg->manifest,
+				    kppg->kpg->pg->process_count);
+	ipu_psys_free_resources(&kppg->kpg->resource_alloc,
+				&psys->resource_pool_running);
+
 	return ret;
 }
 
@@ -379,8 +396,7 @@ int ipu_psys_ppg_stop(struct ipu_psys_ppg *kppg)
 			ipu_psys_free_cmd_queue_resource(
 				&psys->resource_pool_running,
 				ipu_fw_psys_ppg_get_base_queue_id(kcmd));
-			list_move_tail(&kcmd->list, &kppg->kcmds_finished_list);
-			ipu_psys_kcmd_complete(psys, kcmd, 0);
+			ipu_psys_kcmd_complete(kppg, kcmd, 0);
 			spin_lock_irqsave(&psys->pgs_lock, flags);
 			kppg->kpg->pg_size = 0;
 			spin_unlock_irqrestore(&psys->pgs_lock, flags);
diff --git a/drivers/media/pci/intel/ipu6/ipu6-psys.c b/drivers/media/pci/intel/ipu6/ipu6-psys.c
index baf208ac1a3f..10c6366c60c9 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-psys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-psys.c
@@ -251,7 +251,7 @@ static struct ipu_psys_kcmd *ipu_psys_copy_cmd(struct ipu_psys_command *cmd,
 	}
 
 	/* check and remap if possibe */
-	ret = ipu_psys_mapbuf_with_lock(fd, fh, kpgbuf);
+	ret = ipu_psys_mapbuf_locked(fd, fh, kpgbuf);
 	if (ret) {
 		dev_err(&psys->adev->dev, "%s remap failed\n", __func__);
 		mutex_unlock(&fh->mutex);
@@ -349,7 +349,7 @@ static struct ipu_psys_kcmd *ipu_psys_copy_cmd(struct ipu_psys_command *cmd,
 			goto error;
 		}
 
-		ret = ipu_psys_mapbuf_with_lock(fd, fh, kpgbuf);
+		ret = ipu_psys_mapbuf_locked(fd, fh, kpgbuf);
 		if (ret) {
 			dev_err(&psys->adev->dev, "%s remap failed\n",
 				__func__);
@@ -448,15 +448,17 @@ static struct ipu_psys_ppg *ipu_psys_lookup_ppg(struct ipu_psys *psys,
  * Move kcmd into completed state (due to running finished or failure).
  * Fill up the event struct and notify waiters.
  */
-void ipu_psys_kcmd_complete(struct ipu_psys *psys,
+void ipu_psys_kcmd_complete(struct ipu_psys_ppg *kppg,
 			    struct ipu_psys_kcmd *kcmd, int error)
 {
 	struct ipu_psys_fh *fh = kcmd->fh;
+	struct ipu_psys *psys = fh->psys;
 
 	kcmd->ev.type = IPU_PSYS_EVENT_TYPE_CMD_COMPLETE;
 	kcmd->ev.user_token = kcmd->user_token;
 	kcmd->ev.issue_id = kcmd->issue_id;
 	kcmd->ev.error = error;
+	list_move_tail(&kcmd->list, &kppg->kcmds_finished_list);
 
 	if (kcmd->constraint.min_freq)
 		ipu_buttress_remove_psys_constraint(psys->adev->isp,
@@ -532,90 +534,101 @@ static void ipu_psys_watchdog(struct timer_list *t)
 	queue_work(IPU_PSYS_WORK_QUEUE, &psys->watchdog_work);
 }
 
-static int ipu_psys_kcmd_send_to_ppg(struct ipu_psys_kcmd *kcmd)
+static int ipu_psys_kcmd_send_to_ppg_start(struct ipu_psys_kcmd *kcmd)
 {
 	struct ipu_psys_fh *fh = kcmd->fh;
 	struct ipu_psys_scheduler *sched = &fh->sched;
 	struct ipu_psys *psys = fh->psys;
 	struct ipu_psys_ppg *kppg;
 	struct ipu_psys_resource_pool *rpr;
-	unsigned long flags;
-	u8 id;
-	bool resche = true;
+	int queue_id;
+	int ret;
 
 	rpr = &psys->resource_pool_running;
-	if (kcmd->state == KCMD_STATE_PPG_START) {
-		int queue_id;
-		int ret;
 
-		mutex_lock(&psys->mutex);
-		queue_id = ipu_psys_allocate_cmd_queue_resource(rpr);
-		if (queue_id == -ENOSPC) {
-			dev_err(&psys->adev->dev, "no available queue\n");
-			mutex_unlock(&psys->mutex);
-			return -ENOMEM;
-		}
+	kppg = kzalloc(sizeof(*kppg), GFP_KERNEL);
+	if (!kppg)
+		return -ENOMEM;
+
+	kppg->fh = fh;
+	kppg->kpg = kcmd->kpg;
+	kppg->state = PPG_STATE_START;
+	kppg->pri_base = kcmd->priority;
+	kppg->pri_dynamic = 0;
+	INIT_LIST_HEAD(&kppg->list);
+
+	mutex_init(&kppg->mutex);
+	INIT_LIST_HEAD(&kppg->kcmds_new_list);
+	INIT_LIST_HEAD(&kppg->kcmds_processing_list);
+	INIT_LIST_HEAD(&kppg->kcmds_finished_list);
+	INIT_LIST_HEAD(&kppg->sched_list);
+
+	kppg->manifest = kzalloc(kcmd->pg_manifest_size, GFP_KERNEL);
+	if (!kppg->manifest) {
+		kfree(kppg);
+		return -ENOMEM;
+	}
+	memcpy(kppg->manifest, kcmd->pg_manifest,
+	       kcmd->pg_manifest_size);
+
+	queue_id = ipu_psys_allocate_cmd_queue_resource(rpr);
+	if (queue_id == -ENOSPC) {
+		dev_err(&psys->adev->dev, "no available queue\n");
+		kfree(kppg->manifest);
+		kfree(kppg);
 		mutex_unlock(&psys->mutex);
+		return -ENOMEM;
+	}
 
-		kppg = kzalloc(sizeof(*kppg), GFP_KERNEL);
-		if (!kppg)
-			return -ENOMEM;
-
-		kppg->fh = fh;
-		kppg->kpg = kcmd->kpg;
-		kppg->state = PPG_STATE_START;
-		kppg->pri_base = kcmd->priority;
-		kppg->pri_dynamic = 0;
-		INIT_LIST_HEAD(&kppg->list);
-
-		mutex_init(&kppg->mutex);
-		INIT_LIST_HEAD(&kppg->kcmds_new_list);
-		INIT_LIST_HEAD(&kppg->kcmds_processing_list);
-		INIT_LIST_HEAD(&kppg->kcmds_finished_list);
-		INIT_LIST_HEAD(&kppg->sched_list);
-
-		kppg->manifest = kzalloc(kcmd->pg_manifest_size, GFP_KERNEL);
-		if (!kppg->manifest) {
-			kfree(kppg);
-			return -ENOMEM;
-		}
-		memcpy(kppg->manifest, kcmd->pg_manifest,
-		       kcmd->pg_manifest_size);
+	/*
+	 * set token as start cmd will immediately be followed by a
+	 * enqueue cmd so that kppg could be retrieved.
+	 */
+	kppg->token = (u64)kcmd->kpg;
+	ipu_fw_psys_pg_set_token(kcmd, kppg->token);
+	ipu_fw_psys_ppg_set_base_queue_id(kcmd, queue_id);
+	ret = ipu_fw_psys_pg_set_ipu_vaddress(kcmd,
+					      kcmd->kpg->pg_dma_addr);
+	if (ret) {
+		ipu_psys_free_cmd_queue_resource(rpr, queue_id);
+		kfree(kppg->manifest);
+		kfree(kppg);
+		return -EIO;
+	}
+	memcpy(kcmd->pg_user, kcmd->kpg->pg, kcmd->kpg->pg_size);
 
-		/*
-		 * set token as start cmd will immediately be followed by a
-		 * enqueue cmd so that kppg could be retrieved.
-		 */
-		kppg->token = (u64)kcmd->kpg;
-		ipu_fw_psys_pg_set_token(kcmd, kppg->token);
-		ipu_fw_psys_ppg_set_base_queue_id(kcmd, queue_id);
-		ret = ipu_fw_psys_pg_set_ipu_vaddress(kcmd,
-						      kcmd->kpg->pg_dma_addr);
-		if (ret) {
-			kfree(kppg->manifest);
-			kfree(kppg);
-			return -EIO;
-		}
-		memcpy(kcmd->pg_user, kcmd->kpg->pg, kcmd->kpg->pg_size);
+	mutex_lock(&fh->mutex);
+	list_add_tail(&kppg->list, &sched->ppgs);
+	mutex_unlock(&fh->mutex);
 
-		mutex_lock(&fh->mutex);
-		list_add_tail(&kppg->list, &sched->ppgs);
-		mutex_unlock(&fh->mutex);
+	mutex_lock(&kppg->mutex);
+	list_add(&kcmd->list, &kppg->kcmds_new_list);
+	mutex_unlock(&kppg->mutex);
 
-		mutex_lock(&kppg->mutex);
-		list_add(&kcmd->list, &kppg->kcmds_new_list);
-		mutex_unlock(&kppg->mutex);
+	dev_dbg(&psys->adev->dev,
+		"START ppg(%d, 0x%p) kcmd 0x%p, queue %d\n",
+		ipu_fw_psys_pg_get_id(kcmd), kppg, kcmd, queue_id);
 
-		dev_dbg(&psys->adev->dev,
-			"START ppg(%d, 0x%p) kcmd 0x%p, queue %d\n",
-			ipu_fw_psys_pg_get_id(kcmd), kppg, kcmd, queue_id);
+	/* Kick l-scheduler thread */
+	atomic_set(&psys->wakeup_count, 1);
+	wake_up_interruptible(&psys->sched_cmd_wq);
 
-		/* Kick l-scheduler thread */
-		atomic_set(&psys->wakeup_count, 1);
-		wake_up_interruptible(&psys->sched_cmd_wq);
+	return 0;
+}
 
-		return 0;
-	}
+static int ipu_psys_kcmd_send_to_ppg(struct ipu_psys_kcmd *kcmd)
+{
+	struct ipu_psys_fh *fh = kcmd->fh;
+	struct ipu_psys *psys = fh->psys;
+	struct ipu_psys_ppg *kppg;
+	struct ipu_psys_resource_pool *rpr;
+	unsigned long flags;
+	u8 id;
+	bool resche = true;
+
+	rpr = &psys->resource_pool_running;
+	if (kcmd->state == KCMD_STATE_PPG_START)
+		return ipu_psys_kcmd_send_to_ppg_start(kcmd);
 
 	kppg = ipu_psys_identify_kppg(kcmd);
 	spin_lock_irqsave(&psys->pgs_lock, flags);
@@ -640,8 +653,7 @@ static int ipu_psys_kcmd_send_to_ppg(struct ipu_psys_kcmd *kcmd)
 				"kppg 0x%p  stopped!\n", kppg);
 			id = ipu_fw_psys_ppg_get_base_queue_id(kcmd);
 			ipu_psys_free_cmd_queue_resource(rpr, id);
-			list_add(&kcmd->list, &kppg->kcmds_finished_list);
-			ipu_psys_kcmd_complete(psys, kcmd, 0);
+			ipu_psys_kcmd_complete(kppg, kcmd, 0);
 			spin_lock_irqsave(&psys->pgs_lock, flags);
 			kppg->kpg->pg_size = 0;
 			spin_unlock_irqrestore(&psys->pgs_lock, flags);
@@ -765,7 +777,7 @@ void ipu_psys_handle_events(struct ipu_psys *psys)
 	bool error;
 	u32 hdl;
 	u16 cmd, status;
-	int res, state;
+	int res;
 
 	do {
 		memset(&event, 0, sizeof(event));
@@ -815,22 +827,19 @@ void ipu_psys_handle_events(struct ipu_psys *psys)
 			kppg = ipu_psys_lookup_ppg(psys, hdl);
 			if (kppg) {
 				mutex_lock(&kppg->mutex);
-				state = kppg->state;
-				if (state == PPG_STATE_STOPPING) {
+				if (kppg->state == PPG_STATE_STOPPING) {
 					kcmd = ipu_psys_ppg_get_stop_kcmd(kppg);
 					if (!kcmd)
 						error = true;
 				}
 				mutex_unlock(&kppg->mutex);
-			} else {
-				error = true;
 			}
 		} else {
 			dev_err(&psys->adev->dev, "invalid event\n");
 			continue;
 		}
 
-		if (error) {
+		if (error || !kppg) {
 			dev_err(&psys->adev->dev, "event error, command %d\n",
 				cmd);
 			break;
@@ -839,17 +848,15 @@ void ipu_psys_handle_events(struct ipu_psys *psys)
 		dev_dbg(&psys->adev->dev, "event to kppg 0x%p, kcmd 0x%p\n",
 			kppg, kcmd);
 
-		if (kppg)
-			ipu_psys_ppg_complete(psys, kppg);
+		ipu_psys_ppg_complete(psys, kppg);
 
 		if (kcmd && ipu_psys_kcmd_is_valid(psys, kcmd)) {
 			res = (status == IPU_PSYS_EVENT_CMD_COMPLETE ||
 			       status == IPU_PSYS_EVENT_FRAGMENT_COMPLETE) ?
 				0 : -EIO;
 			mutex_lock(&kppg->mutex);
-			list_move_tail(&kcmd->list, &kppg->kcmds_finished_list);
+			ipu_psys_kcmd_complete(kppg, kcmd, res);
 			mutex_unlock(&kppg->mutex);
-			ipu_psys_kcmd_complete(psys, kcmd, res);
 		}
 	} while (1);
 }
diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
index 79f4f3db0374..a404c2f301d0 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.c
+++ b/drivers/media/pci/intel/ipu6/ipu6.c
@@ -58,6 +58,7 @@ static unsigned int ipu6se_csi_offsets[] = {
 	IPU_CSI_PORT_D_ADDR_OFFSET,
 };
 
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
 static unsigned int ipu6se_tpg_offsets[] = {
 	IPU_CSI_PORT_A_PIXGEN_ADDR_OFFSET,
 	IPU_CSI_PORT_B_PIXGEN_ADDR_OFFSET,
@@ -65,17 +66,6 @@ static unsigned int ipu6se_tpg_offsets[] = {
 	IPU_CSI_PORT_D_PIXGEN_ADDR_OFFSET,
 };
 
-static unsigned int ipu6_csi_offsets[] = {
-	IPU_CSI_PORT_A_ADDR_OFFSET,
-	IPU_CSI_PORT_B_ADDR_OFFSET,
-	IPU_CSI_PORT_C_ADDR_OFFSET,
-	IPU_CSI_PORT_D_ADDR_OFFSET,
-	IPU_CSI_PORT_E_ADDR_OFFSET,
-	IPU_CSI_PORT_F_ADDR_OFFSET,
-	IPU_CSI_PORT_G_ADDR_OFFSET,
-	IPU_CSI_PORT_H_ADDR_OFFSET
-};
-
 static unsigned int ipu6_tpg_offsets[] = {
 	IPU_CSI_PORT_A_PIXGEN_ADDR_OFFSET,
 	IPU_CSI_PORT_B_PIXGEN_ADDR_OFFSET,
@@ -86,6 +76,18 @@ static unsigned int ipu6_tpg_offsets[] = {
 	IPU_CSI_PORT_G_PIXGEN_ADDR_OFFSET,
 	IPU_CSI_PORT_H_PIXGEN_ADDR_OFFSET
 };
+#endif
+
+static unsigned int ipu6_csi_offsets[] = {
+	IPU_CSI_PORT_A_ADDR_OFFSET,
+	IPU_CSI_PORT_B_ADDR_OFFSET,
+	IPU_CSI_PORT_C_ADDR_OFFSET,
+	IPU_CSI_PORT_D_ADDR_OFFSET,
+	IPU_CSI_PORT_E_ADDR_OFFSET,
+	IPU_CSI_PORT_F_ADDR_OFFSET,
+	IPU_CSI_PORT_G_ADDR_OFFSET,
+	IPU_CSI_PORT_H_ADDR_OFFSET
+};
 
 struct ipu_isys_internal_pdata isys_ipdata = {
 	.hw_variant = {
@@ -367,18 +369,22 @@ void ipu_internal_pdata_init(void)
 	if (ipu_ver == IPU_VER_6) {
 		isys_ipdata.csi2.nports = ARRAY_SIZE(ipu6_csi_offsets);
 		isys_ipdata.csi2.offsets = ipu6_csi_offsets;
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
 		isys_ipdata.tpg.ntpgs = ARRAY_SIZE(ipu6_tpg_offsets);
 		isys_ipdata.tpg.offsets = ipu6_tpg_offsets;
 		isys_ipdata.tpg.sels = NULL;
+#endif
 		isys_ipdata.num_parallel_streams = IPU6_ISYS_NUM_STREAMS;
 		psys_ipdata.hw_variant.spc_offset = IPU6_PSYS_SPC_OFFSET;
 
 	} else if (ipu_ver == IPU_VER_6SE) {
 		isys_ipdata.csi2.nports = ARRAY_SIZE(ipu6se_csi_offsets);
 		isys_ipdata.csi2.offsets = ipu6se_csi_offsets;
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
 		isys_ipdata.tpg.ntpgs = ARRAY_SIZE(ipu6se_tpg_offsets);
 		isys_ipdata.tpg.offsets = ipu6se_tpg_offsets;
 		isys_ipdata.tpg.sels = NULL;
+#endif
 		isys_ipdata.num_parallel_streams = IPU6SE_ISYS_NUM_STREAMS;
 		psys_ipdata.hw_variant.spc_offset = IPU6SE_PSYS_SPC_OFFSET;
 	}
