From 75eede33771d5a5da7fcccae80f2b2682b4897b3 Mon Sep 17 00:00:00 2001 From: Lionel Vitte Date: Thu, 14 Oct 2021 16:51:46 +0200 Subject: [PATCH 10/23] ARM 5.10.61-stm32mp1-r2 MEDIA-SOC-THERMAL --- drivers/media/i2c/ov5640.c | 111 +++++++--- drivers/media/platform/stm32/stm32-dcmi.c | 173 +++++++++++++--- 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 + 12 files changed, 824 insertions(+), 78 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/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index 8f0812e85..d7d36ad86 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 fd1c41cba..af7fe3e37 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 @@ -120,7 +123,7 @@ struct dcmi_framesize { struct dcmi_buf { struct vb2_v4l2_buffer vb; bool prepared; - dma_addr_t paddr; + struct sg_table sgt; size_t size; struct list_head list; }; @@ -157,11 +160,13 @@ 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; struct dma_chan *dma_chan; dma_cookie_t dma_cookie; + u32 dma_max_burst; u32 misr; int errors_count; int overrun_count; @@ -324,20 +329,19 @@ 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 */ mutex_lock(&dcmi->dma_lock); /* Prepare a DMA transaction */ - desc = dmaengine_prep_slave_single(dcmi->dma_chan, buf->paddr, - buf->size, + desc = dmaengine_prep_slave_sg(dcmi->dma_chan, buf->sgt.sgl, + buf->sgt.nents, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT); if (!desc) { - dev_err(dcmi->dev, "%s: DMA dmaengine_prep_slave_single failed for buffer phy=%pad size=%zu\n", - __func__, &buf->paddr, buf->size); + dev_err(dcmi->dev, "%s: DMA dmaengine_prep_slave_sg failed\n", __func__); mutex_unlock(&dcmi->dma_lock); return -EINVAL; } @@ -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)) @@ -529,6 +533,10 @@ static int dcmi_buf_prepare(struct vb2_buffer *vb) struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct dcmi_buf *buf = container_of(vbuf, struct dcmi_buf, vb); unsigned long size; + unsigned int num_sgs; + dma_addr_t dma_buf; + struct scatterlist *sg; + int i, ret; size = dcmi->fmt.fmt.pix.sizeimage; @@ -542,15 +550,35 @@ static int dcmi_buf_prepare(struct vb2_buffer *vb) if (!buf->prepared) { /* Get memory addresses */ - buf->paddr = - vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); buf->size = vb2_plane_size(&buf->vb.vb2_buf, 0); - buf->prepared = true; + if (buf->size <= dcmi->dma_max_burst) + num_sgs = 1; + else + num_sgs = DIV_ROUND_UP(buf->size, dcmi->dma_max_burst); + + ret = sg_alloc_table(&buf->sgt, num_sgs, GFP_ATOMIC); + if (ret) { + dev_err(dcmi->dev, "sg table alloc failed\n"); + return ret; + } - vb2_set_plane_payload(&buf->vb.vb2_buf, 0, buf->size); + dma_buf = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); dev_dbg(dcmi->dev, "buffer[%d] phy=%pad size=%zu\n", - vb->index, &buf->paddr, buf->size); + vb->index, &dma_buf, buf->size); + + for_each_sg(buf->sgt.sgl, sg, num_sgs, i) { + size_t bytes = min_t(size_t, size, dcmi->dma_max_burst); + + sg_dma_address(sg) = dma_buf; + sg_dma_len(sg) = bytes; + dma_buf += bytes; + size -= bytes; + } + + buf->prepared = true; + + vb2_set_plane_payload(&buf->vb.vb2_buf, 0, buf->size); } return 0; @@ -777,6 +805,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 +829,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 +950,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 +1135,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 +1643,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 +1677,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 +1835,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 +1856,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); @@ -1835,6 +1935,7 @@ static int dcmi_probe(struct platform_device *pdev) struct stm32_dcmi *dcmi; struct vb2_queue *q; struct dma_chan *chan; + struct dma_slave_caps caps; struct clk *mclk; int irq; int ret = 0; @@ -1851,7 +1952,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 +1976,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) @@ -1917,6 +2029,12 @@ static int dcmi_probe(struct platform_device *pdev) return ret; } + dcmi->dma_max_burst = UINT_MAX; + ret = dma_get_slave_caps(chan, &caps); + if (!ret && caps.max_sg_burst) + dcmi->dma_max_burst = caps.max_sg_burst * + DMA_SLAVE_BUSWIDTH_4_BYTES; + spin_lock_init(&dcmi->irqlock); mutex_init(&dcmi->lock); mutex_init(&dcmi->dma_lock); @@ -1972,15 +2090,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 +2110,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 +2136,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 +2161,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 dfc53d110..7d0e2f5d1 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 425ab6f7e..30afdfbfd 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 36452bed8..6b957db9a 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 000000000..8ab604999 --- /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 000000000..85905b768 --- /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 000000000..47687ebd1 --- /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 + * for STMicroelectronics. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 000000000..0386624c2 --- /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 for STMicroelectronics. + * Author: Olivier Bideau for STMicroelectronics. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#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 5fd3fb891..1e065a332 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 000000000..d98665327 --- /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 + * 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 ed0840f3d..598822e23 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