Lines Matching +full:isp +full:- +full:0

1 // SPDX-License-Identifier: GPL-2.0
5 * Driver for Renesas R-Car ISP Channel Selector
7 * The ISP hardware is capable of more than just channel selection, features
20 #include <media/mipi-csi2.h>
21 #include <media/v4l2-subdev.h>
23 #define ISPINPUTSEL0_REG 0x0008
26 #define ISPSTART_REG 0x0014
27 #define ISPSTART_START 0xffff
28 #define ISPSTART_STOP 0x0000
30 #define ISPPROCMODE_DT_REG(n) (0x1100 + (0x4 * (n)))
31 #define ISPPROCMODE_DT_PROC_MODE_VC3(pm) (((pm) & 0x3f) << 24)
32 #define ISPPROCMODE_DT_PROC_MODE_VC2(pm) (((pm) & 0x3f) << 16)
33 #define ISPPROCMODE_DT_PROC_MODE_VC1(pm) (((pm) & 0x3f) << 8)
34 #define ISPPROCMODE_DT_PROC_MODE_VC0(pm) ((pm) & 0x3f)
36 #define ISPCS_FILTER_ID_CH_REG(n) (0x3000 + (0x0100 * (n)))
38 #define ISPCS_DT_CODE03_CH_REG(n) (0x3008 + (0x100 * (n)))
40 #define ISPCS_DT_CODE03_DT3(dt) (((dt) & 0x3f) << 24)
42 #define ISPCS_DT_CODE03_DT2(dt) (((dt) & 0x3f) << 16)
44 #define ISPCS_DT_CODE03_DT1(dt) (((dt) & 0x3f) << 8)
46 #define ISPCS_DT_CODE03_DT0(dt) ((dt) & 0x3f)
58 .procmode = 0x15
62 .procmode = 0x10,
66 .procmode = 0x0c,
70 .procmode = 0x0c,
74 .procmode = 0x0c,
78 .procmode = 0x0c,
82 .procmode = 0x00,
86 .procmode = 0x00,
90 .procmode = 0x00,
94 .procmode = 0x00,
98 .procmode = 0x01,
102 .procmode = 0x01,
106 .procmode = 0x01,
110 .procmode = 0x01,
114 .procmode = 0x02,
118 .procmode = 0x02,
122 .procmode = 0x02,
126 .procmode = 0x02,
134 for (i = 0; i < ARRAY_SIZE(rcar_isp_formats); i++) { in risp_code_to_fmt()
187 static void risp_write(struct rcar_isp *isp, u32 offset, u32 value) in risp_write() argument
189 iowrite32(value, isp->base + offset); in risp_write()
192 static u32 risp_read(struct rcar_isp *isp, u32 offset) in risp_read() argument
194 return ioread32(isp->base + offset); in risp_read()
197 static int risp_power_on(struct rcar_isp *isp) in risp_power_on() argument
201 ret = pm_runtime_resume_and_get(isp->dev); in risp_power_on()
202 if (ret < 0) in risp_power_on()
205 ret = reset_control_deassert(isp->rstc); in risp_power_on()
206 if (ret < 0) { in risp_power_on()
207 pm_runtime_put(isp->dev); in risp_power_on()
211 return 0; in risp_power_on()
214 static void risp_power_off(struct rcar_isp *isp) in risp_power_off() argument
216 reset_control_assert(isp->rstc); in risp_power_off()
217 pm_runtime_put(isp->dev); in risp_power_off()
220 static int risp_start(struct rcar_isp *isp, struct v4l2_subdev_state *state) in risp_start() argument
225 u32 sel_csi = 0; in risp_start()
230 return -EINVAL; in risp_start()
232 format = risp_code_to_fmt(fmt->code); in risp_start()
234 dev_err(isp->dev, "Unsupported bus format\n"); in risp_start()
235 return -EINVAL; in risp_start()
238 ret = risp_power_on(isp); in risp_start()
240 dev_err(isp->dev, "Failed to power on ISP\n"); in risp_start()
244 /* Select CSI-2 input source. */ in risp_start()
245 if (isp->csi_input == RISP_CSI_INPUT1) in risp_start()
248 risp_write(isp, ISPINPUTSEL0_REG, in risp_start()
249 risp_read(isp, ISPINPUTSEL0_REG) | sel_csi); in risp_start()
252 for (vc = 0; vc < 4; vc++) { in risp_start()
254 u8 dt = format->datatype; in risp_start()
256 risp_write(isp, ISPCS_FILTER_ID_CH_REG(ch), BIT(vc)); in risp_start()
257 risp_write(isp, ISPCS_DT_CODE03_CH_REG(ch), in risp_start()
265 risp_write(isp, ISPPROCMODE_DT_REG(format->datatype), in risp_start()
266 ISPPROCMODE_DT_PROC_MODE_VC3(format->procmode) | in risp_start()
267 ISPPROCMODE_DT_PROC_MODE_VC2(format->procmode) | in risp_start()
268 ISPPROCMODE_DT_PROC_MODE_VC1(format->procmode) | in risp_start()
269 ISPPROCMODE_DT_PROC_MODE_VC0(format->procmode)); in risp_start()
271 /* Start ISP. */ in risp_start()
272 risp_write(isp, ISPSTART_REG, ISPSTART_START); in risp_start()
274 ret = v4l2_subdev_enable_streams(isp->remote, isp->remote_pad, in risp_start()
275 BIT_ULL(0)); in risp_start()
277 risp_power_off(isp); in risp_start()
282 static void risp_stop(struct rcar_isp *isp) in risp_stop() argument
284 v4l2_subdev_disable_streams(isp->remote, isp->remote_pad, BIT_ULL(0)); in risp_stop()
286 /* Stop ISP. */ in risp_stop()
287 risp_write(isp, ISPSTART_REG, ISPSTART_STOP); in risp_stop()
289 risp_power_off(isp); in risp_stop()
296 struct rcar_isp *isp = sd_to_isp(sd); in risp_enable_streams() local
297 int ret = 0; in risp_enable_streams()
300 return -EINVAL; in risp_enable_streams()
302 if (!isp->remote) in risp_enable_streams()
303 return -ENODEV; in risp_enable_streams()
305 if (isp->stream_count == 0) { in risp_enable_streams()
306 ret = risp_start(isp, state); in risp_enable_streams()
311 isp->stream_count += 1; in risp_enable_streams()
320 struct rcar_isp *isp = sd_to_isp(sd); in risp_disable_streams() local
323 return -EINVAL; in risp_disable_streams()
325 if (!isp->remote) in risp_disable_streams()
326 return -ENODEV; in risp_disable_streams()
328 if (isp->stream_count == 1) in risp_disable_streams()
329 risp_stop(isp); in risp_disable_streams()
331 isp->stream_count -= 1; in risp_disable_streams()
333 return 0; in risp_disable_streams()
342 if (format->pad > RCAR_ISP_SINK) in risp_set_pad_format()
345 if (!risp_code_to_fmt(format->format.code)) in risp_set_pad_format()
346 format->format.code = rcar_isp_formats[0].code; in risp_set_pad_format()
348 for (unsigned int i = 0; i < RCAR_ISP_NUM_PADS; i++) { in risp_set_pad_format()
350 *framefmt = format->format; in risp_set_pad_format()
353 return 0; in risp_set_pad_format()
368 /* -----------------------------------------------------------------------------
376 struct rcar_isp *isp = notifier_to_isp(notifier); in risp_notify_bound() local
379 pad = media_entity_get_fwnode_pad(&subdev->entity, asd->match.fwnode, in risp_notify_bound()
381 if (pad < 0) { in risp_notify_bound()
382 dev_err(isp->dev, "Failed to find pad for %s\n", subdev->name); in risp_notify_bound()
386 isp->remote = subdev; in risp_notify_bound()
387 isp->remote_pad = pad; in risp_notify_bound()
389 dev_dbg(isp->dev, "Bound %s pad: %d\n", subdev->name, pad); in risp_notify_bound()
391 return media_create_pad_link(&subdev->entity, pad, in risp_notify_bound()
392 &isp->subdev.entity, 0, in risp_notify_bound()
401 struct rcar_isp *isp = notifier_to_isp(notifier); in risp_notify_unbind() local
403 isp->remote = NULL; in risp_notify_unbind()
405 dev_dbg(isp->dev, "Unbind %s\n", subdev->name); in risp_notify_unbind()
413 static int risp_parse_dt(struct rcar_isp *isp) in risp_parse_dt() argument
421 for (id = 0; id < 2; id++) { in risp_parse_dt()
422 ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(isp->dev), in risp_parse_dt()
423 0, id, 0); in risp_parse_dt()
429 dev_err(isp->dev, "Not connected to subdevice\n"); in risp_parse_dt()
430 return -EINVAL; in risp_parse_dt()
434 isp->csi_input = RISP_CSI_INPUT1; in risp_parse_dt()
439 dev_dbg(isp->dev, "Found '%pOF'\n", to_of_node(fwnode)); in risp_parse_dt()
441 v4l2_async_subdev_nf_init(&isp->notifier, &isp->subdev); in risp_parse_dt()
442 isp->notifier.ops = &risp_notify_ops; in risp_parse_dt()
444 asd = v4l2_async_nf_add_fwnode(&isp->notifier, fwnode, in risp_parse_dt()
450 ret = v4l2_async_nf_register(&isp->notifier); in risp_parse_dt()
452 v4l2_async_nf_cleanup(&isp->notifier); in risp_parse_dt()
457 /* -----------------------------------------------------------------------------
465 static int risp_probe_resources(struct rcar_isp *isp, in risp_probe_resources() argument
468 isp->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); in risp_probe_resources()
469 if (IS_ERR(isp->base)) in risp_probe_resources()
470 return PTR_ERR(isp->base); in risp_probe_resources()
472 isp->rstc = devm_reset_control_get(&pdev->dev, NULL); in risp_probe_resources()
474 return PTR_ERR_OR_ZERO(isp->rstc); in risp_probe_resources()
478 { .compatible = "renesas,r8a779a0-isp" },
479 { .compatible = "renesas,r8a779g0-isp" },
481 { .compatible = "renesas,rcar-gen4-isp" },
488 struct rcar_isp *isp; in risp_probe() local
492 isp = devm_kzalloc(&pdev->dev, sizeof(*isp), GFP_KERNEL); in risp_probe()
493 if (!isp) in risp_probe()
494 return -ENOMEM; in risp_probe()
496 isp->dev = &pdev->dev; in risp_probe()
498 ret = risp_probe_resources(isp, pdev); in risp_probe()
500 dev_err(isp->dev, "Failed to get resources\n"); in risp_probe()
504 platform_set_drvdata(pdev, isp); in risp_probe()
506 pm_runtime_enable(&pdev->dev); in risp_probe()
508 ret = risp_parse_dt(isp); in risp_probe()
512 isp->subdev.owner = THIS_MODULE; in risp_probe()
513 isp->subdev.dev = &pdev->dev; in risp_probe()
514 v4l2_subdev_init(&isp->subdev, &rcar_isp_subdev_ops); in risp_probe()
515 v4l2_set_subdevdata(&isp->subdev, &pdev->dev); in risp_probe()
516 snprintf(isp->subdev.name, sizeof(isp->subdev.name), "%s %s", in risp_probe()
517 KBUILD_MODNAME, dev_name(&pdev->dev)); in risp_probe()
518 isp->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; in risp_probe()
520 isp->subdev.entity.function = MEDIA_ENT_F_VID_MUX; in risp_probe()
521 isp->subdev.entity.ops = &risp_entity_ops; in risp_probe()
523 isp->pads[RCAR_ISP_SINK].flags = MEDIA_PAD_FL_SINK; in risp_probe()
525 isp->pads[i].flags = MEDIA_PAD_FL_SOURCE; in risp_probe()
527 ret = media_entity_pads_init(&isp->subdev.entity, RCAR_ISP_NUM_PADS, in risp_probe()
528 isp->pads); in risp_probe()
532 ret = v4l2_subdev_init_finalize(&isp->subdev); in risp_probe()
536 ret = v4l2_async_register_subdev(&isp->subdev); in risp_probe()
537 if (ret < 0) in risp_probe()
540 dev_info(isp->dev, "Using CSI-2 input: %u\n", isp->csi_input); in risp_probe()
542 return 0; in risp_probe()
545 v4l2_subdev_cleanup(&isp->subdev); in risp_probe()
547 v4l2_async_nf_unregister(&isp->notifier); in risp_probe()
548 v4l2_async_nf_cleanup(&isp->notifier); in risp_probe()
550 pm_runtime_disable(&pdev->dev); in risp_probe()
557 struct rcar_isp *isp = platform_get_drvdata(pdev); in risp_remove() local
559 v4l2_async_nf_unregister(&isp->notifier); in risp_remove()
560 v4l2_async_nf_cleanup(&isp->notifier); in risp_remove()
562 v4l2_async_unregister_subdev(&isp->subdev); in risp_remove()
563 v4l2_subdev_cleanup(&isp->subdev); in risp_remove()
565 pm_runtime_disable(&pdev->dev); in risp_remove()
570 .name = "rcar-isp",
581 MODULE_DESCRIPTION("Renesas R-Car ISP Channel Selector driver");