Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

media: platform: Add Renesas RZ/G2L MIPI CSI-2 receiver driver

Add MIPI CSI-2 receiver driver for Renesas RZ/G2L. The MIPI
CSI-2 is part of the CRU module found on RZ/G2L family.

Based on a patch in the BSP by Hien Huynh
<hien.huynh.px@renesas.com>

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>

authored by

Lad Prabhakar and committed by
Mauro Carvalho Chehab
51e8415e a1800417

+899
+1
drivers/media/platform/renesas/Kconfig
··· 41 41 Support for the Video Output Unit (VOU) on SuperH SoCs. 42 42 43 43 source "drivers/media/platform/renesas/rcar-vin/Kconfig" 44 + source "drivers/media/platform/renesas/rzg2l-cru/Kconfig" 44 45 45 46 # Mem2mem drivers 46 47
+1
drivers/media/platform/renesas/Makefile
··· 4 4 # 5 5 6 6 obj-y += rcar-vin/ 7 + obj-y += rzg2l-cru/ 7 8 obj-y += vsp1/ 8 9 9 10 obj-$(CONFIG_VIDEO_RCAR_DRIF) += rcar_drif.o
+17
drivers/media/platform/renesas/rzg2l-cru/Kconfig
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + 3 + config VIDEO_RZG2L_CSI2 4 + tristate "RZ/G2L MIPI CSI-2 Receiver" 5 + depends on ARCH_RENESAS || COMPILE_TEST 6 + depends on V4L_PLATFORM_DRIVERS 7 + depends on VIDEO_DEV && OF 8 + select MEDIA_CONTROLLER 9 + select RESET_CONTROLLER 10 + select V4L2_FWNODE 11 + select VIDEO_V4L2_SUBDEV_API 12 + help 13 + Support for Renesas RZ/G2L (and alike SoC's) MIPI CSI-2 14 + Receiver driver. 15 + 16 + To compile this driver as a module, choose M here: the 17 + module will be called rzg2l-csi2.
+3
drivers/media/platform/renesas/rzg2l-cru/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + 3 + obj-$(CONFIG_VIDEO_RZG2L_CSI2) += rzg2l-csi2.o
+877
drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Driver for Renesas RZ/G2L MIPI CSI-2 Receiver 4 + * 5 + * Copyright (C) 2022 Renesas Electronics Corp. 6 + */ 7 + 8 + #include <linux/clk.h> 9 + #include <linux/delay.h> 10 + #include <linux/interrupt.h> 11 + #include <linux/io.h> 12 + #include <linux/module.h> 13 + #include <linux/of.h> 14 + #include <linux/of_device.h> 15 + #include <linux/of_graph.h> 16 + #include <linux/platform_device.h> 17 + #include <linux/pm_runtime.h> 18 + #include <linux/reset.h> 19 + #include <linux/sys_soc.h> 20 + #include <linux/units.h> 21 + 22 + #include <media/v4l2-ctrls.h> 23 + #include <media/v4l2-device.h> 24 + #include <media/v4l2-fwnode.h> 25 + #include <media/v4l2-mc.h> 26 + #include <media/v4l2-subdev.h> 27 + 28 + /* LINK registers */ 29 + /* Module Configuration Register */ 30 + #define CSI2nMCG 0x0 31 + #define CSI2nMCG_SDLN GENMASK(11, 8) 32 + 33 + /* Module Control Register 0 */ 34 + #define CSI2nMCT0 0x10 35 + #define CSI2nMCT0_VDLN(x) ((x) << 0) 36 + 37 + /* Module Control Register 2 */ 38 + #define CSI2nMCT2 0x18 39 + #define CSI2nMCT2_FRRSKW(x) ((x) << 16) 40 + #define CSI2nMCT2_FRRCLK(x) ((x) << 0) 41 + 42 + /* Module Control Register 3 */ 43 + #define CSI2nMCT3 0x1c 44 + #define CSI2nMCT3_RXEN BIT(0) 45 + 46 + /* Reset Control Register */ 47 + #define CSI2nRTCT 0x28 48 + #define CSI2nRTCT_VSRST BIT(0) 49 + 50 + /* Reset Status Register */ 51 + #define CSI2nRTST 0x2c 52 + #define CSI2nRTST_VSRSTS BIT(0) 53 + 54 + /* Receive Data Type Enable Low Register */ 55 + #define CSI2nDTEL 0x60 56 + 57 + /* Receive Data Type Enable High Register */ 58 + #define CSI2nDTEH 0x64 59 + 60 + /* DPHY registers */ 61 + /* D-PHY Control Register 0 */ 62 + #define CSIDPHYCTRL0 0x400 63 + #define CSIDPHYCTRL0_EN_LDO1200 BIT(1) 64 + #define CSIDPHYCTRL0_EN_BGR BIT(0) 65 + 66 + /* D-PHY Timing Register 0 */ 67 + #define CSIDPHYTIM0 0x404 68 + #define CSIDPHYTIM0_TCLK_MISS(x) ((x) << 24) 69 + #define CSIDPHYTIM0_T_INIT(x) ((x) << 0) 70 + 71 + /* D-PHY Timing Register 1 */ 72 + #define CSIDPHYTIM1 0x408 73 + #define CSIDPHYTIM1_THS_PREPARE(x) ((x) << 24) 74 + #define CSIDPHYTIM1_TCLK_PREPARE(x) ((x) << 16) 75 + #define CSIDPHYTIM1_THS_SETTLE(x) ((x) << 8) 76 + #define CSIDPHYTIM1_TCLK_SETTLE(x) ((x) << 0) 77 + 78 + /* D-PHY Skew Adjustment Function */ 79 + #define CSIDPHYSKW0 0x460 80 + #define CSIDPHYSKW0_UTIL_DL0_SKW_ADJ(x) ((x) & 0x3) 81 + #define CSIDPHYSKW0_UTIL_DL1_SKW_ADJ(x) (((x) & 0x3) << 4) 82 + #define CSIDPHYSKW0_UTIL_DL2_SKW_ADJ(x) (((x) & 0x3) << 8) 83 + #define CSIDPHYSKW0_UTIL_DL3_SKW_ADJ(x) (((x) & 0x3) << 12) 84 + #define CSIDPHYSKW0_DEFAULT_SKW CSIDPHYSKW0_UTIL_DL0_SKW_ADJ(1) | \ 85 + CSIDPHYSKW0_UTIL_DL1_SKW_ADJ(1) | \ 86 + CSIDPHYSKW0_UTIL_DL2_SKW_ADJ(1) | \ 87 + CSIDPHYSKW0_UTIL_DL3_SKW_ADJ(1) 88 + 89 + #define VSRSTS_RETRIES 20 90 + 91 + #define RZG2L_CSI2_MIN_WIDTH 320 92 + #define RZG2L_CSI2_MIN_HEIGHT 240 93 + #define RZG2L_CSI2_MAX_WIDTH 2800 94 + #define RZG2L_CSI2_MAX_HEIGHT 4095 95 + 96 + #define RZG2L_CSI2_DEFAULT_WIDTH RZG2L_CSI2_MIN_WIDTH 97 + #define RZG2L_CSI2_DEFAULT_HEIGHT RZG2L_CSI2_MIN_HEIGHT 98 + #define RZG2L_CSI2_DEFAULT_FMT MEDIA_BUS_FMT_UYVY8_1X16 99 + 100 + enum rzg2l_csi2_pads { 101 + RZG2L_CSI2_SINK = 0, 102 + RZG2L_CSI2_SOURCE, 103 + NR_OF_RZG2L_CSI2_PAD, 104 + }; 105 + 106 + struct rzg2l_csi2 { 107 + struct device *dev; 108 + void __iomem *base; 109 + struct reset_control *presetn; 110 + struct reset_control *cmn_rstb; 111 + struct clk *sysclk; 112 + unsigned long vclk_rate; 113 + 114 + struct v4l2_subdev subdev; 115 + struct media_pad pads[NR_OF_RZG2L_CSI2_PAD]; 116 + 117 + struct v4l2_async_notifier notifier; 118 + struct v4l2_subdev *remote_source; 119 + 120 + unsigned short lanes; 121 + unsigned long hsfreq; 122 + 123 + bool dphy_enabled; 124 + }; 125 + 126 + struct rzg2l_csi2_timings { 127 + u32 t_init; 128 + u32 tclk_miss; 129 + u32 tclk_settle; 130 + u32 ths_settle; 131 + u32 tclk_prepare; 132 + u32 ths_prepare; 133 + u32 max_hsfreq; 134 + }; 135 + 136 + static const struct rzg2l_csi2_timings rzg2l_csi2_global_timings[] = { 137 + { 138 + .max_hsfreq = 80, 139 + .t_init = 79801, 140 + .tclk_miss = 4, 141 + .tclk_settle = 23, 142 + .ths_settle = 31, 143 + .tclk_prepare = 10, 144 + .ths_prepare = 19, 145 + }, 146 + { 147 + .max_hsfreq = 125, 148 + .t_init = 79801, 149 + .tclk_miss = 4, 150 + .tclk_settle = 23, 151 + .ths_settle = 28, 152 + .tclk_prepare = 10, 153 + .ths_prepare = 19, 154 + }, 155 + { 156 + .max_hsfreq = 250, 157 + .t_init = 79801, 158 + .tclk_miss = 4, 159 + .tclk_settle = 23, 160 + .ths_settle = 22, 161 + .tclk_prepare = 10, 162 + .ths_prepare = 16, 163 + }, 164 + { 165 + .max_hsfreq = 360, 166 + .t_init = 79801, 167 + .tclk_miss = 4, 168 + .tclk_settle = 18, 169 + .ths_settle = 19, 170 + .tclk_prepare = 10, 171 + .ths_prepare = 10, 172 + }, 173 + { 174 + .max_hsfreq = 1500, 175 + .t_init = 79801, 176 + .tclk_miss = 4, 177 + .tclk_settle = 18, 178 + .ths_settle = 18, 179 + .tclk_prepare = 10, 180 + .ths_prepare = 10, 181 + }, 182 + }; 183 + 184 + struct rzg2l_csi2_format { 185 + u32 code; 186 + unsigned int datatype; 187 + unsigned int bpp; 188 + }; 189 + 190 + static const struct rzg2l_csi2_format rzg2l_csi2_formats[] = { 191 + { .code = MEDIA_BUS_FMT_UYVY8_1X16, .datatype = 0x1e, .bpp = 16 }, 192 + }; 193 + 194 + static inline struct rzg2l_csi2 *sd_to_csi2(struct v4l2_subdev *sd) 195 + { 196 + return container_of(sd, struct rzg2l_csi2, subdev); 197 + } 198 + 199 + static const struct rzg2l_csi2_format *rzg2l_csi2_code_to_fmt(unsigned int code) 200 + { 201 + unsigned int i; 202 + 203 + for (i = 0; i < ARRAY_SIZE(rzg2l_csi2_formats); i++) 204 + if (rzg2l_csi2_formats[i].code == code) 205 + return &rzg2l_csi2_formats[i]; 206 + 207 + return NULL; 208 + } 209 + 210 + static inline struct rzg2l_csi2 *notifier_to_csi2(struct v4l2_async_notifier *n) 211 + { 212 + return container_of(n, struct rzg2l_csi2, notifier); 213 + } 214 + 215 + static u32 rzg2l_csi2_read(struct rzg2l_csi2 *csi2, unsigned int reg) 216 + { 217 + return ioread32(csi2->base + reg); 218 + } 219 + 220 + static void rzg2l_csi2_write(struct rzg2l_csi2 *csi2, unsigned int reg, 221 + u32 data) 222 + { 223 + iowrite32(data, csi2->base + reg); 224 + } 225 + 226 + static void rzg2l_csi2_set(struct rzg2l_csi2 *csi2, unsigned int reg, u32 set) 227 + { 228 + rzg2l_csi2_write(csi2, reg, rzg2l_csi2_read(csi2, reg) | set); 229 + } 230 + 231 + static void rzg2l_csi2_clr(struct rzg2l_csi2 *csi2, unsigned int reg, u32 clr) 232 + { 233 + rzg2l_csi2_write(csi2, reg, rzg2l_csi2_read(csi2, reg) & ~clr); 234 + } 235 + 236 + static int rzg2l_csi2_calc_mbps(struct rzg2l_csi2 *csi2) 237 + { 238 + struct v4l2_subdev *source = csi2->remote_source; 239 + const struct rzg2l_csi2_format *format; 240 + const struct v4l2_mbus_framefmt *fmt; 241 + struct v4l2_subdev_state *state; 242 + struct v4l2_ctrl *ctrl; 243 + u64 mbps; 244 + 245 + /* Read the pixel rate control from remote. */ 246 + ctrl = v4l2_ctrl_find(source->ctrl_handler, V4L2_CID_PIXEL_RATE); 247 + if (!ctrl) { 248 + dev_err(csi2->dev, "no pixel rate control in subdev %s\n", 249 + source->name); 250 + return -EINVAL; 251 + } 252 + 253 + state = v4l2_subdev_lock_and_get_active_state(&csi2->subdev); 254 + fmt = v4l2_subdev_get_pad_format(&csi2->subdev, state, RZG2L_CSI2_SINK); 255 + format = rzg2l_csi2_code_to_fmt(fmt->code); 256 + v4l2_subdev_unlock_state(state); 257 + 258 + /* 259 + * Calculate hsfreq in Mbps 260 + * hsfreq = (pixel_rate * bits_per_sample) / number_of_lanes 261 + */ 262 + mbps = v4l2_ctrl_g_ctrl_int64(ctrl) * format->bpp; 263 + do_div(mbps, csi2->lanes * 1000000); 264 + 265 + return mbps; 266 + } 267 + 268 + /* ----------------------------------------------------------------------------- 269 + * DPHY setting 270 + */ 271 + 272 + static int rzg2l_csi2_dphy_disable(struct rzg2l_csi2 *csi2) 273 + { 274 + int ret; 275 + 276 + /* Reset the CRU (D-PHY) */ 277 + ret = reset_control_assert(csi2->cmn_rstb); 278 + if (ret) 279 + return ret; 280 + 281 + /* Stop the D-PHY clock */ 282 + clk_disable_unprepare(csi2->sysclk); 283 + 284 + /* Cancel the EN_LDO1200 register setting */ 285 + rzg2l_csi2_clr(csi2, CSIDPHYCTRL0, CSIDPHYCTRL0_EN_LDO1200); 286 + 287 + /* Cancel the EN_BGR register setting */ 288 + rzg2l_csi2_clr(csi2, CSIDPHYCTRL0, CSIDPHYCTRL0_EN_BGR); 289 + 290 + csi2->dphy_enabled = false; 291 + 292 + return 0; 293 + } 294 + 295 + static int rzg2l_csi2_dphy_enable(struct rzg2l_csi2 *csi2) 296 + { 297 + const struct rzg2l_csi2_timings *dphy_timing; 298 + u32 dphytim0, dphytim1; 299 + unsigned int i; 300 + int mbps; 301 + int ret; 302 + 303 + mbps = rzg2l_csi2_calc_mbps(csi2); 304 + if (mbps < 0) 305 + return mbps; 306 + 307 + csi2->hsfreq = mbps; 308 + 309 + /* Set DPHY timing parameters */ 310 + for (i = 0; i < ARRAY_SIZE(rzg2l_csi2_global_timings); ++i) { 311 + dphy_timing = &rzg2l_csi2_global_timings[i]; 312 + 313 + if (csi2->hsfreq <= dphy_timing->max_hsfreq) 314 + break; 315 + } 316 + 317 + if (i >= ARRAY_SIZE(rzg2l_csi2_global_timings)) 318 + return -EINVAL; 319 + 320 + /* Set D-PHY timing parameters */ 321 + dphytim0 = CSIDPHYTIM0_TCLK_MISS(dphy_timing->tclk_miss) | 322 + CSIDPHYTIM0_T_INIT(dphy_timing->t_init); 323 + dphytim1 = CSIDPHYTIM1_THS_PREPARE(dphy_timing->ths_prepare) | 324 + CSIDPHYTIM1_TCLK_PREPARE(dphy_timing->tclk_prepare) | 325 + CSIDPHYTIM1_THS_SETTLE(dphy_timing->ths_settle) | 326 + CSIDPHYTIM1_TCLK_SETTLE(dphy_timing->tclk_settle); 327 + rzg2l_csi2_write(csi2, CSIDPHYTIM0, dphytim0); 328 + rzg2l_csi2_write(csi2, CSIDPHYTIM1, dphytim1); 329 + 330 + /* Enable D-PHY power control 0 */ 331 + rzg2l_csi2_write(csi2, CSIDPHYSKW0, CSIDPHYSKW0_DEFAULT_SKW); 332 + 333 + /* Set the EN_BGR bit */ 334 + rzg2l_csi2_set(csi2, CSIDPHYCTRL0, CSIDPHYCTRL0_EN_BGR); 335 + 336 + /* Delay 20us to be stable */ 337 + usleep_range(20, 40); 338 + 339 + /* Enable D-PHY power control 1 */ 340 + rzg2l_csi2_set(csi2, CSIDPHYCTRL0, CSIDPHYCTRL0_EN_LDO1200); 341 + 342 + /* Delay 10us to be stable */ 343 + usleep_range(10, 20); 344 + 345 + /* Start supplying the internal clock for the D-PHY block */ 346 + ret = clk_prepare_enable(csi2->sysclk); 347 + if (ret) 348 + rzg2l_csi2_dphy_disable(csi2); 349 + 350 + csi2->dphy_enabled = true; 351 + 352 + return ret; 353 + } 354 + 355 + static int rzg2l_csi2_dphy_setting(struct v4l2_subdev *sd, bool on) 356 + { 357 + struct rzg2l_csi2 *csi2 = sd_to_csi2(sd); 358 + 359 + if (on) 360 + return rzg2l_csi2_dphy_enable(csi2); 361 + 362 + return rzg2l_csi2_dphy_disable(csi2); 363 + } 364 + 365 + static void rzg2l_csi2_mipi_link_enable(struct rzg2l_csi2 *csi2) 366 + { 367 + unsigned long vclk_rate = csi2->vclk_rate / HZ_PER_MHZ; 368 + u32 frrskw, frrclk, frrskw_coeff, frrclk_coeff; 369 + 370 + /* Select data lanes */ 371 + rzg2l_csi2_write(csi2, CSI2nMCT0, CSI2nMCT0_VDLN(csi2->lanes)); 372 + 373 + frrskw_coeff = 3 * vclk_rate * 8; 374 + frrclk_coeff = frrskw_coeff / 2; 375 + frrskw = DIV_ROUND_UP(frrskw_coeff, csi2->hsfreq); 376 + frrclk = DIV_ROUND_UP(frrclk_coeff, csi2->hsfreq); 377 + rzg2l_csi2_write(csi2, CSI2nMCT2, CSI2nMCT2_FRRSKW(frrskw) | 378 + CSI2nMCT2_FRRCLK(frrclk)); 379 + 380 + /* 381 + * Select data type. 382 + * FS, FE, LS, LE, Generic Short Packet Codes 1 to 8, 383 + * Generic Long Packet Data Types 1 to 4 YUV422 8-bit, 384 + * RGB565, RGB888, RAW8 to RAW20, User-defined 8-bit 385 + * data types 1 to 8 386 + */ 387 + rzg2l_csi2_write(csi2, CSI2nDTEL, 0xf778ff0f); 388 + rzg2l_csi2_write(csi2, CSI2nDTEH, 0x00ffff1f); 389 + 390 + /* Enable LINK reception */ 391 + rzg2l_csi2_write(csi2, CSI2nMCT3, CSI2nMCT3_RXEN); 392 + } 393 + 394 + static void rzg2l_csi2_mipi_link_disable(struct rzg2l_csi2 *csi2) 395 + { 396 + unsigned int timeout = VSRSTS_RETRIES; 397 + 398 + /* Stop LINK reception */ 399 + rzg2l_csi2_clr(csi2, CSI2nMCT3, CSI2nMCT3_RXEN); 400 + 401 + /* Request a software reset of the LINK Video Pixel Interface */ 402 + rzg2l_csi2_write(csi2, CSI2nRTCT, CSI2nRTCT_VSRST); 403 + 404 + /* Make sure CSI2nRTST.VSRSTS bit is cleared */ 405 + while (timeout--) { 406 + if (!(rzg2l_csi2_read(csi2, CSI2nRTST) & CSI2nRTST_VSRSTS)) 407 + break; 408 + usleep_range(100, 200); 409 + }; 410 + 411 + if (!timeout) 412 + dev_err(csi2->dev, "Clearing CSI2nRTST.VSRSTS timed out\n"); 413 + } 414 + 415 + static int rzg2l_csi2_mipi_link_setting(struct v4l2_subdev *sd, bool on) 416 + { 417 + struct rzg2l_csi2 *csi2 = sd_to_csi2(sd); 418 + 419 + if (on) 420 + rzg2l_csi2_mipi_link_enable(csi2); 421 + else 422 + rzg2l_csi2_mipi_link_disable(csi2); 423 + 424 + return 0; 425 + } 426 + 427 + static int rzg2l_csi2_s_stream(struct v4l2_subdev *sd, int enable) 428 + { 429 + struct rzg2l_csi2 *csi2 = sd_to_csi2(sd); 430 + int s_stream_ret = 0; 431 + int ret; 432 + 433 + if (enable) { 434 + int ret; 435 + 436 + ret = pm_runtime_resume_and_get(csi2->dev); 437 + if (ret) 438 + return ret; 439 + 440 + ret = rzg2l_csi2_mipi_link_setting(sd, 1); 441 + if (ret) 442 + goto err_pm_put; 443 + 444 + ret = reset_control_deassert(csi2->cmn_rstb); 445 + if (ret) 446 + goto err_mipi_link_disable; 447 + } 448 + 449 + ret = v4l2_subdev_call(csi2->remote_source, video, s_stream, enable); 450 + if (ret) 451 + s_stream_ret = ret; 452 + 453 + if (enable && ret) 454 + goto err_assert_rstb; 455 + 456 + if (!enable) { 457 + ret = rzg2l_csi2_dphy_setting(sd, 0); 458 + if (ret && !s_stream_ret) 459 + s_stream_ret = ret; 460 + ret = rzg2l_csi2_mipi_link_setting(sd, 0); 461 + if (ret && !s_stream_ret) 462 + s_stream_ret = ret; 463 + 464 + pm_runtime_put_sync(csi2->dev); 465 + } 466 + 467 + return s_stream_ret; 468 + 469 + err_assert_rstb: 470 + reset_control_assert(csi2->cmn_rstb); 471 + err_mipi_link_disable: 472 + rzg2l_csi2_mipi_link_setting(sd, 0); 473 + err_pm_put: 474 + pm_runtime_put_sync(csi2->dev); 475 + return ret; 476 + } 477 + 478 + static int rzg2l_csi2_pre_streamon(struct v4l2_subdev *sd, u32 flags) 479 + { 480 + return rzg2l_csi2_dphy_setting(sd, 1); 481 + } 482 + 483 + static int rzg2l_csi2_post_streamoff(struct v4l2_subdev *sd) 484 + { 485 + struct rzg2l_csi2 *csi2 = sd_to_csi2(sd); 486 + 487 + /* 488 + * In ideal case D-PHY will be disabled in s_stream(0) callback 489 + * as mentioned in the HW manual. The below will only happen when 490 + * pre_streamon succeeds and further down the line s_stream(1) 491 + * fails so we need to undo things in post_streamoff. 492 + */ 493 + if (csi2->dphy_enabled) 494 + return rzg2l_csi2_dphy_setting(sd, 0); 495 + 496 + return 0; 497 + } 498 + 499 + static int rzg2l_csi2_set_format(struct v4l2_subdev *sd, 500 + struct v4l2_subdev_state *state, 501 + struct v4l2_subdev_format *fmt) 502 + { 503 + struct v4l2_mbus_framefmt *src_format; 504 + struct v4l2_mbus_framefmt *sink_format; 505 + 506 + src_format = v4l2_subdev_get_pad_format(sd, state, RZG2L_CSI2_SOURCE); 507 + if (fmt->pad == RZG2L_CSI2_SOURCE) { 508 + fmt->format = *src_format; 509 + return 0; 510 + } 511 + 512 + sink_format = v4l2_subdev_get_pad_format(sd, state, RZG2L_CSI2_SINK); 513 + 514 + if (!rzg2l_csi2_code_to_fmt(fmt->format.code)) 515 + sink_format->code = rzg2l_csi2_formats[0].code; 516 + else 517 + sink_format->code = fmt->format.code; 518 + 519 + sink_format->field = V4L2_FIELD_NONE; 520 + sink_format->colorspace = fmt->format.colorspace; 521 + sink_format->xfer_func = fmt->format.xfer_func; 522 + sink_format->ycbcr_enc = fmt->format.ycbcr_enc; 523 + sink_format->quantization = fmt->format.quantization; 524 + sink_format->width = clamp_t(u32, fmt->format.width, 525 + RZG2L_CSI2_MIN_WIDTH, RZG2L_CSI2_MAX_WIDTH); 526 + sink_format->height = clamp_t(u32, fmt->format.height, 527 + RZG2L_CSI2_MIN_HEIGHT, RZG2L_CSI2_MAX_HEIGHT); 528 + fmt->format = *sink_format; 529 + 530 + /* propagate format to source pad */ 531 + *src_format = *sink_format; 532 + 533 + return 0; 534 + } 535 + 536 + static int rzg2l_csi2_init_config(struct v4l2_subdev *sd, 537 + struct v4l2_subdev_state *sd_state) 538 + { 539 + struct v4l2_subdev_format fmt = { .pad = RZG2L_CSI2_SINK, }; 540 + 541 + fmt.format.width = RZG2L_CSI2_DEFAULT_WIDTH; 542 + fmt.format.height = RZG2L_CSI2_DEFAULT_HEIGHT; 543 + fmt.format.field = V4L2_FIELD_NONE; 544 + fmt.format.code = RZG2L_CSI2_DEFAULT_FMT; 545 + fmt.format.colorspace = V4L2_COLORSPACE_SRGB; 546 + fmt.format.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; 547 + fmt.format.quantization = V4L2_QUANTIZATION_DEFAULT; 548 + fmt.format.xfer_func = V4L2_XFER_FUNC_DEFAULT; 549 + 550 + return rzg2l_csi2_set_format(sd, sd_state, &fmt); 551 + } 552 + 553 + static int rzg2l_csi2_enum_mbus_code(struct v4l2_subdev *sd, 554 + struct v4l2_subdev_state *sd_state, 555 + struct v4l2_subdev_mbus_code_enum *code) 556 + { 557 + if (code->index >= ARRAY_SIZE(rzg2l_csi2_formats)) 558 + return -EINVAL; 559 + 560 + code->code = rzg2l_csi2_formats[code->index].code; 561 + 562 + return 0; 563 + } 564 + 565 + static int rzg2l_csi2_enum_frame_size(struct v4l2_subdev *sd, 566 + struct v4l2_subdev_state *sd_state, 567 + struct v4l2_subdev_frame_size_enum *fse) 568 + { 569 + if (fse->index != 0) 570 + return -EINVAL; 571 + 572 + fse->min_width = RZG2L_CSI2_MIN_WIDTH; 573 + fse->min_height = RZG2L_CSI2_MIN_HEIGHT; 574 + fse->max_width = RZG2L_CSI2_MAX_WIDTH; 575 + fse->max_height = RZG2L_CSI2_MAX_HEIGHT; 576 + 577 + return 0; 578 + } 579 + 580 + static const struct v4l2_subdev_video_ops rzg2l_csi2_video_ops = { 581 + .s_stream = rzg2l_csi2_s_stream, 582 + .pre_streamon = rzg2l_csi2_pre_streamon, 583 + .post_streamoff = rzg2l_csi2_post_streamoff, 584 + }; 585 + 586 + static const struct v4l2_subdev_pad_ops rzg2l_csi2_pad_ops = { 587 + .enum_mbus_code = rzg2l_csi2_enum_mbus_code, 588 + .init_cfg = rzg2l_csi2_init_config, 589 + .enum_frame_size = rzg2l_csi2_enum_frame_size, 590 + .set_fmt = rzg2l_csi2_set_format, 591 + .get_fmt = v4l2_subdev_get_fmt, 592 + }; 593 + 594 + static const struct v4l2_subdev_ops rzg2l_csi2_subdev_ops = { 595 + .video = &rzg2l_csi2_video_ops, 596 + .pad = &rzg2l_csi2_pad_ops, 597 + }; 598 + 599 + /* ----------------------------------------------------------------------------- 600 + * Async handling and registration of subdevices and links. 601 + */ 602 + 603 + static int rzg2l_csi2_notify_bound(struct v4l2_async_notifier *notifier, 604 + struct v4l2_subdev *subdev, 605 + struct v4l2_async_subdev *asd) 606 + { 607 + struct rzg2l_csi2 *csi2 = notifier_to_csi2(notifier); 608 + 609 + csi2->remote_source = subdev; 610 + 611 + dev_dbg(csi2->dev, "Bound subdev: %s pad\n", subdev->name); 612 + 613 + return media_create_pad_link(&subdev->entity, RZG2L_CSI2_SINK, 614 + &csi2->subdev.entity, 0, 615 + MEDIA_LNK_FL_ENABLED | 616 + MEDIA_LNK_FL_IMMUTABLE); 617 + } 618 + 619 + static void rzg2l_csi2_notify_unbind(struct v4l2_async_notifier *notifier, 620 + struct v4l2_subdev *subdev, 621 + struct v4l2_async_subdev *asd) 622 + { 623 + struct rzg2l_csi2 *csi2 = notifier_to_csi2(notifier); 624 + 625 + csi2->remote_source = NULL; 626 + 627 + dev_dbg(csi2->dev, "Unbind subdev %s\n", subdev->name); 628 + } 629 + 630 + static const struct v4l2_async_notifier_operations rzg2l_csi2_notify_ops = { 631 + .bound = rzg2l_csi2_notify_bound, 632 + .unbind = rzg2l_csi2_notify_unbind, 633 + }; 634 + 635 + static int rzg2l_csi2_parse_v4l2(struct rzg2l_csi2 *csi2, 636 + struct v4l2_fwnode_endpoint *vep) 637 + { 638 + /* Only port 0 endpoint 0 is valid. */ 639 + if (vep->base.port || vep->base.id) 640 + return -ENOTCONN; 641 + 642 + csi2->lanes = vep->bus.mipi_csi2.num_data_lanes; 643 + 644 + return 0; 645 + } 646 + 647 + static int rzg2l_csi2_parse_dt(struct rzg2l_csi2 *csi2) 648 + { 649 + struct v4l2_fwnode_endpoint v4l2_ep = { 650 + .bus_type = V4L2_MBUS_CSI2_DPHY 651 + }; 652 + struct v4l2_async_subdev *asd; 653 + struct fwnode_handle *fwnode; 654 + struct fwnode_handle *ep; 655 + int ret; 656 + 657 + ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(csi2->dev), 0, 0, 0); 658 + if (!ep) { 659 + dev_err(csi2->dev, "Not connected to subdevice\n"); 660 + return -EINVAL; 661 + } 662 + 663 + ret = v4l2_fwnode_endpoint_parse(ep, &v4l2_ep); 664 + if (ret) { 665 + dev_err(csi2->dev, "Could not parse v4l2 endpoint\n"); 666 + fwnode_handle_put(ep); 667 + return -EINVAL; 668 + } 669 + 670 + ret = rzg2l_csi2_parse_v4l2(csi2, &v4l2_ep); 671 + if (ret) { 672 + fwnode_handle_put(ep); 673 + return ret; 674 + } 675 + 676 + fwnode = fwnode_graph_get_remote_endpoint(ep); 677 + fwnode_handle_put(ep); 678 + 679 + v4l2_async_nf_init(&csi2->notifier); 680 + csi2->notifier.ops = &rzg2l_csi2_notify_ops; 681 + 682 + asd = v4l2_async_nf_add_fwnode(&csi2->notifier, fwnode, 683 + struct v4l2_async_subdev); 684 + fwnode_handle_put(fwnode); 685 + if (IS_ERR(asd)) 686 + return PTR_ERR(asd); 687 + 688 + ret = v4l2_async_subdev_nf_register(&csi2->subdev, &csi2->notifier); 689 + if (ret) 690 + v4l2_async_nf_cleanup(&csi2->notifier); 691 + 692 + return ret; 693 + } 694 + 695 + static int rzg2l_validate_csi2_lanes(struct rzg2l_csi2 *csi2) 696 + { 697 + int lanes; 698 + int ret; 699 + 700 + if (csi2->lanes != 1 && csi2->lanes != 2 && csi2->lanes != 4) { 701 + dev_err(csi2->dev, "Unsupported number of data-lanes: %u\n", 702 + csi2->lanes); 703 + return -EINVAL; 704 + } 705 + 706 + ret = pm_runtime_resume_and_get(csi2->dev); 707 + if (ret) 708 + return ret; 709 + 710 + /* Checking the maximum lanes support for CSI-2 module */ 711 + lanes = (rzg2l_csi2_read(csi2, CSI2nMCG) & CSI2nMCG_SDLN) >> 8; 712 + if (lanes < csi2->lanes) { 713 + dev_err(csi2->dev, 714 + "Failed to support %d data lanes\n", csi2->lanes); 715 + ret = -EINVAL; 716 + } 717 + 718 + pm_runtime_put_sync(csi2->dev); 719 + 720 + return ret; 721 + } 722 + 723 + /* ----------------------------------------------------------------------------- 724 + * Platform Device Driver. 725 + */ 726 + 727 + static const struct media_entity_operations rzg2l_csi2_entity_ops = { 728 + .link_validate = v4l2_subdev_link_validate, 729 + }; 730 + 731 + static int rzg2l_csi2_probe(struct platform_device *pdev) 732 + { 733 + struct rzg2l_csi2 *csi2; 734 + struct clk *vclk; 735 + int ret; 736 + 737 + csi2 = devm_kzalloc(&pdev->dev, sizeof(*csi2), GFP_KERNEL); 738 + if (!csi2) 739 + return -ENOMEM; 740 + 741 + csi2->base = devm_platform_ioremap_resource(pdev, 0); 742 + if (IS_ERR(csi2->base)) 743 + return PTR_ERR(csi2->base); 744 + 745 + csi2->cmn_rstb = devm_reset_control_get_exclusive(&pdev->dev, "cmn-rstb"); 746 + if (IS_ERR(csi2->cmn_rstb)) 747 + return dev_err_probe(&pdev->dev, PTR_ERR(csi2->cmn_rstb), 748 + "Failed to get cpg cmn-rstb\n"); 749 + 750 + csi2->presetn = devm_reset_control_get_shared(&pdev->dev, "presetn"); 751 + if (IS_ERR(csi2->presetn)) 752 + return dev_err_probe(&pdev->dev, PTR_ERR(csi2->presetn), 753 + "Failed to get cpg presetn\n"); 754 + 755 + csi2->sysclk = devm_clk_get(&pdev->dev, "system"); 756 + if (IS_ERR(csi2->sysclk)) 757 + return dev_err_probe(&pdev->dev, PTR_ERR(csi2->sysclk), 758 + "Failed to get system clk\n"); 759 + 760 + vclk = clk_get(&pdev->dev, "video"); 761 + if (IS_ERR(vclk)) 762 + return dev_err_probe(&pdev->dev, PTR_ERR(vclk), 763 + "Failed to get video clock\n"); 764 + csi2->vclk_rate = clk_get_rate(vclk); 765 + clk_put(vclk); 766 + 767 + csi2->dev = &pdev->dev; 768 + 769 + platform_set_drvdata(pdev, csi2); 770 + 771 + ret = rzg2l_csi2_parse_dt(csi2); 772 + if (ret) 773 + return ret; 774 + 775 + pm_runtime_enable(&pdev->dev); 776 + 777 + ret = rzg2l_validate_csi2_lanes(csi2); 778 + if (ret) 779 + goto error_pm; 780 + 781 + csi2->subdev.dev = &pdev->dev; 782 + v4l2_subdev_init(&csi2->subdev, &rzg2l_csi2_subdev_ops); 783 + v4l2_set_subdevdata(&csi2->subdev, &pdev->dev); 784 + snprintf(csi2->subdev.name, sizeof(csi2->subdev.name), 785 + "csi-%s", dev_name(&pdev->dev)); 786 + csi2->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; 787 + 788 + csi2->subdev.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; 789 + csi2->subdev.entity.ops = &rzg2l_csi2_entity_ops; 790 + 791 + csi2->pads[RZG2L_CSI2_SINK].flags = MEDIA_PAD_FL_SINK; 792 + /* 793 + * TODO: RZ/G2L CSI2 supports 4 virtual channels, as virtual 794 + * channels should be implemented by streams API which is under 795 + * development lets hardcode to VC0 for now. 796 + */ 797 + csi2->pads[RZG2L_CSI2_SOURCE].flags = MEDIA_PAD_FL_SOURCE; 798 + ret = media_entity_pads_init(&csi2->subdev.entity, 2, csi2->pads); 799 + if (ret) 800 + goto error_pm; 801 + 802 + ret = v4l2_subdev_init_finalize(&csi2->subdev); 803 + if (ret < 0) 804 + goto error_async; 805 + 806 + ret = v4l2_async_register_subdev(&csi2->subdev); 807 + if (ret < 0) 808 + goto error_subdev; 809 + 810 + return 0; 811 + 812 + error_subdev: 813 + v4l2_subdev_cleanup(&csi2->subdev); 814 + error_async: 815 + v4l2_async_nf_unregister(&csi2->notifier); 816 + v4l2_async_nf_cleanup(&csi2->notifier); 817 + media_entity_cleanup(&csi2->subdev.entity); 818 + error_pm: 819 + pm_runtime_disable(&pdev->dev); 820 + 821 + return ret; 822 + } 823 + 824 + static int rzg2l_csi2_remove(struct platform_device *pdev) 825 + { 826 + struct rzg2l_csi2 *csi2 = platform_get_drvdata(pdev); 827 + 828 + v4l2_async_nf_unregister(&csi2->notifier); 829 + v4l2_async_nf_cleanup(&csi2->notifier); 830 + v4l2_async_unregister_subdev(&csi2->subdev); 831 + v4l2_subdev_cleanup(&csi2->subdev); 832 + media_entity_cleanup(&csi2->subdev.entity); 833 + pm_runtime_disable(&pdev->dev); 834 + 835 + return 0; 836 + } 837 + 838 + static int __maybe_unused rzg2l_csi2_pm_runtime_suspend(struct device *dev) 839 + { 840 + struct rzg2l_csi2 *csi2 = dev_get_drvdata(dev); 841 + 842 + reset_control_assert(csi2->presetn); 843 + 844 + return 0; 845 + } 846 + 847 + static int __maybe_unused rzg2l_csi2_pm_runtime_resume(struct device *dev) 848 + { 849 + struct rzg2l_csi2 *csi2 = dev_get_drvdata(dev); 850 + 851 + return reset_control_deassert(csi2->presetn); 852 + } 853 + 854 + static const struct dev_pm_ops rzg2l_csi2_pm_ops = { 855 + SET_RUNTIME_PM_OPS(rzg2l_csi2_pm_runtime_suspend, rzg2l_csi2_pm_runtime_resume, NULL) 856 + }; 857 + 858 + static const struct of_device_id rzg2l_csi2_of_table[] = { 859 + { .compatible = "renesas,rzg2l-csi2", }, 860 + { /* sentinel */ } 861 + }; 862 + 863 + static struct platform_driver rzg2l_csi2_pdrv = { 864 + .remove = rzg2l_csi2_remove, 865 + .probe = rzg2l_csi2_probe, 866 + .driver = { 867 + .name = "rzg2l-csi2", 868 + .of_match_table = rzg2l_csi2_of_table, 869 + .pm = &rzg2l_csi2_pm_ops, 870 + }, 871 + }; 872 + 873 + module_platform_driver(rzg2l_csi2_pdrv); 874 + 875 + MODULE_AUTHOR("Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>"); 876 + MODULE_DESCRIPTION("Renesas RZ/G2L MIPI CSI2 receiver driver"); 877 + MODULE_LICENSE("GPL");