1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2021 Renesas Electronics Corp. 4 * 5 * Driver for Renesas R-Car ISP Channel Selector 6 * 7 * The ISP hardware is capable of more than just channel selection, features 8 * such as demosaicing, white balance control and color space conversion are 9 * also possible. These more advanced features are not supported by the driver 10 * due to lack of documentation. 11 */ 12 13 #include <linux/module.h> 14 #include <linux/of.h> 15 #include <linux/pm_runtime.h> 16 17 #include <media/mipi-csi2.h> 18 #include <media/v4l2-async.h> 19 20 #include "risp-core.h" 21 22 #define ISPINPUTSEL0_REG 0x0008 23 #define ISPINPUTSEL0_SEL_CSI0 BIT(31) 24 25 #define ISPSTART_REG 0x0014 26 #define ISPSTART_START 0xffff 27 #define ISPSTART_STOP 0x0000 28 29 #define ISPPROCMODE_DT_REG(n) (0x1100 + (0x4 * (n))) 30 #define ISPPROCMODE_DT_PROC_MODE_VCn(vc, pm) (((pm) & 0x3f) << (8 * (vc))) 31 32 #define ISPCS_FILTER_ID_CH_REG(n) (0x3000 + (0x0100 * (n))) 33 34 #define ISPCS_DT_CODE03_CH_REG(n) (0x3008 + (0x100 * (n))) 35 #define ISPCS_DT_CODE03_EN3 BIT(31) 36 #define ISPCS_DT_CODE03_DT3(dt) (((dt) & 0x3f) << 24) 37 #define ISPCS_DT_CODE03_EN2 BIT(23) 38 #define ISPCS_DT_CODE03_DT2(dt) (((dt) & 0x3f) << 16) 39 #define ISPCS_DT_CODE03_EN1 BIT(15) 40 #define ISPCS_DT_CODE03_DT1(dt) (((dt) & 0x3f) << 8) 41 #define ISPCS_DT_CODE03_EN0 BIT(7) 42 #define ISPCS_DT_CODE03_DT0(dt) ((dt) & 0x3f) 43 44 struct rcar_isp_format { 45 u32 code; 46 unsigned int datatype; 47 unsigned int procmode; 48 }; 49 50 static const struct rcar_isp_format rcar_isp_formats[] = { 51 { 52 .code = MEDIA_BUS_FMT_RGB888_1X24, 53 .datatype = MIPI_CSI2_DT_RGB888, 54 .procmode = 0x15 55 }, { 56 .code = MEDIA_BUS_FMT_Y10_1X10, 57 .datatype = MIPI_CSI2_DT_RAW10, 58 .procmode = 0x10, 59 }, { 60 .code = MEDIA_BUS_FMT_UYVY8_1X16, 61 .datatype = MIPI_CSI2_DT_YUV422_8B, 62 .procmode = 0x0c, 63 }, { 64 .code = MEDIA_BUS_FMT_YUYV8_1X16, 65 .datatype = MIPI_CSI2_DT_YUV422_8B, 66 .procmode = 0x0c, 67 }, { 68 .code = MEDIA_BUS_FMT_UYVY8_2X8, 69 .datatype = MIPI_CSI2_DT_YUV422_8B, 70 .procmode = 0x0c, 71 }, { 72 .code = MEDIA_BUS_FMT_YUYV10_2X10, 73 .datatype = MIPI_CSI2_DT_YUV422_8B, 74 .procmode = 0x0c, 75 }, { 76 .code = MEDIA_BUS_FMT_SBGGR8_1X8, 77 .datatype = MIPI_CSI2_DT_RAW8, 78 .procmode = 0x00, 79 }, { 80 .code = MEDIA_BUS_FMT_SGBRG8_1X8, 81 .datatype = MIPI_CSI2_DT_RAW8, 82 .procmode = 0x00, 83 }, { 84 .code = MEDIA_BUS_FMT_SGRBG8_1X8, 85 .datatype = MIPI_CSI2_DT_RAW8, 86 .procmode = 0x00, 87 }, { 88 .code = MEDIA_BUS_FMT_SRGGB8_1X8, 89 .datatype = MIPI_CSI2_DT_RAW8, 90 .procmode = 0x00, 91 }, { 92 .code = MEDIA_BUS_FMT_SBGGR10_1X10, 93 .datatype = MIPI_CSI2_DT_RAW10, 94 .procmode = 0x01, 95 }, { 96 .code = MEDIA_BUS_FMT_SGBRG10_1X10, 97 .datatype = MIPI_CSI2_DT_RAW10, 98 .procmode = 0x01, 99 }, { 100 .code = MEDIA_BUS_FMT_SGRBG10_1X10, 101 .datatype = MIPI_CSI2_DT_RAW10, 102 .procmode = 0x01, 103 }, { 104 .code = MEDIA_BUS_FMT_SRGGB10_1X10, 105 .datatype = MIPI_CSI2_DT_RAW10, 106 .procmode = 0x01, 107 }, { 108 .code = MEDIA_BUS_FMT_SBGGR12_1X12, 109 .datatype = MIPI_CSI2_DT_RAW12, 110 .procmode = 0x02, 111 }, { 112 .code = MEDIA_BUS_FMT_SGBRG12_1X12, 113 .datatype = MIPI_CSI2_DT_RAW12, 114 .procmode = 0x02, 115 }, { 116 .code = MEDIA_BUS_FMT_SGRBG12_1X12, 117 .datatype = MIPI_CSI2_DT_RAW12, 118 .procmode = 0x02, 119 }, { 120 .code = MEDIA_BUS_FMT_SRGGB12_1X12, 121 .datatype = MIPI_CSI2_DT_RAW12, 122 .procmode = 0x02, 123 }, 124 }; 125 126 static const struct rcar_isp_format *risp_code_to_fmt(unsigned int code) 127 { 128 unsigned int i; 129 130 for (i = 0; i < ARRAY_SIZE(rcar_isp_formats); i++) { 131 if (rcar_isp_formats[i].code == code) 132 return &rcar_isp_formats[i]; 133 } 134 135 return NULL; 136 } 137 138 enum rcar_isp_input { 139 RISP_CSI_INPUT0, 140 RISP_CSI_INPUT1, 141 }; 142 143 enum rcar_isp_pads { 144 RCAR_ISP_SINK, 145 RCAR_ISP_PORT0, 146 RCAR_ISP_PORT1, 147 RCAR_ISP_PORT2, 148 RCAR_ISP_PORT3, 149 RCAR_ISP_PORT4, 150 RCAR_ISP_PORT5, 151 RCAR_ISP_PORT6, 152 RCAR_ISP_PORT7, 153 RCAR_ISP_NUM_PADS, 154 }; 155 156 struct rcar_isp { 157 struct device *dev; 158 void __iomem *csbase; 159 struct reset_control *rstc; 160 struct rcar_isp_core core; 161 162 enum rcar_isp_input csi_input; 163 164 struct v4l2_subdev subdev; 165 struct media_pad pads[RCAR_ISP_NUM_PADS]; 166 167 struct v4l2_async_notifier notifier; 168 struct v4l2_subdev *remote; 169 unsigned int remote_pad; 170 171 int stream_count; 172 }; 173 174 static inline struct rcar_isp *sd_to_isp(struct v4l2_subdev *sd) 175 { 176 return container_of(sd, struct rcar_isp, subdev); 177 } 178 179 static inline struct rcar_isp *notifier_to_isp(struct v4l2_async_notifier *n) 180 { 181 return container_of(n, struct rcar_isp, notifier); 182 } 183 184 static void risp_write_cs(struct rcar_isp *isp, u32 offset, u32 value) 185 { 186 iowrite32(value, isp->csbase + offset); 187 } 188 189 static u32 risp_read_cs(struct rcar_isp *isp, u32 offset) 190 { 191 return ioread32(isp->csbase + offset); 192 } 193 194 static int risp_power_on(struct rcar_isp *isp) 195 { 196 int ret; 197 198 ret = pm_runtime_resume_and_get(isp->dev); 199 if (ret < 0) 200 return ret; 201 202 ret = reset_control_deassert(isp->rstc); 203 if (ret < 0) { 204 pm_runtime_put(isp->dev); 205 return ret; 206 } 207 208 return 0; 209 } 210 211 static void risp_power_off(struct rcar_isp *isp) 212 { 213 reset_control_assert(isp->rstc); 214 pm_runtime_put(isp->dev); 215 } 216 217 static int risp_start(struct rcar_isp *isp, struct v4l2_subdev_state *state) 218 { 219 const struct v4l2_mbus_framefmt *fmt; 220 const struct rcar_isp_format *format; 221 unsigned int vc; 222 u32 sel_csi = 0; 223 int ret; 224 225 fmt = v4l2_subdev_state_get_format(state, RCAR_ISP_SINK); 226 if (!fmt) 227 return -EINVAL; 228 229 format = risp_code_to_fmt(fmt->code); 230 if (!format) { 231 dev_err(isp->dev, "Unsupported bus format\n"); 232 return -EINVAL; 233 } 234 235 ret = risp_power_on(isp); 236 if (ret) { 237 dev_err(isp->dev, "Failed to power on ISP\n"); 238 return ret; 239 } 240 241 /* Select CSI-2 input source. */ 242 if (isp->csi_input == RISP_CSI_INPUT1) 243 sel_csi = ISPINPUTSEL0_SEL_CSI0; 244 245 risp_write_cs(isp, ISPINPUTSEL0_REG, 246 risp_read_cs(isp, ISPINPUTSEL0_REG) | sel_csi); 247 248 /* Configure Channel Selector. */ 249 for (vc = 0; vc < 4; vc++) { 250 u8 ch = vc + 4; 251 u8 dt = format->datatype; 252 253 risp_write_cs(isp, ISPCS_FILTER_ID_CH_REG(ch), BIT(vc)); 254 risp_write_cs(isp, ISPCS_DT_CODE03_CH_REG(ch), 255 ISPCS_DT_CODE03_EN3 | ISPCS_DT_CODE03_DT3(dt) | 256 ISPCS_DT_CODE03_EN2 | ISPCS_DT_CODE03_DT2(dt) | 257 ISPCS_DT_CODE03_EN1 | ISPCS_DT_CODE03_DT1(dt) | 258 ISPCS_DT_CODE03_EN0 | ISPCS_DT_CODE03_DT0(dt)); 259 } 260 261 /* Setup processing method. */ 262 risp_write_cs(isp, ISPPROCMODE_DT_REG(format->datatype), 263 ISPPROCMODE_DT_PROC_MODE_VCn(3, format->procmode) | 264 ISPPROCMODE_DT_PROC_MODE_VCn(2, format->procmode) | 265 ISPPROCMODE_DT_PROC_MODE_VCn(1, format->procmode) | 266 ISPPROCMODE_DT_PROC_MODE_VCn(0, format->procmode)); 267 268 /* Start ISP. */ 269 risp_write_cs(isp, ISPSTART_REG, ISPSTART_START); 270 271 ret = v4l2_subdev_enable_streams(isp->remote, isp->remote_pad, 272 BIT_ULL(0)); 273 if (ret) 274 risp_power_off(isp); 275 276 return ret; 277 } 278 279 static void risp_stop(struct rcar_isp *isp) 280 { 281 v4l2_subdev_disable_streams(isp->remote, isp->remote_pad, BIT_ULL(0)); 282 283 /* Stop ISP. */ 284 risp_write_cs(isp, ISPSTART_REG, ISPSTART_STOP); 285 286 risp_power_off(isp); 287 } 288 289 static int risp_enable_streams(struct v4l2_subdev *sd, 290 struct v4l2_subdev_state *state, u32 source_pad, 291 u64 source_streams_mask) 292 { 293 struct rcar_isp *isp = sd_to_isp(sd); 294 int ret = 0; 295 296 if (source_streams_mask != 1) 297 return -EINVAL; 298 299 if (!isp->remote) 300 return -ENODEV; 301 302 if (isp->stream_count == 0) { 303 ret = risp_start(isp, state); 304 if (ret) 305 return ret; 306 } 307 308 isp->stream_count += 1; 309 310 return ret; 311 } 312 313 static int risp_disable_streams(struct v4l2_subdev *sd, 314 struct v4l2_subdev_state *state, u32 source_pad, 315 u64 source_streams_mask) 316 { 317 struct rcar_isp *isp = sd_to_isp(sd); 318 319 if (source_streams_mask != 1) 320 return -EINVAL; 321 322 if (!isp->remote) 323 return -ENODEV; 324 325 if (isp->stream_count == 1) 326 risp_stop(isp); 327 328 isp->stream_count -= 1; 329 330 return 0; 331 } 332 333 static int risp_set_pad_format(struct v4l2_subdev *sd, 334 struct v4l2_subdev_state *state, 335 struct v4l2_subdev_format *format) 336 { 337 struct v4l2_mbus_framefmt *framefmt; 338 339 if (format->pad > RCAR_ISP_SINK) 340 return v4l2_subdev_get_fmt(sd, state, format); 341 342 if (!risp_code_to_fmt(format->format.code)) 343 format->format.code = rcar_isp_formats[0].code; 344 345 for (unsigned int i = 0; i < RCAR_ISP_NUM_PADS; i++) { 346 framefmt = v4l2_subdev_state_get_format(state, i); 347 *framefmt = format->format; 348 } 349 350 return 0; 351 } 352 353 static const struct v4l2_subdev_pad_ops risp_pad_ops = { 354 .enable_streams = risp_enable_streams, 355 .disable_streams = risp_disable_streams, 356 .set_fmt = risp_set_pad_format, 357 .get_fmt = v4l2_subdev_get_fmt, 358 .link_validate = v4l2_subdev_link_validate_default, 359 }; 360 361 static const struct v4l2_subdev_ops rcar_isp_subdev_ops = { 362 .pad = &risp_pad_ops, 363 }; 364 365 /* ----------------------------------------------------------------------------- 366 * Async handling and registration of subdevices and links 367 */ 368 369 static int risp_notify_bound(struct v4l2_async_notifier *notifier, 370 struct v4l2_subdev *subdev, 371 struct v4l2_async_connection *asd) 372 { 373 struct rcar_isp *isp = notifier_to_isp(notifier); 374 int pad; 375 376 pad = media_entity_get_fwnode_pad(&subdev->entity, asd->match.fwnode, 377 MEDIA_PAD_FL_SOURCE); 378 if (pad < 0) { 379 dev_err(isp->dev, "Failed to find pad for %s\n", subdev->name); 380 return pad; 381 } 382 383 isp->remote = subdev; 384 isp->remote_pad = pad; 385 386 dev_dbg(isp->dev, "Bound %s pad: %d\n", subdev->name, pad); 387 388 return media_create_pad_link(&subdev->entity, pad, 389 &isp->subdev.entity, 0, 390 MEDIA_LNK_FL_ENABLED | 391 MEDIA_LNK_FL_IMMUTABLE); 392 } 393 394 static void risp_notify_unbind(struct v4l2_async_notifier *notifier, 395 struct v4l2_subdev *subdev, 396 struct v4l2_async_connection *asd) 397 { 398 struct rcar_isp *isp = notifier_to_isp(notifier); 399 400 isp->remote = NULL; 401 402 dev_dbg(isp->dev, "Unbind %s\n", subdev->name); 403 } 404 405 static const struct v4l2_async_notifier_operations risp_notify_ops = { 406 .bound = risp_notify_bound, 407 .unbind = risp_notify_unbind, 408 }; 409 410 static int risp_parse_dt(struct rcar_isp *isp) 411 { 412 struct v4l2_async_connection *asd; 413 struct fwnode_handle *fwnode; 414 struct fwnode_handle *ep; 415 unsigned int id; 416 int ret; 417 418 for (id = 0; id < 2; id++) { 419 ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(isp->dev), 420 0, id, 0); 421 if (ep) 422 break; 423 } 424 425 if (!ep) { 426 dev_err(isp->dev, "Not connected to subdevice\n"); 427 return -EINVAL; 428 } 429 430 if (id == 1) 431 isp->csi_input = RISP_CSI_INPUT1; 432 433 fwnode = fwnode_graph_get_remote_endpoint(ep); 434 fwnode_handle_put(ep); 435 436 dev_dbg(isp->dev, "Found '%pOF'\n", to_of_node(fwnode)); 437 438 v4l2_async_subdev_nf_init(&isp->notifier, &isp->subdev); 439 isp->notifier.ops = &risp_notify_ops; 440 441 asd = v4l2_async_nf_add_fwnode(&isp->notifier, fwnode, 442 struct v4l2_async_connection); 443 fwnode_handle_put(fwnode); 444 if (IS_ERR(asd)) 445 return PTR_ERR(asd); 446 447 ret = v4l2_async_nf_register(&isp->notifier); 448 if (ret) 449 v4l2_async_nf_cleanup(&isp->notifier); 450 451 return ret; 452 } 453 454 /* ----------------------------------------------------------------------------- 455 * ISP Core connection 456 */ 457 458 static int risp_cs_registered(struct v4l2_subdev *sd) 459 { 460 struct rcar_isp *isp = sd_to_isp(sd); 461 462 return risp_core_registered(&isp->core, sd); 463 } 464 465 static const struct v4l2_subdev_internal_ops risp_cs_internal_ops = { 466 .registered = risp_cs_registered, 467 }; 468 469 /* ----------------------------------------------------------------------------- 470 * Platform Device Driver 471 */ 472 473 static const struct media_entity_operations risp_entity_ops = { 474 .link_validate = v4l2_subdev_link_validate, 475 }; 476 477 static int risp_probe_resources(struct rcar_isp *isp, 478 struct platform_device *pdev) 479 { 480 struct resource *res; 481 482 /* 483 * For backward compatibility allow cs base to be the only reg if no 484 * reg-names are set in DT. 485 */ 486 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cs"); 487 if (!res) 488 isp->csbase = devm_platform_ioremap_resource(pdev, 0); 489 else 490 isp->csbase = devm_ioremap_resource(&pdev->dev, res); 491 492 if (IS_ERR(isp->csbase)) 493 return PTR_ERR(isp->csbase); 494 495 isp->rstc = devm_reset_control_get_shared(&pdev->dev, NULL); 496 497 return PTR_ERR_OR_ZERO(isp->rstc); 498 } 499 500 static const struct of_device_id risp_of_id_table[] = { 501 { .compatible = "renesas,r8a779a0-isp" }, 502 { .compatible = "renesas,r8a779g0-isp" }, 503 /* Keep above for compatibility with old DTB files. */ 504 { .compatible = "renesas,rcar-gen4-isp" }, 505 { /* sentinel */ } 506 }; 507 MODULE_DEVICE_TABLE(of, risp_of_id_table); 508 509 static int risp_probe(struct platform_device *pdev) 510 { 511 struct rcar_isp *isp; 512 unsigned int i; 513 int ret; 514 515 isp = devm_kzalloc(&pdev->dev, sizeof(*isp), GFP_KERNEL); 516 if (!isp) 517 return -ENOMEM; 518 519 isp->dev = &pdev->dev; 520 521 ret = risp_probe_resources(isp, pdev); 522 if (ret) { 523 dev_err(isp->dev, "Failed to get resources\n"); 524 return ret; 525 } 526 527 platform_set_drvdata(pdev, isp); 528 529 pm_runtime_enable(&pdev->dev); 530 531 ret = risp_parse_dt(isp); 532 if (ret) 533 goto error_pm; 534 535 isp->subdev.owner = THIS_MODULE; 536 isp->subdev.dev = &pdev->dev; 537 v4l2_subdev_init(&isp->subdev, &rcar_isp_subdev_ops); 538 v4l2_set_subdevdata(&isp->subdev, &pdev->dev); 539 snprintf(isp->subdev.name, sizeof(isp->subdev.name), "%s %s", 540 KBUILD_MODNAME, dev_name(&pdev->dev)); 541 isp->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; 542 543 isp->subdev.entity.function = MEDIA_ENT_F_VID_MUX; 544 isp->subdev.entity.ops = &risp_entity_ops; 545 546 isp->pads[RCAR_ISP_SINK].flags = MEDIA_PAD_FL_SINK; 547 for (i = RCAR_ISP_PORT0; i < RCAR_ISP_NUM_PADS; i++) 548 isp->pads[i].flags = MEDIA_PAD_FL_SOURCE; 549 550 ret = media_entity_pads_init(&isp->subdev.entity, RCAR_ISP_NUM_PADS, 551 isp->pads); 552 if (ret) 553 goto error_notifier; 554 555 ret = v4l2_subdev_init_finalize(&isp->subdev); 556 if (ret) 557 goto error_notifier; 558 559 ret = risp_core_probe(&isp->core, pdev, isp->csbase, isp->rstc); 560 switch (ret) { 561 case 0: 562 /* The device have an ISP core. */ 563 isp->subdev.internal_ops = &risp_cs_internal_ops; 564 break; 565 case -ENODEV: 566 /* The device don't have an ISP core, that is OK. */ 567 ret = 0; 568 break; 569 default: 570 /* Something went wrong registering the ISP core. */ 571 goto error_subdev; 572 } 573 574 ret = v4l2_async_register_subdev(&isp->subdev); 575 if (ret < 0) 576 goto error_core; 577 578 dev_info(isp->dev, "Using CSI-2 input: %u\n", isp->csi_input); 579 580 return 0; 581 582 error_core: 583 risp_core_remove(&isp->core); 584 error_subdev: 585 v4l2_subdev_cleanup(&isp->subdev); 586 error_notifier: 587 v4l2_async_nf_unregister(&isp->notifier); 588 v4l2_async_nf_cleanup(&isp->notifier); 589 error_pm: 590 pm_runtime_disable(&pdev->dev); 591 592 return ret; 593 } 594 595 static void risp_remove(struct platform_device *pdev) 596 { 597 struct rcar_isp *isp = platform_get_drvdata(pdev); 598 599 risp_core_remove(&isp->core); 600 601 v4l2_async_nf_unregister(&isp->notifier); 602 v4l2_async_nf_cleanup(&isp->notifier); 603 604 v4l2_async_unregister_subdev(&isp->subdev); 605 v4l2_subdev_cleanup(&isp->subdev); 606 607 pm_runtime_disable(&pdev->dev); 608 } 609 610 static struct platform_driver rcar_isp_driver = { 611 .driver = { 612 .name = "rcar-isp", 613 .suppress_bind_attrs = true, 614 .of_match_table = risp_of_id_table, 615 }, 616 .probe = risp_probe, 617 .remove = risp_remove, 618 }; 619 620 module_platform_driver(rcar_isp_driver); 621 622 MODULE_AUTHOR("Niklas Söderlund <niklas.soderlund@ragnatech.se>"); 623 MODULE_DESCRIPTION("Renesas R-Car ISP Channel Selector driver"); 624 MODULE_LICENSE("GPL"); 625