From 88453f29216e4dc473683b0fa9fe5e3e7ae0bff2 Mon Sep 17 00:00:00 2001
From: Romuald JEANNE <romuald.jeanne@st.com>
Date: Tue, 16 Mar 2021 09:11:20 +0100
Subject: [PATCH 10/22] ARM 5.10.10-stm32mp1-r1 MEDIA-SOC-THERMAL

Signed-off-by: Romuald JEANNE <romuald.jeanne@st.com>
---
 drivers/media/cec/platform/Makefile       |   1 +
 drivers/media/i2c/ov5640.c                | 111 +++++++---
 drivers/media/platform/stm32/stm32-dcmi.c | 122 +++++++++--
 drivers/media/v4l2-core/v4l2-fwnode.c     |   3 +
 drivers/soc/Kconfig                       |   1 +
 drivers/soc/Makefile                      |   1 +
 drivers/soc/st/Kconfig                    |  17 ++
 drivers/soc/st/Makefile                   |   2 +
 drivers/soc/st/stm32_hdp.c                | 242 ++++++++++++++++++++++
 drivers/soc/st/stm32_pm_domain.c          | 212 +++++++++++++++++++
 drivers/thermal/st/stm_thermal.c          |  30 +--
 include/dt-bindings/soc/stm32-hdp.h       | 108 ++++++++++
 include/media/v4l2-fwnode.h               |   2 +
 13 files changed, 784 insertions(+), 68 deletions(-)
 create mode 100644 drivers/soc/st/Kconfig
 create mode 100644 drivers/soc/st/Makefile
 create mode 100644 drivers/soc/st/stm32_hdp.c
 create mode 100644 drivers/soc/st/stm32_pm_domain.c
 create mode 100644 include/dt-bindings/soc/stm32-hdp.h

diff --git a/drivers/media/cec/platform/Makefile b/drivers/media/cec/platform/Makefile
index 3a947159b25a..ea6f8ee8161c 100644
--- a/drivers/media/cec/platform/Makefile
+++ b/drivers/media/cec/platform/Makefile
@@ -10,5 +10,6 @@ obj-$(CONFIG_CEC_MESON_AO)	+= meson/
 obj-$(CONFIG_CEC_SAMSUNG_S5P)	+= s5p/
 obj-$(CONFIG_CEC_SECO)		+= seco/
 obj-$(CONFIG_CEC_STI)		+= sti/
+obj-$(CONFIG_CEC_STM32)		+= stm32/
 obj-$(CONFIG_CEC_TEGRA)		+= tegra/
 
diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c
index 8f0812e85901..d7d36ad863ea 100644
--- a/drivers/media/i2c/ov5640.c
+++ b/drivers/media/i2c/ov5640.c
@@ -65,6 +65,7 @@
 #define OV5640_REG_TIMING_VTS		0x380e
 #define OV5640_REG_TIMING_TC_REG20	0x3820
 #define OV5640_REG_TIMING_TC_REG21	0x3821
+#define OV5640_REG_DVP_PCLK_DIVIDER	0x3824
 #define OV5640_REG_AEC_CTRL00		0x3a00
 #define OV5640_REG_AEC_B50_STEP		0x3a08
 #define OV5640_REG_AEC_B60_STEP		0x3a0a
