18082e2f4SPaul Elder // SPDX-License-Identifier: (GPL-2.0+ OR MIT)
28082e2f4SPaul Elder /*
38082e2f4SPaul Elder * Rockchip ISP1 Driver - CSI-2 Receiver
48082e2f4SPaul Elder *
58082e2f4SPaul Elder * Copyright (C) 2019 Collabora, Ltd.
68082e2f4SPaul Elder * Copyright (C) 2022 Ideas on Board
78082e2f4SPaul Elder *
88082e2f4SPaul Elder * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd.
98082e2f4SPaul Elder * Copyright (C) 2017 Rockchip Electronics Co., Ltd.
108082e2f4SPaul Elder */
118082e2f4SPaul Elder
12a81138afSLaurent Pinchart #include <linux/delay.h>
138082e2f4SPaul Elder #include <linux/device.h>
14b298f059SPaul Elder #include <linux/lockdep.h>
158082e2f4SPaul Elder #include <linux/phy/phy.h>
168082e2f4SPaul Elder #include <linux/phy/phy-mipi-dphy.h>
178082e2f4SPaul Elder
188082e2f4SPaul Elder #include <media/v4l2-ctrls.h>
19b298f059SPaul Elder #include <media/v4l2-fwnode.h>
208082e2f4SPaul Elder
218082e2f4SPaul Elder #include "rkisp1-common.h"
228082e2f4SPaul Elder #include "rkisp1-csi.h"
238082e2f4SPaul Elder
24b298f059SPaul Elder #define RKISP1_CSI_DEV_NAME RKISP1_DRIVER_NAME "_csi"
25b298f059SPaul Elder
26b298f059SPaul Elder #define RKISP1_CSI_DEF_FMT MEDIA_BUS_FMT_SRGGB10_1X10
27b298f059SPaul Elder
to_rkisp1_csi(struct v4l2_subdev * sd)28b298f059SPaul Elder static inline struct rkisp1_csi *to_rkisp1_csi(struct v4l2_subdev *sd)
29b298f059SPaul Elder {
30b298f059SPaul Elder return container_of(sd, struct rkisp1_csi, sd);
31b298f059SPaul Elder }
32b298f059SPaul Elder
rkisp1_csi_link_sensor(struct rkisp1_device * rkisp1,struct v4l2_subdev * sd,struct rkisp1_sensor_async * s_asd,unsigned int source_pad)3398bfd0cdSLaurent Pinchart int rkisp1_csi_link_sensor(struct rkisp1_device *rkisp1, struct v4l2_subdev *sd,
3498bfd0cdSLaurent Pinchart struct rkisp1_sensor_async *s_asd,
3598bfd0cdSLaurent Pinchart unsigned int source_pad)
3698bfd0cdSLaurent Pinchart {
3798bfd0cdSLaurent Pinchart struct rkisp1_csi *csi = &rkisp1->csi;
3898bfd0cdSLaurent Pinchart int ret;
3998bfd0cdSLaurent Pinchart
4098bfd0cdSLaurent Pinchart s_asd->pixel_rate_ctrl = v4l2_ctrl_find(sd->ctrl_handler,
4198bfd0cdSLaurent Pinchart V4L2_CID_PIXEL_RATE);
4298bfd0cdSLaurent Pinchart if (!s_asd->pixel_rate_ctrl) {
4398bfd0cdSLaurent Pinchart dev_err(rkisp1->dev, "No pixel rate control in subdev %s\n",
4498bfd0cdSLaurent Pinchart sd->name);
4598bfd0cdSLaurent Pinchart return -EINVAL;
4698bfd0cdSLaurent Pinchart }
4798bfd0cdSLaurent Pinchart
4898bfd0cdSLaurent Pinchart /* Create the link from the sensor to the CSI receiver. */
4998bfd0cdSLaurent Pinchart ret = media_create_pad_link(&sd->entity, source_pad,
5098bfd0cdSLaurent Pinchart &csi->sd.entity, RKISP1_CSI_PAD_SINK,
5198bfd0cdSLaurent Pinchart !s_asd->index ? MEDIA_LNK_FL_ENABLED : 0);
5298bfd0cdSLaurent Pinchart if (ret) {
5398bfd0cdSLaurent Pinchart dev_err(csi->rkisp1->dev, "failed to link src pad of %s\n",
5498bfd0cdSLaurent Pinchart sd->name);
5598bfd0cdSLaurent Pinchart return ret;
5698bfd0cdSLaurent Pinchart }
5798bfd0cdSLaurent Pinchart
5898bfd0cdSLaurent Pinchart return 0;
5998bfd0cdSLaurent Pinchart }
6098bfd0cdSLaurent Pinchart
rkisp1_csi_config(struct rkisp1_csi * csi,const struct rkisp1_sensor_async * sensor,const struct rkisp1_mbus_info * format)61c5045943SLaurent Pinchart static int rkisp1_csi_config(struct rkisp1_csi *csi,
62c7e26218SLaurent Pinchart const struct rkisp1_sensor_async *sensor,
63c7e26218SLaurent Pinchart const struct rkisp1_mbus_info *format)
648082e2f4SPaul Elder {
658082e2f4SPaul Elder struct rkisp1_device *rkisp1 = csi->rkisp1;
66c5045943SLaurent Pinchart unsigned int lanes = sensor->lanes;
678082e2f4SPaul Elder u32 mipi_ctrl;
688082e2f4SPaul Elder
698082e2f4SPaul Elder if (lanes < 1 || lanes > 4)
708082e2f4SPaul Elder return -EINVAL;
718082e2f4SPaul Elder
728082e2f4SPaul Elder mipi_ctrl = RKISP1_CIF_MIPI_CTRL_NUM_LANES(lanes - 1) |
738082e2f4SPaul Elder RKISP1_CIF_MIPI_CTRL_SHUTDOWNLANES(0xf) |
748082e2f4SPaul Elder RKISP1_CIF_MIPI_CTRL_ERR_SOT_SYNC_HS_SKIP |
758082e2f4SPaul Elder RKISP1_CIF_MIPI_CTRL_CLOCKLANE_ENA;
768082e2f4SPaul Elder
778082e2f4SPaul Elder rkisp1_write(rkisp1, RKISP1_CIF_MIPI_CTRL, mipi_ctrl);
788082e2f4SPaul Elder
798082e2f4SPaul Elder /* V12 could also use a newer csi2-host, but we don't want that yet */
808082e2f4SPaul Elder if (rkisp1->info->isp_ver == RKISP1_V12)
818082e2f4SPaul Elder rkisp1_write(rkisp1, RKISP1_CIF_ISP_CSI0_CTRL0, 0);
828082e2f4SPaul Elder
838082e2f4SPaul Elder /* Configure Data Type and Virtual Channel */
848082e2f4SPaul Elder rkisp1_write(rkisp1, RKISP1_CIF_MIPI_IMG_DATA_SEL,
85c7e26218SLaurent Pinchart RKISP1_CIF_MIPI_DATA_SEL_DT(format->mipi_dt) |
868082e2f4SPaul Elder RKISP1_CIF_MIPI_DATA_SEL_VC(0));
878082e2f4SPaul Elder
888082e2f4SPaul Elder /* Clear MIPI interrupts */
898082e2f4SPaul Elder rkisp1_write(rkisp1, RKISP1_CIF_MIPI_ICR, ~0);
908082e2f4SPaul Elder
918082e2f4SPaul Elder /*
928082e2f4SPaul Elder * Disable RKISP1_CIF_MIPI_ERR_DPHY interrupt here temporary for
938082e2f4SPaul Elder * isp bus may be dead when switch isp.
948082e2f4SPaul Elder */
958082e2f4SPaul Elder rkisp1_write(rkisp1, RKISP1_CIF_MIPI_IMSC,
968082e2f4SPaul Elder RKISP1_CIF_MIPI_FRAME_END | RKISP1_CIF_MIPI_ERR_CSI |
978082e2f4SPaul Elder RKISP1_CIF_MIPI_ERR_DPHY |
988082e2f4SPaul Elder RKISP1_CIF_MIPI_SYNC_FIFO_OVFLW(0x03) |
998082e2f4SPaul Elder RKISP1_CIF_MIPI_ADD_DATA_OVFLW);
1008082e2f4SPaul Elder
1018082e2f4SPaul Elder dev_dbg(rkisp1->dev, "\n MIPI_CTRL 0x%08x\n"
1028082e2f4SPaul Elder " MIPI_IMG_DATA_SEL 0x%08x\n"
1038082e2f4SPaul Elder " MIPI_STATUS 0x%08x\n"
1048082e2f4SPaul Elder " MIPI_IMSC 0x%08x\n",
1058082e2f4SPaul Elder rkisp1_read(rkisp1, RKISP1_CIF_MIPI_CTRL),
1068082e2f4SPaul Elder rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMG_DATA_SEL),
1078082e2f4SPaul Elder rkisp1_read(rkisp1, RKISP1_CIF_MIPI_STATUS),
1088082e2f4SPaul Elder rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC));
1098082e2f4SPaul Elder
1108082e2f4SPaul Elder return 0;
1118082e2f4SPaul Elder }
1128082e2f4SPaul Elder
rkisp1_csi_enable(struct rkisp1_csi * csi)1130c0b9f9cSLaurent Pinchart static void rkisp1_csi_enable(struct rkisp1_csi *csi)
114039a7342SLaurent Pinchart {
115039a7342SLaurent Pinchart struct rkisp1_device *rkisp1 = csi->rkisp1;
116039a7342SLaurent Pinchart u32 val;
117039a7342SLaurent Pinchart
118039a7342SLaurent Pinchart val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_CTRL);
119039a7342SLaurent Pinchart rkisp1_write(rkisp1, RKISP1_CIF_MIPI_CTRL,
120039a7342SLaurent Pinchart val | RKISP1_CIF_MIPI_CTRL_OUTPUT_ENA);
121039a7342SLaurent Pinchart }
122039a7342SLaurent Pinchart
rkisp1_csi_disable(struct rkisp1_csi * csi)1230c0b9f9cSLaurent Pinchart static void rkisp1_csi_disable(struct rkisp1_csi *csi)
124039a7342SLaurent Pinchart {
125039a7342SLaurent Pinchart struct rkisp1_device *rkisp1 = csi->rkisp1;
126039a7342SLaurent Pinchart u32 val;
127039a7342SLaurent Pinchart
128870565f0STomi Valkeinen /* Mask MIPI interrupts. */
129039a7342SLaurent Pinchart rkisp1_write(rkisp1, RKISP1_CIF_MIPI_IMSC, 0);
130870565f0STomi Valkeinen
131870565f0STomi Valkeinen /* Flush posted writes */
132870565f0STomi Valkeinen rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC);
133870565f0STomi Valkeinen
134870565f0STomi Valkeinen /*
135870565f0STomi Valkeinen * Wait until the IRQ handler has ended. The IRQ handler may get called
136870565f0STomi Valkeinen * even after this, but it will return immediately as the MIPI
137870565f0STomi Valkeinen * interrupts have been masked.
138870565f0STomi Valkeinen */
139870565f0STomi Valkeinen synchronize_irq(rkisp1->irqs[RKISP1_IRQ_MIPI]);
140870565f0STomi Valkeinen
141870565f0STomi Valkeinen /* Clear MIPI interrupt status */
142039a7342SLaurent Pinchart rkisp1_write(rkisp1, RKISP1_CIF_MIPI_ICR, ~0);
143039a7342SLaurent Pinchart
144039a7342SLaurent Pinchart val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_CTRL);
145039a7342SLaurent Pinchart rkisp1_write(rkisp1, RKISP1_CIF_MIPI_CTRL,
146039a7342SLaurent Pinchart val & (~RKISP1_CIF_MIPI_CTRL_OUTPUT_ENA));
147039a7342SLaurent Pinchart }
148039a7342SLaurent Pinchart
rkisp1_csi_start(struct rkisp1_csi * csi,const struct rkisp1_sensor_async * sensor,const struct rkisp1_mbus_info * format)14998bfd0cdSLaurent Pinchart static int rkisp1_csi_start(struct rkisp1_csi *csi,
150c7e26218SLaurent Pinchart const struct rkisp1_sensor_async *sensor,
151c7e26218SLaurent Pinchart const struct rkisp1_mbus_info *format)
1528082e2f4SPaul Elder {
1538082e2f4SPaul Elder struct rkisp1_device *rkisp1 = csi->rkisp1;
1548082e2f4SPaul Elder union phy_configure_opts opts;
1558082e2f4SPaul Elder struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
1568082e2f4SPaul Elder s64 pixel_clock;
157039a7342SLaurent Pinchart int ret;
158039a7342SLaurent Pinchart
159c7e26218SLaurent Pinchart ret = rkisp1_csi_config(csi, sensor, format);
160039a7342SLaurent Pinchart if (ret)
161039a7342SLaurent Pinchart return ret;
1628082e2f4SPaul Elder
1638082e2f4SPaul Elder pixel_clock = v4l2_ctrl_g_ctrl_int64(sensor->pixel_rate_ctrl);
1648082e2f4SPaul Elder if (!pixel_clock) {
1658082e2f4SPaul Elder dev_err(rkisp1->dev, "Invalid pixel rate value\n");
1668082e2f4SPaul Elder return -EINVAL;
1678082e2f4SPaul Elder }
1688082e2f4SPaul Elder
169c7e26218SLaurent Pinchart phy_mipi_dphy_get_default_config(pixel_clock, format->bus_width,
1708082e2f4SPaul Elder sensor->lanes, cfg);
1718082e2f4SPaul Elder phy_set_mode(csi->dphy, PHY_MODE_MIPI_DPHY);
1728082e2f4SPaul Elder phy_configure(csi->dphy, &opts);
1738082e2f4SPaul Elder phy_power_on(csi->dphy);
1748082e2f4SPaul Elder
1750c0b9f9cSLaurent Pinchart rkisp1_csi_enable(csi);
176039a7342SLaurent Pinchart
177a81138afSLaurent Pinchart /*
178a81138afSLaurent Pinchart * CIF spec says to wait for sufficient time after enabling
179a81138afSLaurent Pinchart * the MIPI interface and before starting the sensor output.
180a81138afSLaurent Pinchart */
181a81138afSLaurent Pinchart usleep_range(1000, 1200);
182a81138afSLaurent Pinchart
1838082e2f4SPaul Elder return 0;
1848082e2f4SPaul Elder }
1858082e2f4SPaul Elder
rkisp1_csi_stop(struct rkisp1_csi * csi)18698bfd0cdSLaurent Pinchart static void rkisp1_csi_stop(struct rkisp1_csi *csi)
1878082e2f4SPaul Elder {
1880c0b9f9cSLaurent Pinchart rkisp1_csi_disable(csi);
189039a7342SLaurent Pinchart
1908082e2f4SPaul Elder phy_power_off(csi->dphy);
1918082e2f4SPaul Elder }
1928082e2f4SPaul Elder
rkisp1_csi_isr(int irq,void * ctx)1930c0b9f9cSLaurent Pinchart irqreturn_t rkisp1_csi_isr(int irq, void *ctx)
1948082e2f4SPaul Elder {
1958082e2f4SPaul Elder struct device *dev = ctx;
1968082e2f4SPaul Elder struct rkisp1_device *rkisp1 = dev_get_drvdata(dev);
1978082e2f4SPaul Elder u32 val, status;
1988082e2f4SPaul Elder
199ffb635bbSTomi Valkeinen if (!rkisp1->irqs_enabled)
200ffb635bbSTomi Valkeinen return IRQ_NONE;
201ffb635bbSTomi Valkeinen
2028082e2f4SPaul Elder status = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_MIS);
2038082e2f4SPaul Elder if (!status)
2048082e2f4SPaul Elder return IRQ_NONE;
2058082e2f4SPaul Elder
2068082e2f4SPaul Elder rkisp1_write(rkisp1, RKISP1_CIF_MIPI_ICR, status);
2078082e2f4SPaul Elder
2088082e2f4SPaul Elder /*
2098082e2f4SPaul Elder * Disable DPHY errctrl interrupt, because this dphy
2108082e2f4SPaul Elder * erctrl signal is asserted until the next changes
2118082e2f4SPaul Elder * of line state. This time is may be too long and cpu
2128082e2f4SPaul Elder * is hold in this interrupt.
2138082e2f4SPaul Elder */
2148082e2f4SPaul Elder if (status & RKISP1_CIF_MIPI_ERR_CTRL(0x0f)) {
2158082e2f4SPaul Elder val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC);
2168082e2f4SPaul Elder rkisp1_write(rkisp1, RKISP1_CIF_MIPI_IMSC,
2178082e2f4SPaul Elder val & ~RKISP1_CIF_MIPI_ERR_CTRL(0x0f));
2188082e2f4SPaul Elder rkisp1->csi.is_dphy_errctrl_disabled = true;
2198082e2f4SPaul Elder }
2208082e2f4SPaul Elder
2218082e2f4SPaul Elder /*
2228082e2f4SPaul Elder * Enable DPHY errctrl interrupt again, if mipi have receive
2238082e2f4SPaul Elder * the whole frame without any error.
2248082e2f4SPaul Elder */
2258082e2f4SPaul Elder if (status == RKISP1_CIF_MIPI_FRAME_END) {
2268082e2f4SPaul Elder /*
2278082e2f4SPaul Elder * Enable DPHY errctrl interrupt again, if mipi have receive
2288082e2f4SPaul Elder * the whole frame without any error.
2298082e2f4SPaul Elder */
2308082e2f4SPaul Elder if (rkisp1->csi.is_dphy_errctrl_disabled) {
2318082e2f4SPaul Elder val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC);
2328082e2f4SPaul Elder val |= RKISP1_CIF_MIPI_ERR_CTRL(0x0f);
2338082e2f4SPaul Elder rkisp1_write(rkisp1, RKISP1_CIF_MIPI_IMSC, val);
2348082e2f4SPaul Elder rkisp1->csi.is_dphy_errctrl_disabled = false;
2358082e2f4SPaul Elder }
2368082e2f4SPaul Elder } else {
2378082e2f4SPaul Elder rkisp1->debug.mipi_error++;
2388082e2f4SPaul Elder }
2398082e2f4SPaul Elder
2408082e2f4SPaul Elder return IRQ_HANDLED;
2418082e2f4SPaul Elder }
2428082e2f4SPaul Elder
243b298f059SPaul Elder /* ----------------------------------------------------------------------------
244b298f059SPaul Elder * Subdev pad operations
245b298f059SPaul Elder */
246b298f059SPaul Elder
rkisp1_csi_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_mbus_code_enum * code)247b298f059SPaul Elder static int rkisp1_csi_enum_mbus_code(struct v4l2_subdev *sd,
248b298f059SPaul Elder struct v4l2_subdev_state *sd_state,
249b298f059SPaul Elder struct v4l2_subdev_mbus_code_enum *code)
250b298f059SPaul Elder {
251b298f059SPaul Elder unsigned int i;
252b298f059SPaul Elder int pos = 0;
253b298f059SPaul Elder
254b298f059SPaul Elder if (code->pad == RKISP1_CSI_PAD_SRC) {
255b298f059SPaul Elder const struct v4l2_mbus_framefmt *sink_fmt;
256b298f059SPaul Elder
257b298f059SPaul Elder if (code->index)
258b298f059SPaul Elder return -EINVAL;
259b298f059SPaul Elder
260bc0e8d91SSakari Ailus sink_fmt = v4l2_subdev_state_get_format(sd_state,
261c7e26218SLaurent Pinchart RKISP1_CSI_PAD_SINK);
262b298f059SPaul Elder code->code = sink_fmt->code;
263b298f059SPaul Elder
264b298f059SPaul Elder return 0;
265b298f059SPaul Elder }
266b298f059SPaul Elder
267b298f059SPaul Elder for (i = 0; ; i++) {
268b298f059SPaul Elder const struct rkisp1_mbus_info *fmt =
269b298f059SPaul Elder rkisp1_mbus_info_get_by_index(i);
270b298f059SPaul Elder
271b298f059SPaul Elder if (!fmt)
272b298f059SPaul Elder return -EINVAL;
273b298f059SPaul Elder
274b298f059SPaul Elder if (!(fmt->direction & RKISP1_ISP_SD_SINK))
275b298f059SPaul Elder continue;
276b298f059SPaul Elder
277b298f059SPaul Elder if (code->index == pos) {
278b298f059SPaul Elder code->code = fmt->mbus_code;
279b298f059SPaul Elder return 0;
280b298f059SPaul Elder }
281b298f059SPaul Elder
282b298f059SPaul Elder pos++;
283b298f059SPaul Elder }
284b298f059SPaul Elder
285b298f059SPaul Elder return -EINVAL;
286b298f059SPaul Elder }
287b298f059SPaul Elder
rkisp1_csi_init_state(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state)2885755be5fSLaurent Pinchart static int rkisp1_csi_init_state(struct v4l2_subdev *sd,
289b298f059SPaul Elder struct v4l2_subdev_state *sd_state)
290b298f059SPaul Elder {
291b298f059SPaul Elder struct v4l2_mbus_framefmt *sink_fmt, *src_fmt;
292b298f059SPaul Elder
293bc0e8d91SSakari Ailus sink_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_CSI_PAD_SINK);
294bc0e8d91SSakari Ailus src_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_CSI_PAD_SRC);
295b298f059SPaul Elder
296b298f059SPaul Elder sink_fmt->width = RKISP1_DEFAULT_WIDTH;
297b298f059SPaul Elder sink_fmt->height = RKISP1_DEFAULT_HEIGHT;
298b298f059SPaul Elder sink_fmt->field = V4L2_FIELD_NONE;
299b298f059SPaul Elder sink_fmt->code = RKISP1_CSI_DEF_FMT;
300b298f059SPaul Elder
301b298f059SPaul Elder *src_fmt = *sink_fmt;
302b298f059SPaul Elder
303b298f059SPaul Elder return 0;
304b298f059SPaul Elder }
305b298f059SPaul Elder
rkisp1_csi_set_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)306b298f059SPaul Elder static int rkisp1_csi_set_fmt(struct v4l2_subdev *sd,
307b298f059SPaul Elder struct v4l2_subdev_state *sd_state,
308b298f059SPaul Elder struct v4l2_subdev_format *fmt)
309b298f059SPaul Elder {
310983b32a2SOndrej Jirman struct rkisp1_csi *csi = to_rkisp1_csi(sd);
311b298f059SPaul Elder const struct rkisp1_mbus_info *mbus_info;
312b298f059SPaul Elder struct v4l2_mbus_framefmt *sink_fmt, *src_fmt;
313b298f059SPaul Elder
314b298f059SPaul Elder /* The format on the source pad always matches the sink pad. */
315b298f059SPaul Elder if (fmt->pad == RKISP1_CSI_PAD_SRC)
316c7e26218SLaurent Pinchart return v4l2_subdev_get_fmt(sd, sd_state, fmt);
317b298f059SPaul Elder
318bc0e8d91SSakari Ailus sink_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_CSI_PAD_SINK);
319b298f059SPaul Elder
320b298f059SPaul Elder sink_fmt->code = fmt->format.code;
321b298f059SPaul Elder
322b298f059SPaul Elder mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code);
323b298f059SPaul Elder if (!mbus_info || !(mbus_info->direction & RKISP1_ISP_SD_SINK)) {
324b298f059SPaul Elder sink_fmt->code = RKISP1_CSI_DEF_FMT;
325b298f059SPaul Elder mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code);
326b298f059SPaul Elder }
327b298f059SPaul Elder
328b298f059SPaul Elder sink_fmt->width = clamp_t(u32, fmt->format.width,
329b298f059SPaul Elder RKISP1_ISP_MIN_WIDTH,
330983b32a2SOndrej Jirman csi->rkisp1->info->max_width);
331b298f059SPaul Elder sink_fmt->height = clamp_t(u32, fmt->format.height,
332b298f059SPaul Elder RKISP1_ISP_MIN_HEIGHT,
333983b32a2SOndrej Jirman csi->rkisp1->info->max_height);
334b298f059SPaul Elder
335b298f059SPaul Elder fmt->format = *sink_fmt;
336b298f059SPaul Elder
337b298f059SPaul Elder /* Propagate the format to the source pad. */
338bc0e8d91SSakari Ailus src_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_CSI_PAD_SRC);
339b298f059SPaul Elder *src_fmt = *sink_fmt;
340b298f059SPaul Elder
341b298f059SPaul Elder return 0;
342b298f059SPaul Elder }
343b298f059SPaul Elder
344b298f059SPaul Elder /* ----------------------------------------------------------------------------
345b298f059SPaul Elder * Subdev video operations
346b298f059SPaul Elder */
347b298f059SPaul Elder
rkisp1_csi_s_stream(struct v4l2_subdev * sd,int enable)348b298f059SPaul Elder static int rkisp1_csi_s_stream(struct v4l2_subdev *sd, int enable)
349b298f059SPaul Elder {
350b298f059SPaul Elder struct rkisp1_csi *csi = to_rkisp1_csi(sd);
351b298f059SPaul Elder struct rkisp1_device *rkisp1 = csi->rkisp1;
352c7e26218SLaurent Pinchart const struct v4l2_mbus_framefmt *sink_fmt;
353c7e26218SLaurent Pinchart const struct rkisp1_mbus_info *format;
354b298f059SPaul Elder struct rkisp1_sensor_async *source_asd;
355c91fd7b7SSakari Ailus struct v4l2_async_connection *asc;
356c7e26218SLaurent Pinchart struct v4l2_subdev_state *sd_state;
357b298f059SPaul Elder struct media_pad *source_pad;
358b298f059SPaul Elder struct v4l2_subdev *source;
359b298f059SPaul Elder int ret;
360b298f059SPaul Elder
361b298f059SPaul Elder if (!enable) {
362b298f059SPaul Elder v4l2_subdev_call(csi->source, video, s_stream, false);
363b298f059SPaul Elder
364b298f059SPaul Elder rkisp1_csi_stop(csi);
365b298f059SPaul Elder
366b298f059SPaul Elder return 0;
367b298f059SPaul Elder }
368b298f059SPaul Elder
369b298f059SPaul Elder source_pad = media_entity_remote_source_pad_unique(&sd->entity);
370b298f059SPaul Elder if (IS_ERR(source_pad)) {
371b298f059SPaul Elder dev_dbg(rkisp1->dev, "Failed to get source for CSI: %ld\n",
372b298f059SPaul Elder PTR_ERR(source_pad));
373b298f059SPaul Elder return -EPIPE;
374b298f059SPaul Elder }
375b298f059SPaul Elder
376b298f059SPaul Elder source = media_entity_to_v4l2_subdev(source_pad->entity);
377b298f059SPaul Elder if (!source) {
378b298f059SPaul Elder /* This should really not happen, so is not worth a message. */
379b298f059SPaul Elder return -EPIPE;
380b298f059SPaul Elder }
381b298f059SPaul Elder
382c91fd7b7SSakari Ailus asc = v4l2_async_connection_unique(source);
383c91fd7b7SSakari Ailus if (!asc)
384c91fd7b7SSakari Ailus return -EPIPE;
385c91fd7b7SSakari Ailus
386c91fd7b7SSakari Ailus source_asd = container_of(asc, struct rkisp1_sensor_async, asd);
387b298f059SPaul Elder if (source_asd->mbus_type != V4L2_MBUS_CSI2_DPHY)
388b298f059SPaul Elder return -EINVAL;
389b298f059SPaul Elder
390c7e26218SLaurent Pinchart sd_state = v4l2_subdev_lock_and_get_active_state(sd);
391bc0e8d91SSakari Ailus sink_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_CSI_PAD_SINK);
392c7e26218SLaurent Pinchart format = rkisp1_mbus_info_get_by_code(sink_fmt->code);
393c7e26218SLaurent Pinchart v4l2_subdev_unlock_state(sd_state);
394c7e26218SLaurent Pinchart
395c7e26218SLaurent Pinchart ret = rkisp1_csi_start(csi, source_asd, format);
396b298f059SPaul Elder if (ret)
397b298f059SPaul Elder return ret;
398b298f059SPaul Elder
399b298f059SPaul Elder ret = v4l2_subdev_call(source, video, s_stream, true);
400b298f059SPaul Elder if (ret) {
401b298f059SPaul Elder rkisp1_csi_stop(csi);
402b298f059SPaul Elder return ret;
403b298f059SPaul Elder }
404b298f059SPaul Elder
405b298f059SPaul Elder csi->source = source;
406b298f059SPaul Elder
407b298f059SPaul Elder return 0;
408b298f059SPaul Elder }
409b298f059SPaul Elder
410b298f059SPaul Elder /* ----------------------------------------------------------------------------
411b298f059SPaul Elder * Registration
412b298f059SPaul Elder */
413b298f059SPaul Elder
414b298f059SPaul Elder static const struct media_entity_operations rkisp1_csi_media_ops = {
415b298f059SPaul Elder .link_validate = v4l2_subdev_link_validate,
416b298f059SPaul Elder };
417b298f059SPaul Elder
418b298f059SPaul Elder static const struct v4l2_subdev_video_ops rkisp1_csi_video_ops = {
419b298f059SPaul Elder .s_stream = rkisp1_csi_s_stream,
420b298f059SPaul Elder };
421b298f059SPaul Elder
422b298f059SPaul Elder static const struct v4l2_subdev_pad_ops rkisp1_csi_pad_ops = {
423b298f059SPaul Elder .enum_mbus_code = rkisp1_csi_enum_mbus_code,
424c7e26218SLaurent Pinchart .get_fmt = v4l2_subdev_get_fmt,
425b298f059SPaul Elder .set_fmt = rkisp1_csi_set_fmt,
426b298f059SPaul Elder };
427b298f059SPaul Elder
428b298f059SPaul Elder static const struct v4l2_subdev_ops rkisp1_csi_ops = {
429b298f059SPaul Elder .video = &rkisp1_csi_video_ops,
430b298f059SPaul Elder .pad = &rkisp1_csi_pad_ops,
431b298f059SPaul Elder };
432b298f059SPaul Elder
4335755be5fSLaurent Pinchart static const struct v4l2_subdev_internal_ops rkisp1_csi_internal_ops = {
4345755be5fSLaurent Pinchart .init_state = rkisp1_csi_init_state,
4355755be5fSLaurent Pinchart };
4365755be5fSLaurent Pinchart
rkisp1_csi_register(struct rkisp1_device * rkisp1)437b298f059SPaul Elder int rkisp1_csi_register(struct rkisp1_device *rkisp1)
438b298f059SPaul Elder {
439b298f059SPaul Elder struct rkisp1_csi *csi = &rkisp1->csi;
440b298f059SPaul Elder struct media_pad *pads;
441b298f059SPaul Elder struct v4l2_subdev *sd;
442b298f059SPaul Elder int ret;
443b298f059SPaul Elder
444b298f059SPaul Elder csi->rkisp1 = rkisp1;
445b298f059SPaul Elder
446b298f059SPaul Elder sd = &csi->sd;
447b298f059SPaul Elder v4l2_subdev_init(sd, &rkisp1_csi_ops);
4485755be5fSLaurent Pinchart sd->internal_ops = &rkisp1_csi_internal_ops;
449b298f059SPaul Elder sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
450b298f059SPaul Elder sd->entity.ops = &rkisp1_csi_media_ops;
451b298f059SPaul Elder sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
452b298f059SPaul Elder sd->owner = THIS_MODULE;
453b298f059SPaul Elder strscpy(sd->name, RKISP1_CSI_DEV_NAME, sizeof(sd->name));
454b298f059SPaul Elder
455b298f059SPaul Elder pads = csi->pads;
456b298f059SPaul Elder pads[RKISP1_CSI_PAD_SINK].flags = MEDIA_PAD_FL_SINK |
457b298f059SPaul Elder MEDIA_PAD_FL_MUST_CONNECT;
458b298f059SPaul Elder pads[RKISP1_CSI_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE |
459b298f059SPaul Elder MEDIA_PAD_FL_MUST_CONNECT;
460b298f059SPaul Elder
461b298f059SPaul Elder ret = media_entity_pads_init(&sd->entity, RKISP1_CSI_PAD_NUM, pads);
462b298f059SPaul Elder if (ret)
463c7e26218SLaurent Pinchart goto err_entity_cleanup;
464b298f059SPaul Elder
465c7e26218SLaurent Pinchart ret = v4l2_subdev_init_finalize(sd);
466c7e26218SLaurent Pinchart if (ret)
467c7e26218SLaurent Pinchart goto err_entity_cleanup;
468b298f059SPaul Elder
469b298f059SPaul Elder ret = v4l2_device_register_subdev(&csi->rkisp1->v4l2_dev, sd);
470b298f059SPaul Elder if (ret) {
471b298f059SPaul Elder dev_err(sd->dev, "Failed to register csi receiver subdev\n");
472c7e26218SLaurent Pinchart goto err_subdev_cleanup;
473b298f059SPaul Elder }
474b298f059SPaul Elder
475b298f059SPaul Elder return 0;
476b298f059SPaul Elder
477c7e26218SLaurent Pinchart err_subdev_cleanup:
478c7e26218SLaurent Pinchart v4l2_subdev_cleanup(sd);
479c7e26218SLaurent Pinchart err_entity_cleanup:
480b298f059SPaul Elder media_entity_cleanup(&sd->entity);
481b298f059SPaul Elder csi->rkisp1 = NULL;
482b298f059SPaul Elder return ret;
483b298f059SPaul Elder }
484b298f059SPaul Elder
rkisp1_csi_unregister(struct rkisp1_device * rkisp1)485b298f059SPaul Elder void rkisp1_csi_unregister(struct rkisp1_device *rkisp1)
486b298f059SPaul Elder {
487b298f059SPaul Elder struct rkisp1_csi *csi = &rkisp1->csi;
488b298f059SPaul Elder
489b298f059SPaul Elder if (!csi->rkisp1)
490b298f059SPaul Elder return;
491b298f059SPaul Elder
492b298f059SPaul Elder v4l2_device_unregister_subdev(&csi->sd);
493c7e26218SLaurent Pinchart v4l2_subdev_cleanup(&csi->sd);
494b298f059SPaul Elder media_entity_cleanup(&csi->sd.entity);
495b298f059SPaul Elder }
496b298f059SPaul Elder
rkisp1_csi_init(struct rkisp1_device * rkisp1)4978082e2f4SPaul Elder int rkisp1_csi_init(struct rkisp1_device *rkisp1)
4988082e2f4SPaul Elder {
4998082e2f4SPaul Elder struct rkisp1_csi *csi = &rkisp1->csi;
5008082e2f4SPaul Elder
5018082e2f4SPaul Elder csi->rkisp1 = rkisp1;
5028082e2f4SPaul Elder
5038082e2f4SPaul Elder csi->dphy = devm_phy_get(rkisp1->dev, "dphy");
5048082e2f4SPaul Elder if (IS_ERR(csi->dphy))
5058082e2f4SPaul Elder return dev_err_probe(rkisp1->dev, PTR_ERR(csi->dphy),
5068082e2f4SPaul Elder "Couldn't get the MIPI D-PHY\n");
5078082e2f4SPaul Elder
5088082e2f4SPaul Elder phy_init(csi->dphy);
5098082e2f4SPaul Elder
5108082e2f4SPaul Elder return 0;
5118082e2f4SPaul Elder }
5128082e2f4SPaul Elder
rkisp1_csi_cleanup(struct rkisp1_device * rkisp1)5138082e2f4SPaul Elder void rkisp1_csi_cleanup(struct rkisp1_device *rkisp1)
5148082e2f4SPaul Elder {
5158082e2f4SPaul Elder struct rkisp1_csi *csi = &rkisp1->csi;
5168082e2f4SPaul Elder
5178082e2f4SPaul Elder phy_exit(csi->dphy);
5188082e2f4SPaul Elder }
519