@@ -98,7 +99,8 @@
 #define OV5640_REG_AVG_READOUT		0x56a1
 
 enum ov5640_mode_id {
-	OV5640_MODE_QCIF_176_144 = 0,
+	OV5640_MODE_QQVGA_160_120 = 0,
+	OV5640_MODE_QCIF_176_144,
 	OV5640_MODE_QVGA_320_240,
 	OV5640_MODE_VGA_640_480,
 	OV5640_MODE_NTSC_720_480,
@@ -113,7 +115,6 @@ enum ov5640_mode_id {
 enum ov5640_frame_rate {
 	OV5640_15_FPS = 0,
 	OV5640_30_FPS,
-	OV5640_60_FPS,
 	OV5640_NUM_FRAMERATES,
 };
 
@@ -155,7 +156,6 @@ MODULE_PARM_DESC(virtual_channel,
 static const int ov5640_framerates[] = {
 	[OV5640_15_FPS] = 15,
 	[OV5640_30_FPS] = 30,
-	[OV5640_60_FPS] = 60,
 };
 
 /* regulator supplies */
@@ -219,6 +219,7 @@ struct ov5640_ctrls {
 	struct v4l2_ctrl *test_pattern;
 	struct v4l2_ctrl *hflip;
 	struct v4l2_ctrl *vflip;
+	struct v4l2_ctrl *link_freq;
 };
 
 struct ov5640_dev {
@@ -374,8 +375,8 @@ static const struct reg_value ov5640_setting_VGA_640_480[] = {
 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
-	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
-	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
+	{0x4407, 0x04, 0, 0},
+	{0x5001, 0xa3, 0, 0},
 };
 
 static const struct reg_value ov5640_setting_XGA_1024_768[] = {
@@ -393,8 +394,7 @@ static const struct reg_value ov5640_setting_XGA_1024_768[] = {
 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
-	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
-	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
+	{0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0},
 };
 
 static const struct reg_value ov5640_setting_QVGA_320_240[] = {
@@ -412,8 +412,25 @@ static const struct reg_value ov5640_setting_QVGA_320_240[] = {
 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
-	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
-	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
+	{0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0},
+};
+
+static const struct reg_value ov5640_setting_QQVGA_160_120[] = {
+	{0x3c07, 0x08, 0, 0},
+	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+	{0x3814, 0x31, 0, 0},
+	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+	{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
+	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
+	{0x3810, 0x00, 0, 0},
+	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
+	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
+	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
+	{0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0},
 };
 
 static const struct reg_value ov5640_setting_QCIF_176_144[] = {
@@ -431,8 +448,7 @@ static const struct reg_value ov5640_setting_QCIF_176_144[] = {
 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
-	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
-	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
+	{0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0},
 };
 
 static const struct reg_value ov5640_setting_NTSC_720_480[] = {
@@ -450,8 +466,7 @@ static const struct reg_value ov5640_setting_NTSC_720_480[] = {
 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
-	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
-	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
+	{0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0},
 };
 
 static const struct reg_value ov5640_setting_PAL_720_576[] = {
@@ -469,8 +484,7 @@ static const struct reg_value ov5640_setting_PAL_720_576[] = {
 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
-	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
-	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
+	{0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0},
 };
 
 static const struct reg_value ov5640_setting_720P_1280_720[] = {
@@ -488,8 +502,7 @@ static const struct reg_value ov5640_setting_720P_1280_720[] = {
 	{0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0},
 	{0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0},
 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
-	{0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0},
-	{0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0},
+	{0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0},
 };
 
 static const struct reg_value ov5640_setting_1080P_1920_1080[] = {
@@ -507,8 +520,8 @@ static const struct reg_value ov5640_setting_1080P_1920_1080[] = {
 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
 	{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0},
-	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
-	{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0},
+	{0x4407, 0x04, 0, 0},
+	{0x5001, 0x83, 0, 0},
 	{0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0},
 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
 	{0x3800, 0x01, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3802, 0x01, 0, 0},
@@ -519,7 +532,6 @@ static const struct reg_value ov5640_setting_1080P_1920_1080[] = {
 	{0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0},
 	{0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0},
 	{0x3a15, 0x60, 0, 0}, {0x4407, 0x04, 0, 0},
-	{0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0},
 	{0x4005, 0x1a, 0, 0},
 };
 
@@ -538,8 +550,8 @@ static const struct reg_value ov5640_setting_QSXGA_2592_1944[] = {
 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
 	{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0},
-	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
-	{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 70},
+	{0x4407, 0x04, 0, 0},
+	{0x5001, 0x83, 0, 70},
 };
 
 /* power-on sensor init reg table */
@@ -552,6 +564,11 @@ static const struct ov5640_mode_info ov5640_mode_init_data = {
 
 static const struct ov5640_mode_info
 ov5640_mode_data[OV5640_NUM_MODES] = {
+	{OV5640_MODE_QQVGA_160_120, SUBSAMPLING,
+	 160, 1896, 120, 984,
+	 ov5640_setting_QQVGA_160_120,
+	 ARRAY_SIZE(ov5640_setting_QQVGA_160_120),
+	 OV5640_30_FPS},
 	{OV5640_MODE_QCIF_176_144, SUBSAMPLING,
 	 176, 1896, 144, 984,
 	 ov5640_setting_QCIF_176_144,
@@ -566,7 +583,7 @@ ov5640_mode_data[OV5640_NUM_MODES] = {
 	 640, 1896, 480, 1080,
 	 ov5640_setting_VGA_640_480,
 	 ARRAY_SIZE(ov5640_setting_VGA_640_480),
-	 OV5640_60_FPS},
+	 OV5640_30_FPS},
 	{OV5640_MODE_NTSC_720_480, SUBSAMPLING,
 	 720, 1896, 480, 984,
 	 ov5640_setting_NTSC_720_480,
@@ -1018,9 +1035,38 @@ static unsigned long ov5640_calc_pclk(struct ov5640_dev *sensor,
 
 static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor, unsigned long rate)
 {
+	const struct ov5640_mode_info *mode = sensor->current_mode;
 	u8 prediv, mult, sysdiv, pll_rdiv, bit_div, pclk_div;
+	struct i2c_client *client = sensor->i2c_client;
+	unsigned int pclk_freq, max_pclk_freq;
+	u8 dvp_pclk_divider;
 	int ret;
 
+	/*
+	 * 1280x720 and 1024x768 are reported to use 'SUBSAMPLING' only,
+	 * but they seems to go through the scaler before subsampling.
+	 */
+	if (mode->dn_mode == SCALING ||
+	   (mode->id == OV5640_MODE_720P_1280_720) ||
+	   (mode->id == OV5640_MODE_XGA_1024_768))
+		dvp_pclk_divider = 1;
+	else
+		dvp_pclk_divider = 2;
+
+	ret = ov5640_write_reg(sensor, OV5640_REG_DVP_PCLK_DIVIDER,
+			       dvp_pclk_divider);
+	if (ret)
+		return ret;
+	pclk_freq = rate / dvp_pclk_divider;
+	max_pclk_freq = sensor->ep.bus.parallel.pclk_max_frequency;
+
+	/* clip rate according to optional maximum pixel clock limit */
+	if (max_pclk_freq && (pclk_freq > max_pclk_freq)) {
+		rate = max_pclk_freq * dvp_pclk_divider;
+		dev_dbg(&client->dev, "DVP pixel clock too high (%d > %d Hz), reducing rate...\n",
+			pclk_freq, max_pclk_freq);
+	}
+
 	ov5640_calc_pclk(sensor, rate, &prediv, &mult, &sysdiv, &pll_rdiv,
 			 &bit_div, &pclk_div);
 
@@ -1055,6 +1101,7 @@ static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor, unsigned long rate)
 			      (ilog2(pclk_div) << 4));
 }
 
+#if 0
 /* set JPEG framing sizes */
 static int ov5640_set_jpeg_timings(struct ov5640_dev *sensor,
 				   const struct ov5640_mode_info *mode)
@@ -1078,19 +1125,20 @@ static int ov5640_set_jpeg_timings(struct ov5640_dev *sensor,
 
 	return ov5640_write_reg16(sensor, OV5640_REG_VFIFO_VSIZE, mode->vact);
 }
+#endif
 
 /* download ov5640 settings to sensor through i2c */
 static int ov5640_set_timings(struct ov5640_dev *sensor,
 			      const struct ov5640_mode_info *mode)
 {
 	int ret;
-
+#if 0
 	if (sensor->fmt.code == MEDIA_BUS_FMT_JPEG_1X8) {
 		ret = ov5640_set_jpeg_timings(sensor, mode);
 		if (ret < 0)
 			return ret;
 	}
-
+#endif
 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, mode->hact);
 	if (ret < 0)
 		return ret;
@@ -2172,12 +2220,12 @@ static int ov5640_try_frame_interval(struct ov5640_dev *sensor,
 	int i;
 
 	minfps = ov5640_framerates[OV5640_15_FPS];
-	maxfps = ov5640_framerates[OV5640_60_FPS];
+	maxfps = ov5640_framerates[OV5640_30_FPS];
 
 	if (fi->numerator == 0) {
 		fi->denominator = maxfps;
 		fi->numerator = 1;
-		rate = OV5640_60_FPS;
+		rate = OV5640_30_FPS;
 		goto find_mode;
 	}
 
@@ -2260,6 +2308,10 @@ static int ov5640_try_fmt_internal(struct v4l2_subdev *sd,
 	return 0;
 }
 
+static const s64 link_freq_menu_items[] = {
+	384000000,
+};
+
 static int ov5640_set_fmt(struct v4l2_subdev *sd,
 			  struct v4l2_subdev_pad_config *cfg,
 			  struct v4l2_subdev_format *format)
@@ -2700,6 +2752,8 @@ static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl)
 	case V4L2_CID_VFLIP:
 		ret = ov5640_set_ctrl_vflip(sensor, ctrl->val);
 		break;
+	case V4L2_CID_LINK_FREQ:
+		return 0;
 	default:
 		ret = -EINVAL;
 		break;
@@ -2772,6 +2826,9 @@ static int ov5640_init_controls(struct ov5640_dev *sensor)
 				       V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0,
 				       V4L2_CID_POWER_LINE_FREQUENCY_50HZ);
 
+	ctrls->link_freq = v4l2_ctrl_new_int_menu(hdl, ops, V4L2_CID_LINK_FREQ,
+						  0, 0, link_freq_menu_items);
+
 	if (hdl->error) {
 		ret = hdl->error;
 		goto free_ctrls;
diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c
index fd1c41cba52f..60ef8a65f16c 100644
--- a/drivers/media/platform/stm32/stm32-dcmi.c
+++ b/drivers/media/platform/stm32/stm32-dcmi.c
@@ -95,6 +95,9 @@ enum state {
 #define MIN_HEIGHT	16U
 #define MAX_HEIGHT	2592U
 
+/* DMA can sustain YUV 720p@15fps max */
+#define MAX_DMA_BANDWIDTH	(1280 * 720 * 2 * 15)
+
 #define TIMEOUT_MS	1000
 
 #define OVERRUN_ERROR_THRESHOLD	3
@@ -157,6 +160,7 @@ struct stm32_dcmi {
 	struct vb2_queue		queue;
 
 	struct v4l2_fwnode_bus_parallel	bus;
+	enum v4l2_mbus_type		bus_type;
 	struct completion		complete;
 	struct clk			*mclk;
 	enum state			state;
@@ -324,7 +328,7 @@ static int dcmi_start_dma(struct stm32_dcmi *dcmi,
 	}
 
 	/*
-	 * Avoid call of dmaengine_terminate_all() between
+	 * Avoid call of dmaengine_terminate_sync() between
 	 * dmaengine_prep_slave_single() and dmaengine_submit()
 	 * by locking the whole DMA submission sequence
 	 */
@@ -438,7 +442,7 @@ static void dcmi_process_jpeg(struct stm32_dcmi *dcmi)
 	}
 
 	/* Abort DMA operation */
-	dmaengine_terminate_all(dcmi->dma_chan);
+	dmaengine_terminate_sync(dcmi->dma_chan);
 
 	/* Restart capture */
 	if (dcmi_restart_capture(dcmi))
@@ -777,6 +781,23 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count)
 	if (dcmi->bus.flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
 		val |= CR_PCKPOL;
 
+	/*
+	 * BT656 embedded synchronisation bus mode.
+	 *
+	 * Default SAV/EAV mode is supported here with default codes
+	 * SAV=0xff000080 & EAV=0xff00009d.
+	 * With DCMI this means LSC=SAV=0x80 & LEC=EAV=0x9d.
+	 */
+	if (dcmi->bus_type == V4L2_MBUS_BT656) {
+		val |= CR_ESS;
+
+		/* Unmask all codes */
+		reg_write(dcmi->regs, DCMI_ESUR, 0xffffffff);/* FEC:LEC:LSC:FSC */
+
+		/* Trig on LSC=0x80 & LEC=0x9d codes, ignore FSC and FEC */
+		reg_write(dcmi->regs, DCMI_ESCR, 0xff9d80ff);/* FEC:LEC:LSC:FSC */
+	}
+
 	reg_write(dcmi->regs, DCMI_CR, val);
 
 	/* Set crop */
@@ -784,8 +805,31 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count)
 		dcmi_set_crop(dcmi);
 
 	/* Enable jpeg capture */
-	if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG)
-		reg_set(dcmi->regs, DCMI_CR, CR_CM);/* Snapshot mode */
+	if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG) {
+		unsigned int rate;
+		struct v4l2_streamparm p = {
+			.type = V4L2_BUF_TYPE_VIDEO_CAPTURE
+		};
+		struct v4l2_fract frame_interval = {1, 30};
+
+		ret = v4l2_g_parm_cap(dcmi->vdev, dcmi->entity.source, &p);
+		if (!ret)
+			frame_interval = p.parm.capture.timeperframe;
+
+		rate = dcmi->fmt.fmt.pix.sizeimage *
+		       frame_interval.denominator / frame_interval.numerator;
+
+		/*
+		 * If rate exceed DMA capabilities, switch to snapshot mode
+		 * to ensure that current DMA transfer is elapsed before
+		 * capturing a new JPEG.
+		 */
+		if (rate > MAX_DMA_BANDWIDTH) {
+			reg_set(dcmi->regs, DCMI_CR, CR_CM);/* Snapshot mode */
+			dev_dbg(dcmi->dev, "Capture rate is too high for continuous mode (%d > %d bytes/s), switch to snapshot mode\n",
+				rate, MAX_DMA_BANDWIDTH);
+		}
+	}
 
 	/* Enable dcmi */
 	reg_set(dcmi->regs, DCMI_CR, CR_ENABLE);
@@ -882,7 +926,7 @@ static void dcmi_stop_streaming(struct vb2_queue *vq)
 
 	/* Stop all pending DMA operations */
 	mutex_lock(&dcmi->dma_lock);
-	dmaengine_terminate_all(dcmi->dma_chan);
+	dmaengine_terminate_sync(dcmi->dma_chan);
 	mutex_unlock(&dcmi->dma_lock);
 
 	pm_runtime_put(dcmi->dev);
@@ -1067,8 +1111,9 @@ static int dcmi_set_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f)
 	if (ret)
 		return ret;
 
-	/* Disable crop if JPEG is requested */
-	if (pix->pixelformat == V4L2_PIX_FMT_JPEG)
+	/* Disable crop if JPEG is requested or BT656 bus is selected */
+	if (pix->pixelformat == V4L2_PIX_FMT_JPEG &&
+	    dcmi->bus_type != V4L2_MBUS_BT656)
 		dcmi->do_crop = false;
 
 	/* pix to mbus format */
@@ -1574,6 +1619,22 @@ static const struct dcmi_format dcmi_formats[] = {
 		.fourcc = V4L2_PIX_FMT_JPEG,
 		.mbus_code = MEDIA_BUS_FMT_JPEG_1X8,
 		.bpp = 1,
+	}, {
+		.fourcc = V4L2_PIX_FMT_SBGGR8,
+		.mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8,
+		.bpp = 1,
+	}, {
+		.fourcc = V4L2_PIX_FMT_SGBRG8,
+		.mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8,
+		.bpp = 1,
+	}, {
+		.fourcc = V4L2_PIX_FMT_SGRBG8,
+		.mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8,
+		.bpp = 1,
+	}, {
+		.fourcc = V4L2_PIX_FMT_SRGGB8,
+		.mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8,
+		.bpp = 1,
 	},
 };
 
@@ -1592,6 +1653,11 @@ static int dcmi_formats_init(struct stm32_dcmi *dcmi)
 			if (dcmi_formats[i].mbus_code != mbus_code.code)
 				continue;
 
+			/* Exclude JPEG if BT656 bus is selected */
+			if (dcmi_formats[i].fourcc == V4L2_PIX_FMT_JPEG &&
+			    dcmi->bus_type == V4L2_MBUS_BT656)
+				continue;
+
 			/* Code supported, have we got this fourcc yet? */
 			for (j = 0; j < num_fmts; j++)
 				if (sd_fmts[j]->fourcc ==
@@ -1745,6 +1811,15 @@ static int dcmi_graph_notify_bound(struct v4l2_async_notifier *notifier,
 
 	dev_dbg(dcmi->dev, "Subdev \"%s\" bound\n", subdev->name);
 
+	ret = video_register_device(dcmi->vdev, VFL_TYPE_VIDEO, -1);
+	if (ret) {
+		dev_err(dcmi->dev, "Failed to register video device\n");
+		return ret;
+	}
+
+	dev_dbg(dcmi->dev, "Device registered as %s\n",
+		video_device_node_name(dcmi->vdev));
+
 	/*
 	 * Link this sub-device to DCMI, it could be
 	 * a parallel camera sensor or a bridge
@@ -1757,10 +1832,11 @@ static int dcmi_graph_notify_bound(struct v4l2_async_notifier *notifier,
 				    &dcmi->vdev->entity, 0,
 				    MEDIA_LNK_FL_IMMUTABLE |
 				    MEDIA_LNK_FL_ENABLED);
-	if (ret)
+	if (ret) {
 		dev_err(dcmi->dev, "Failed to create media pad link with subdev \"%s\"\n",
 			subdev->name);
-	else
+		video_unregister_device(dcmi->vdev);
+	} else
 		dev_dbg(dcmi->dev, "DCMI is now linked to \"%s\"\n",
 			subdev->name);
 
@@ -1851,7 +1927,9 @@ static int dcmi_probe(struct platform_device *pdev)
 
 	dcmi->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
 	if (IS_ERR(dcmi->rstc)) {
-		dev_err(&pdev->dev, "Could not get reset control\n");
+		if (PTR_ERR(dcmi->rstc) != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "Could not get reset control\n");
+
 		return PTR_ERR(dcmi->rstc);
 	}
 
@@ -1873,9 +1951,18 @@ static int dcmi_probe(struct platform_device *pdev)
 		dev_err(&pdev->dev, "CSI bus not supported\n");
 		return -ENODEV;
 	}
+
+	if (ep.bus_type == V4L2_MBUS_BT656 &&
+	    ep.bus.parallel.bus_width != 8) {
+		dev_err(&pdev->dev, "BT656 bus conflicts with %u bits bus width (8 bits required)\n",
+			ep.bus.parallel.bus_width);
+		return -ENODEV;
+	}
+
 	dcmi->bus.flags = ep.bus.parallel.flags;
 	dcmi->bus.bus_width = ep.bus.parallel.bus_width;
 	dcmi->bus.data_shift = ep.bus.parallel.data_shift;
+	dcmi->bus_type = ep.bus_type;
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq <= 0)
@@ -1972,15 +2059,6 @@ static int dcmi_probe(struct platform_device *pdev)
 	}
 	dcmi->vdev->entity.flags |= MEDIA_ENT_FL_DEFAULT;
 
-	ret = video_register_device(dcmi->vdev, VFL_TYPE_VIDEO, -1);
-	if (ret) {
-		dev_err(dcmi->dev, "Failed to register video device\n");
-		goto err_media_entity_cleanup;
-	}
-
-	dev_dbg(dcmi->dev, "Device registered as %s\n",
-		video_device_node_name(dcmi->vdev));
-
 	/* Buffer queue */
 	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 	q->io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF;
@@ -2001,7 +2079,7 @@ static int dcmi_probe(struct platform_device *pdev)
 
 	ret = dcmi_graph_init(dcmi);
 	if (ret < 0)
-		goto err_media_entity_cleanup;
+		goto err_vb2_queue_release;
 
 	/* Reset device */
 	ret = reset_control_assert(dcmi->rstc);
@@ -2027,7 +2105,10 @@ static int dcmi_probe(struct platform_device *pdev)
 	return 0;
 
 err_cleanup:
+	v4l2_async_notifier_unregister(&dcmi->notifier);
 	v4l2_async_notifier_cleanup(&dcmi->notifier);
+err_vb2_queue_release:
+	vb2_queue_release(q);
 err_media_entity_cleanup:
 	media_entity_cleanup(&dcmi->vdev->entity);
 err_device_release:
@@ -2049,6 +2130,7 @@ static int dcmi_remove(struct platform_device *pdev)
 
 	v4l2_async_notifier_unregister(&dcmi->notifier);
 	v4l2_async_notifier_cleanup(&dcmi->notifier);
+	vb2_queue_release(&dcmi->queue);
 	media_entity_cleanup(&dcmi->vdev->entity);
 	v4l2_device_unregister(&dcmi->v4l2_dev);
 	media_device_cleanup(&dcmi->mdev);
diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
index dfc53d11053f..7d0e2f5d1700 100644
--- a/drivers/media/v4l2-core/v4l2-fwnode.c
+++ b/drivers/media/v4l2-core/v4l2-fwnode.c
@@ -356,6 +356,9 @@ v4l2_fwnode_endpoint_parse_parallel_bus(struct fwnode_handle *fwnode,
 		pr_debug("data-enable-active %s\n", v ? "high" : "low");
 	}
 
+	if (!fwnode_property_read_u32(fwnode, "pclk-max-frequency", &v))
+		bus->pclk_max_frequency = v;
+
 	switch (bus_type) {
 	default:
 		bus->flags = flags;
diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
index 425ab6f7e375..30afdfbfd9cc 100644
--- a/drivers/soc/Kconfig
+++ b/drivers/soc/Kconfig
@@ -15,6 +15,7 @@ source "drivers/soc/renesas/Kconfig"
 source "drivers/soc/rockchip/Kconfig"
 source "drivers/soc/samsung/Kconfig"
 source "drivers/soc/sifive/Kconfig"
+source "drivers/soc/st/Kconfig"
 source "drivers/soc/sunxi/Kconfig"
 source "drivers/soc/tegra/Kconfig"
 source "drivers/soc/ti/Kconfig"
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
index 36452bed86ef..6b957db9a9bb 100644
--- a/drivers/soc/Makefile
+++ b/drivers/soc/Makefile
@@ -21,6 +21,7 @@ obj-y				+= renesas/
 obj-$(CONFIG_ARCH_ROCKCHIP)	+= rockchip/
 obj-$(CONFIG_SOC_SAMSUNG)	+= samsung/
 obj-$(CONFIG_SOC_SIFIVE)	+= sifive/
+obj-$(CONFIG_ARCH_STM32)	+= st/
 obj-y				+= sunxi/
 obj-$(CONFIG_ARCH_TEGRA)	+= tegra/
 obj-y				+= ti/
diff --git a/drivers/soc/st/Kconfig b/drivers/soc/st/Kconfig
new file mode 100644
index 000000000000..8ab604999db4
--- /dev/null
+++ b/drivers/soc/st/Kconfig
@@ -0,0 +1,17 @@
+if ARCH_STM32
+
+config STM32_PM_DOMAINS
+	bool "STM32 PM domains"
+	depends on MACH_STM32MP157
+	select PM_GENERIC_DOMAINS
+	default y if MACH_STM32MP157
+
+config STM32_HDP
+	bool "STMicroelectronics STM32MP157 Hardware Debug Port (HDP) pin control"
+	depends on MACH_STM32MP157
+	default n if MACH_STM32MP157
+	help
+	  The Hardware Debug Port allows the observation of internal signals. By using multiplexers,
+	  up to 16 signals for each of 8-bit output can be observed.
+
+endif # ARCH_STM32
diff --git a/drivers/soc/st/Makefile b/drivers/soc/st/Makefile
new file mode 100644
index 000000000000..85905b7688ed
--- /dev/null
+++ b/drivers/soc/st/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_STM32_PM_DOMAINS) += stm32_pm_domain.o
+obj-$(CONFIG_STM32_HDP) += stm32_hdp.o
diff --git a/drivers/soc/st/stm32_hdp.c b/drivers/soc/st/stm32_hdp.c
new file mode 100644
index 000000000000..47687ebd1ffd
--- /dev/null
+++ b/drivers/soc/st/stm32_hdp.c
@@ -0,0 +1,242 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
+ * Author: Christophe Roullier <christophe.roullier@st.com>
+ * for STMicroelectronics.
+ */
+
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/module.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/suspend.h>
+
+#define HDP_CTRL_ENABLE 1
+#define HDP_CTRL_DISABLE 0
+
+enum {
+	HDP_CTRL = 0,
+	HDP_MUX = 0x4,
+	HDP_VAL = 0x10,
+	HDP_GPOSET = 0x14,
+	HDP_GPOCLR = 0x18,
+	HDP_GPOVAL = 0x1c,
+	HDP_VERR = 0x3f4,
+	HDP_IPIDR = 0x3f8,
+	HDP_SIDR = 0x3fc
+} HDP_register_offsets;
+
+struct data_priv {
+	struct clk *clk;
+	int clk_is_enabled;
+	struct dentry *pwr_dentry;
+	unsigned char __iomem *hdp_membase;
+	unsigned int hdp_ctrl;
+	unsigned int hdp_mux;
+};
+
+/* enable/disable */
+static int stm32_hdp_enable_set(void *data, int val)
+{
+	struct data_priv *e = (struct data_priv *)data;
+
+	if (!e->clk)
+		return -EPERM;
+
+	if (val == 1) {
+		if (clk_prepare_enable(e->clk) < 0) {
+			pr_err("Failed to enable HDP clock\n");
+			return -EPERM;
+		}
+		e->clk_is_enabled = 1;
+	} else {
+		clk_disable_unprepare(e->clk);
+		e->clk_is_enabled = 0;
+	}
+	return 0;
+}
+
+static int stm32_hdp_fops_set(void *data, u64 val)
+{
+	unsigned char __iomem *addr = (unsigned char __iomem *)data;
+
+	writel_relaxed(val, addr);
+
+	return 0;
+}
+
+static int stm32_hdp_fops_get(void *data, u64 *val)
+{
+	unsigned char __iomem *addr = (unsigned char __iomem *)data;
+
+	*val = readl_relaxed(addr);
+
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(stm32_hdp_fops, stm32_hdp_fops_get,
+			stm32_hdp_fops_set, "0x%llx\n");
+
+static int stm32_hdp_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+
+	struct data_priv *data;
+	struct dentry *r;
+
+	int ret;
+	const __be32 *getmuxing;
+	u32 muxing, version;
+
+	if (!np)
+		return -ENODEV;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(struct data_priv), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	data->hdp_membase = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(data->hdp_membase))
+		return PTR_ERR(data->hdp_membase);
+
+	/*  Get HDP clocks */
+	data->clk = devm_clk_get(dev, "hdp");
+	if (IS_ERR(data->clk)) {
+		dev_err(dev, "No HDP CK clock provided...\n");
+		return PTR_ERR(data->clk);
+	}
+
+	/* Enable clock */
+	ret = stm32_hdp_enable_set(data, 1);
+	if (ret != 0)
+		return ret;
+
+	getmuxing = of_get_property(np, "muxing-hdp", NULL);
+	if (!getmuxing) {
+		dev_err(dev,
+			"no muxing-hdp property in node\n");
+		/* Disable clock */
+		ret = stm32_hdp_enable_set(data, 0);
+		if (ret != 0)
+			return ret;
+
+		return -EINVAL;
+	}
+
+	/* add hdp directory */
+	r = debugfs_create_dir("hdp", NULL);
+	if (!r) {
+		dev_err(dev, "Unable to create HDP debugFS\n");
+		/* Disable clock */
+		ret = stm32_hdp_enable_set(data, 0);
+		if (ret != 0)
+			return ret;
+
+		return -ENODEV;
+	}
+
+	debugfs_create_file("ctrl", 0644, r,
+			    data->hdp_membase + HDP_CTRL, &stm32_hdp_fops);
+	debugfs_create_file("mux", 0644, r,
+			    data->hdp_membase + HDP_MUX, &stm32_hdp_fops);
+	debugfs_create_file("val", 0644, r,
+			    data->hdp_membase + HDP_VAL, &stm32_hdp_fops);
+	debugfs_create_file("gposet", 0644, r,
+			    data->hdp_membase + HDP_GPOSET, &stm32_hdp_fops);
+	debugfs_create_file("gpoclr", 0644, r,
+			    data->hdp_membase + HDP_GPOCLR, &stm32_hdp_fops);
+	debugfs_create_file("gpoval", 0644, r,
+			    data->hdp_membase + HDP_GPOVAL, &stm32_hdp_fops);
+
+	/* Enable HDP */
+	writel(HDP_CTRL_ENABLE, data->hdp_membase + HDP_CTRL);
+
+	/* HDP Multiplexing */
+	muxing = of_read_number(getmuxing,
+				of_n_addr_cells(np));
+
+	writel(muxing, data->hdp_membase + HDP_MUX);
+
+	platform_set_drvdata(pdev, data);
+
+	/* Get Majeur, Minor version */
+	version = readl(data->hdp_membase + HDP_VERR);
+
+	dev_info(dev, "STM32 HDP version %d.%d initialized\n",
+		 version >> 4, version & 0x0F);
+
+	return 0;
+}
+
+static int stm32_hdp_remove(struct platform_device *pdev)
+{
+	struct data_priv *data = platform_get_drvdata(pdev);
+
+	/* Disable HDP */
+	writel(HDP_CTRL_DISABLE, data->hdp_membase + HDP_CTRL);
+
+	if (data->clk) {
+		if (data->clk_is_enabled)
+			clk_disable_unprepare(data->clk);
+	}
+
+	pr_info("driver STM32 HDP removed\n");
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int stm32_hdp_suspend(struct device *dev)
+{
+	struct data_priv *data = dev_get_drvdata(dev);
+
+	data->hdp_ctrl = readl_relaxed(data->hdp_membase + HDP_CTRL);
+	data->hdp_mux = readl_relaxed(data->hdp_membase + HDP_MUX);
+
+	pinctrl_pm_select_sleep_state(dev);
+
+	return 0;
+}
+
+static int stm32_hdp_resume(struct device *dev)
+{
+	struct data_priv *data = dev_get_drvdata(dev);
+
+	writel_relaxed(data->hdp_ctrl, data->hdp_membase + HDP_CTRL);
+	writel_relaxed(data->hdp_mux, data->hdp_membase + HDP_MUX);
+
+	pinctrl_pm_select_default_state(dev);
+
+	return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static SIMPLE_DEV_PM_OPS(stm32_hdp_pm_ops,
+			 stm32_hdp_suspend,
+			 stm32_hdp_resume);
+
+static const struct of_device_id hdp_match[] = {
+	{	.compatible = "st,stm32mp1-hdp",},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, hdp_match);
+
+static struct platform_driver hdp_driver = {
+	.probe = stm32_hdp_probe,
+	.remove = stm32_hdp_remove,
+	.driver = {
+		.name = "hdp",
+		.of_match_table = hdp_match,
+		.pm = &stm32_hdp_pm_ops,
+	},
+};
+
+module_platform_driver(hdp_driver);
diff --git a/drivers/soc/st/stm32_pm_domain.c b/drivers/soc/st/stm32_pm_domain.c
new file mode 100644
index 000000000000..0386624c20f2
--- /dev/null
+++ b/drivers/soc/st/stm32_pm_domain.c
@@ -0,0 +1,212 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
+ * Author: Olivier Bideau <olivier.bideau@st.com> for STMicroelectronics.
+ */
+
+#include <linux/arm-smccc.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/pm_domain.h>
+#include <linux/printk.h>
+#include <linux/slab.h>
+
+#define SMC(domain, state)				\
+{							\
+	struct arm_smccc_res res;			\
+	arm_smccc_smc(0x82001008, domain, state, 0,	\
+		      0, 0, 0, 0, &res);		\
+}
+
+#define STM32_SMC_PD_DOMAIN_ON	0
+#define STM32_SMC_PD_DOMAIN_OFF	1
+
+struct stm32_pm_domain {
+	struct device *dev;
+	struct generic_pm_domain genpd;
+	int id;
+};
+
+static int stm32_pd_power_off(struct generic_pm_domain *domain)
+{
+	struct stm32_pm_domain *priv = container_of(domain,
+						    struct stm32_pm_domain,
+						    genpd);
+
+	SMC(priv->id, STM32_SMC_PD_DOMAIN_OFF);
+
+	dev_dbg(priv->dev, "%s OFF\n", domain->name);
+
+	return 0;
+}
+
+static int stm32_pd_power_on(struct generic_pm_domain *domain)
+{
+	struct stm32_pm_domain *priv = container_of(domain,
+						    struct stm32_pm_domain,
+						    genpd);
+
+	SMC(priv->id, STM32_SMC_PD_DOMAIN_ON);
+
+	dev_dbg(priv->dev, "%s ON\n", domain->name);
+
+	return 0;
+}
+
+static void stm32_pm_domain_remove(struct stm32_pm_domain *domain)
+{
+	int ret;
+
+	ret = pm_genpd_remove(&domain->genpd);
+	if (ret)
+		dev_err(domain->dev, "failed to remove PM domain %s: %d\n",
+			domain->genpd.name, ret);
+}
+
+static int stm32_pm_domain_add(struct stm32_pm_domain *domain,
+			       struct device *dev,
+			       struct device_node *np)
+{
+	int ret;
+
+	domain->dev = dev;
+	domain->genpd.name = np->name;
+	domain->genpd.power_off = stm32_pd_power_off;
+	domain->genpd.power_on = stm32_pd_power_on;
+	domain->genpd.flags |= GENPD_FLAG_ACTIVE_WAKEUP;
+
+	ret = of_property_read_u32(np, "reg", &domain->id);
+	if (ret) {
+		dev_err(domain->dev, "no domain ID\n");
+		return ret;
+	}
+
+	ret = pm_genpd_init(&domain->genpd, NULL, 0);
+	if (ret < 0) {
+		dev_err(domain->dev, "failed to initialise PM domain %s: %d\n",
+			np->name, ret);
+		return ret;
+	}
+
+	ret = of_genpd_add_provider_simple(np, &domain->genpd);
+	if (ret < 0) {
+		dev_err(domain->dev, "failed to register PM domain %s: %d\n",
+			np->name, ret);
+		stm32_pm_domain_remove(domain);
+		return ret;
+	}
+
+	dev_info(domain->dev, "domain %s registered\n", np->name);
+
+	return 0;
+}
+
+static void stm32_pm_subdomain_add(struct stm32_pm_domain *domain,
+				   struct device *dev,
+				   struct device_node *np)
+{
+	struct device_node *np_child;
+	int ret;
+
+	for_each_child_of_node(np, np_child) {
+		struct stm32_pm_domain *sub_domain;
+
+		sub_domain = devm_kzalloc(dev, sizeof(*sub_domain), GFP_KERNEL);
+		if (!sub_domain)
+			continue;
+
+		sub_domain->dev = dev;
+		sub_domain->genpd.name = np_child->name;
+		sub_domain->genpd.power_off = stm32_pd_power_off;
+		sub_domain->genpd.power_on = stm32_pd_power_on;
+		sub_domain->genpd.flags |= GENPD_FLAG_ACTIVE_WAKEUP;
+
+		ret = of_property_read_u32(np_child, "reg", &sub_domain->id);
+		if (ret) {
+			dev_err(sub_domain->dev, "no domain ID\n");
+			devm_kfree(dev, sub_domain);
+			continue;
+		}
+
+		ret = pm_genpd_init(&sub_domain->genpd, NULL, 0);
+		if (ret < 0) {
+			dev_err(sub_domain->dev, "failed to initialise PM domain %s: %d\n"
+				, np_child->name, ret);
+			devm_kfree(dev, sub_domain);
+			continue;
+		}
+
+		ret = of_genpd_add_provider_simple(np_child,
+						   &sub_domain->genpd);
+		if (ret < 0) {
+			dev_err(sub_domain->dev, "failed to register PM domain %s: %d\n"
+				, np_child->name, ret);
+			stm32_pm_domain_remove(sub_domain);
+			devm_kfree(dev, sub_domain);
+			continue;
+		}
+
+		ret = pm_genpd_add_subdomain(&domain->genpd,
+					     &sub_domain->genpd);
+
+		if (ret < 0) {
+			dev_err(sub_domain->dev, "failed to add Sub PM domain %s: %d\n"
+				, np_child->name, ret);
+			stm32_pm_domain_remove(sub_domain);
+			devm_kfree(dev, sub_domain);
+			continue;
+		}
+
+		dev_info(sub_domain->dev, "subdomain %s registered\n",
+			 np_child->name);
+	}
+}
+
+static int stm32_pm_domain_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node, *child_np;
+	int ret;
+
+	for_each_child_of_node(np, child_np) {
+		struct stm32_pm_domain *domain;
+
+		domain = devm_kzalloc(dev, sizeof(*domain), GFP_KERNEL);
+		if (!domain)
+			continue;
+
+		ret = stm32_pm_domain_add(domain, dev, child_np);
+		if (ret) {
+			devm_kfree(dev, domain);
+			continue;
+		}
+
+		stm32_pm_subdomain_add(domain, dev, child_np);
+	}
+
+	dev_info(dev, "domains probed\n");
+
+	return 0;
+}
+
+static const struct of_device_id stm32_pm_domain_matches[] = {
+	{ .compatible = "st,stm32mp157c-pd", },
+	{ },
+};
+
+static struct platform_driver stm32_pm_domains_driver = {
+	.probe = stm32_pm_domain_probe,
+	.driver = {
+		.name   = "stm32-pm-domain",
+		.of_match_table = stm32_pm_domain_matches,
+	},
+};
+
+static int __init stm32_pm_domains_init(void)
+{
+	return platform_driver_register(&stm32_pm_domains_driver);
+}
+core_initcall(stm32_pm_domains_init);
diff --git a/drivers/thermal/st/stm_thermal.c b/drivers/thermal/st/stm_thermal.c
index 5fd3fb8912a6..1e065a3323f9 100644
--- a/drivers/thermal/st/stm_thermal.c
+++ b/drivers/thermal/st/stm_thermal.c
@@ -82,8 +82,7 @@
 #define ONE_MHZ			1000000
 #define POLL_TIMEOUT		5000
 #define STARTUP_TIME		40
-#define TS1_T0_VAL0		30000  /* 30 celsius */
-#define TS1_T0_VAL1		130000 /* 130 celsius */
+#define T0			30000  /* 30 celsius */
 #define NO_HW_TRIG		0
 #define SAMPLING_TIME		15
 
@@ -96,7 +95,7 @@ struct stm_thermal_sensor {
 	unsigned int high_temp_enabled;
 	int irq;
 	void __iomem *base;
-	int t0, fmt0, ramp_coeff;
+	int fmt0, ramp_coeff;
 };
 
 static int stm_enable_irq(struct stm_thermal_sensor *sensor)
@@ -243,14 +242,6 @@ static int stm_thermal_calibration(struct stm_thermal_sensor *sensor)
 /* Fill in DTS structure with factory sensor values */
 static int stm_thermal_read_factory_settings(struct stm_thermal_sensor *sensor)
 {
-	/* Retrieve engineering calibration temperature */
-	sensor->t0 = readl_relaxed(sensor->base + DTS_T0VALR1_OFFSET) &
-					TS1_T0_MASK;
-	if (!sensor->t0)
-		sensor->t0 = TS1_T0_VAL0;
-	else
-		sensor->t0 = TS1_T0_VAL1;
-
 	/* Retrieve fmt0 and put it on Hz */
 	sensor->fmt0 = ADJUST * (readl_relaxed(sensor->base +
 				 DTS_T0VALR1_OFFSET) & TS1_FMT0_MASK);
@@ -264,8 +255,8 @@ static int stm_thermal_read_factory_settings(struct stm_thermal_sensor *sensor)
 		return -EINVAL;
 	}
 
-	dev_dbg(sensor->dev, "%s: T0 = %doC, FMT0 = %dHz, RAMP_COEFF = %dHz/oC",
-		__func__, sensor->t0, sensor->fmt0, sensor->ramp_coeff);
+	dev_dbg(sensor->dev, "%s: FMT0 = %dHz, RAMP_COEFF = %dHz/oC",
+		__func__, sensor->fmt0, sensor->ramp_coeff);
 
 	return 0;
 }
@@ -276,8 +267,7 @@ static int stm_thermal_calculate_threshold(struct stm_thermal_sensor *sensor,
 	int freqM;
 
 	/* Figure out the CLK_PTAT frequency for a given temperature */
-	freqM = ((temp - sensor->t0) * sensor->ramp_coeff) / 1000 +
-		sensor->fmt0;
+	freqM = ((temp - T0) * sensor->ramp_coeff) / 1000 + sensor->fmt0;
 
 	/* Figure out the threshold sample number */
 	*th = clk_get_rate(sensor->clk) * SAMPLING_TIME / freqM;
@@ -372,7 +362,7 @@ static int stm_thermal_get_temp(void *data, int *temp)
 		return -EINVAL;
 
 	/* Figure out the temperature in mili celsius */
-	*temp = (freqM - sensor->fmt0) * 1000 / sensor->ramp_coeff + sensor->t0;
+	*temp = (freqM - sensor->fmt0) * 1000 / sensor->ramp_coeff + T0;
 
 	return 0;
 }
@@ -515,11 +505,9 @@ static int stm_thermal_probe(struct platform_device *pdev)
 	sensor->base = base;
 
 	sensor->clk = devm_clk_get(&pdev->dev, "pclk");
-	if (IS_ERR(sensor->clk)) {
-		dev_err(&pdev->dev, "%s: failed to fetch PCLK clock\n",
-			__func__);
-		return PTR_ERR(sensor->clk);
-	}
+	if (IS_ERR(sensor->clk))
+		return dev_err_probe(&pdev->dev, PTR_ERR(sensor->clk),
+				     "Failed to get PCLK clock\n");
 
 	stm_disable_irq(sensor);
 
diff --git a/include/dt-bindings/soc/stm32-hdp.h b/include/dt-bindings/soc/stm32-hdp.h
new file mode 100644
index 000000000000..d98665327281
--- /dev/null
+++ b/include/dt-bindings/soc/stm32-hdp.h
@@ -0,0 +1,108 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+/*
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
+ * Author: Roullier Christophe <christophe.roullier@st.com>
+ * for STMicroelectronics.
+ */
+
+#ifndef _DT_BINDINGS_STM32_HDP_H
+#define _DT_BINDINGS_STM32_HDP_H
+
+#define STM32_HDP(port, value) ((value) << ((port) * 4))
+
+/* define HDP Pins number*/
+#define HDP0_PWR_PWRWAKE_SYS			0
+#define HDP0_CM4_SLEEPDEEP			1
+#define HDP0_PWR_STDBY_WKUP			2
+#define HDP0_PWR_ENCOMP_VDDCORE			3
+#define HDP0_BSEC_OUT_SEC_NIDEN			4
+#define HDP0_RCC_CM4_SLEEPDEEP			6
+#define HDP0_GPU_DBG7				7
+#define HDP0_DDRCTRL_LP_REQ			8
+#define HDP0_PWR_DDR_RET_ENABLE_N		9
+#define HDP0_GPOVAL_0				15
+
+#define HDP1_PWR_PWRWAKE_MCU			0
+#define HDP1_CM4_HALTED				1
+#define HDP1_CA7_NAXIERRIRQ			2
+#define HDP1_PWR_OKIN_MR			3
+#define HDP1_BSEC_OUT_SEC_DBGEN			4
+#define HDP1_EXTI_SYS_WAKEUP			5
+#define HDP1_RCC_PWRDS_MPU			6
+#define HDP1_GPU_DBG6				7
+#define HDP1_DDRCTRL_DFI_CTRLUPD_REQ		8
+#define HDP1_DDRCTRL_CACTIVE_DDRC_ASR		9
+#define HDP1_GPOVAL_1				15
+
+#define HDP2_PWR_PWRWAKE_MPU			0
+#define HDP2_CM4_RXEV				1
+#define HDP2_CA7_NPMUIRQ1			2
+#define HDP2_CA7_NFIQOUT1			3
+#define HDP2_BSEC_IN_RSTCORE_N			4
+#define HDP2_EXTI_C2_WAKEUP			5
+#define HDP2_RCC_PWRDS_MCU			6
+#define HDP2_GPU_DBG5				7
+#define HDP2_DDRCTRL_DFI_INIT_COMPLETE		8
+#define HDP2_DDRCTRL_PERF_OP_IS_REFRESH		9
+#define HDP2_DDRCTRL_GSKP_DFI_LP_REQ		10
+#define HDP2_GPOVAL_2				15
+
+#define HDP3_PWR_SEL_VTH_VDD_CORE		0
+#define HDP3_CM4_TXEV				1
+#define HDP3_CA7_NPMUIRQ0			2
+#define HDP3_CA7_NFIQOUT0			3
+#define HDP3_BSEC_OUT_SEC_DFTLOCK		4
+#define HDP3_EXTI_C1_WAKEUP			5
+#define HDP3_RCC_PWRDS_SYS			6
+#define HDP3_GPU_DBG4				7
+#define HDP3_DDRCTRL_STAT_DDRC_REG_SELREF_TYPE0	8
+#define HDP3_DDRCTRL_CACTIVE_1			9
+#define HDP3_GPOVAL_3				15
+
+#define HDP4_PWR_PDDS				0
+#define HDP4_CM4_SLEEPING			1
+#define HDP4_CA7_NRESET1			2
+#define HDP4_CA7_NIRQOUT1			3
+#define HDP4_BSEC_OUT_SEC_DFTEN			4
+#define HDP4_BSEC_OUT_SEC_DBGSWENABLE		5
+#define HDP4_ETH_OUT_PMT_INTR_O			6
+#define HDP4_GPU_DBG3				7
+#define HDP4_DDRCTRL_STAT_DDRC_REG_SELREF_TYPE1	8
+#define HDP4_DDRCTRL_CACTIVE_0			9
+#define HDP4_GPOVAL_4				15
+
+#define HDP5_CA7_STANDBYWFIL2			0
+#define HDP5_PWR_VTH_VDDCORE_ACK		1
+#define HDP5_CA7_NRESET0			2
+#define HDP5_CA7_NIRQOUT0			3
+#define HDP5_BSEC_IN_PWROK			4
+#define HDP5_BSEC_OUT_SEC_DEVICEEN		5
+#define HDP5_ETH_OUT_LPI_INTR_O			6
+#define HDP5_GPU_DBG2				7
+#define HDP5_DDRCTRL_CACTIVE_DDRC		8
+#define HDP5_DDRCTRL_WR_CREDIT_CNT		9
+#define HDP5_GPOVAL_5				15
+
+#define HDP6_CA7_STANDBYWFI1			0
+#define HDP6_CA7_STANDBYWFE1			1
+#define HDP6_CA7_EVENT0				2
+#define HDP6_CA7_DBGACK1			3
+#define HDP6_BSEC_OUT_SEC_SPNIDEN		5
+#define HDP6_ETH_OUT_MAC_SPEED_O1		6
+#define HDP6_GPU_DBG1				7
+#define HDP6_DDRCTRL_CSYSACK_DDRC		8
+#define HDP6_DDRCTRL_LPR_CREDIT_CNT		9
+#define HDP6_GPOVAL_6				15
+
+#define HDP7_CA7_STANDBYWFI0			0
+#define HDP7_CA7_STANDBYWFE0			1
+#define HDP7_CA7_DBGACK0			3
+#define HDP7_BSEC_OUT_FUSE_OK			4
+#define HDP7_BSEC_OUT_SEC_SPIDEN		5
+#define HDP7_ETH_OUT_MAC_SPEED_O0		6
+#define HDP7_GPU_DBG0				7
+#define HDP7_DDRCTRL_CSYSREQ_DDRC		8
+#define HDP7_DDRCTRL_HPR_CREDIT_CNT		9
+#define HDP7_GPOVAL_7				15
+
+#endif /* _DT_BINDINGS_STM32_HDP_H */
diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
index ed0840f3d5df..598822e23e9e 100644
--- a/include/media/v4l2-fwnode.h
+++ b/include/media/v4l2-fwnode.h
@@ -49,11 +49,13 @@ struct v4l2_fwnode_bus_mipi_csi2 {
  * @flags: media bus (V4L2_MBUS_*) flags
  * @bus_width: bus width in bits
  * @data_shift: data shift in bits
+ * @max_pclk_frequency: maximum pixel clock in hertz
  */
 struct v4l2_fwnode_bus_parallel {
 	unsigned int flags;
 	unsigned char bus_width;
 	unsigned char data_shift;
+	unsigned int pclk_max_frequency;
 };
 
 /**
-- 
2.17.1

