1 | // SPDX-License-Identifier: (GPL-2.0+ OR MIT) |
2 | /* |
3 | * Rockchip ISP1 Driver - Base driver |
4 | * |
5 | * Copyright (C) 2019 Collabora, Ltd. |
6 | * |
7 | * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd. |
8 | * Copyright (C) 2017 Rockchip Electronics Co., Ltd. |
9 | */ |
10 | |
11 | #include <linux/clk.h> |
12 | #include <linux/interrupt.h> |
13 | #include <linux/mfd/syscon.h> |
14 | #include <linux/module.h> |
15 | #include <linux/of.h> |
16 | #include <linux/of_graph.h> |
17 | #include <linux/platform_device.h> |
18 | #include <linux/pinctrl/consumer.h> |
19 | #include <linux/pm_runtime.h> |
20 | #include <media/v4l2-fwnode.h> |
21 | #include <media/v4l2-mc.h> |
22 | |
23 | #include "rkisp1-common.h" |
24 | #include "rkisp1-csi.h" |
25 | |
26 | /* |
27 | * ISP Details |
28 | * ----------- |
29 | * |
30 | * ISP Comprises with: |
31 | * MIPI serial camera interface |
32 | * Image Signal Processing |
33 | * Many Image Enhancement Blocks |
34 | * Crop |
35 | * Resizer |
36 | * RBG display ready image |
37 | * Image Rotation |
38 | * |
39 | * ISP Block Diagram |
40 | * ----------------- |
41 | * rkisp1-resizer.c rkisp1-capture.c |
42 | * |====================| |=======================| |
43 | * rkisp1-isp.c Main Picture Path |
44 | * |==========================| |===============================================| |
45 | * +-----------+ +--+--+--+--+ +--------+ +--------+ +-----------+ |
46 | * | | | | | | | | | | | | | |
47 | * +--------+ |\ | | | | | | | -->| Crop |->| RSZ |------------->| | |
48 | * | MIPI |--->| \ | | | | | | | | | | | | | | |
49 | * +--------+ | | | | |IE|IE|IE|IE| | +--------+ +--------+ | Memory | |
50 | * |MUX|--->| ISP |->|0 |1 |2 |3 |---+ | Interface | |
51 | * +--------+ | | | | | | | | | | +--------+ +--------+ +--------+ | | |
52 | * |Parallel|--->| / | | | | | | | | | | | | | | | | |
53 | * +--------+ |/ | | | | | | | -->| Crop |->| RSZ |->| RGB |->| | |
54 | * | | | | | | | | | | | | Rotate | | | |
55 | * +-----------+ +--+--+--+--+ +--------+ +--------+ +--------+ +-----------+ |
56 | * ^ |
57 | * +--------+ | |===============================================| |
58 | * | DMA |------------------------------------+ Self Picture Path |
59 | * +--------+ |
60 | * |
61 | * rkisp1-stats.c rkisp1-params.c |
62 | * |===============| |===============| |
63 | * +---------------+ +---------------+ |
64 | * | | | | |
65 | * | ISP | | ISP | |
66 | * | | | | |
67 | * +---------------+ +---------------+ |
68 | * |
69 | * |
70 | * Media Topology |
71 | * -------------- |
72 | * |
73 | * +----------+ +----------+ |
74 | * | Sensor 1 | | Sensor X | |
75 | * ------------ ... ------------ |
76 | * | 0 | | 0 | |
77 | * +----------+ +----------+ |
78 | * | | |
79 | * \----\ /----/ |
80 | * | | |
81 | * v v |
82 | * +-------------+ |
83 | * | 0 | |
84 | * --------------- |
85 | * | CSI-2 RX | |
86 | * --------------- +-----------+ |
87 | * | 1 | | params | |
88 | * +-------------+ | (output) | |
89 | * | +-----------+ |
90 | * v | |
91 | * +------+------+ | |
92 | * | 0 | 1 |<---------+ |
93 | * |------+------| |
94 | * | ISP | |
95 | * |------+------| |
96 | * +-------------| 2 | 3 |----------+ |
97 | * | +------+------+ | |
98 | * | | | |
99 | * v v v |
100 | * +- ---------+ +-----------+ +-----------+ |
101 | * | 0 | | 0 | | stats | |
102 | * ------------- ------------- | (capture) | |
103 | * | Resizer | | Resizer | +-----------+ |
104 | * ------------| ------------| |
105 | * | 1 | | 1 | |
106 | * +-----------+ +-----------+ |
107 | * | | |
108 | * v v |
109 | * +-----------+ +-----------+ |
110 | * | selfpath | | mainpath | |
111 | * | (capture) | | (capture) | |
112 | * +-----------+ +-----------+ |
113 | */ |
114 | |
115 | struct rkisp1_isr_data { |
116 | const char *name; |
117 | irqreturn_t (*isr)(int irq, void *ctx); |
118 | u32 line_mask; |
119 | }; |
120 | |
121 | /* ---------------------------------------------------------------------------- |
122 | * Sensor DT bindings |
123 | */ |
124 | |
125 | static int rkisp1_subdev_notifier_bound(struct v4l2_async_notifier *notifier, |
126 | struct v4l2_subdev *sd, |
127 | struct v4l2_async_connection *asc) |
128 | { |
129 | struct rkisp1_device *rkisp1 = |
130 | container_of(notifier, struct rkisp1_device, notifier); |
131 | struct rkisp1_sensor_async *s_asd = |
132 | container_of(asc, struct rkisp1_sensor_async, asd); |
133 | int source_pad; |
134 | int ret; |
135 | |
136 | s_asd->sd = sd; |
137 | |
138 | source_pad = media_entity_get_fwnode_pad(entity: &sd->entity, fwnode: s_asd->source_ep, |
139 | MEDIA_PAD_FL_SOURCE); |
140 | if (source_pad < 0) { |
141 | dev_err(rkisp1->dev, "failed to find source pad for %s\n" , |
142 | sd->name); |
143 | return source_pad; |
144 | } |
145 | |
146 | if (s_asd->port == 0) |
147 | return rkisp1_csi_link_sensor(rkisp1, sd, s_asd, source_pad); |
148 | |
149 | ret = media_create_pad_link(source: &sd->entity, source_pad, |
150 | sink: &rkisp1->isp.sd.entity, |
151 | sink_pad: RKISP1_ISP_PAD_SINK_VIDEO, |
152 | flags: !s_asd->index ? MEDIA_LNK_FL_ENABLED : 0); |
153 | if (ret) { |
154 | dev_err(rkisp1->dev, "failed to link source pad of %s\n" , |
155 | sd->name); |
156 | return ret; |
157 | } |
158 | |
159 | return 0; |
160 | } |
161 | |
162 | static int rkisp1_subdev_notifier_complete(struct v4l2_async_notifier *notifier) |
163 | { |
164 | struct rkisp1_device *rkisp1 = |
165 | container_of(notifier, struct rkisp1_device, notifier); |
166 | |
167 | return v4l2_device_register_subdev_nodes(v4l2_dev: &rkisp1->v4l2_dev); |
168 | } |
169 | |
170 | static void rkisp1_subdev_notifier_destroy(struct v4l2_async_connection *asc) |
171 | { |
172 | struct rkisp1_sensor_async *rk_asd = |
173 | container_of(asc, struct rkisp1_sensor_async, asd); |
174 | |
175 | fwnode_handle_put(fwnode: rk_asd->source_ep); |
176 | } |
177 | |
178 | static const struct v4l2_async_notifier_operations rkisp1_subdev_notifier_ops = { |
179 | .bound = rkisp1_subdev_notifier_bound, |
180 | .complete = rkisp1_subdev_notifier_complete, |
181 | .destroy = rkisp1_subdev_notifier_destroy, |
182 | }; |
183 | |
184 | static int rkisp1_subdev_notifier_register(struct rkisp1_device *rkisp1) |
185 | { |
186 | struct v4l2_async_notifier *ntf = &rkisp1->notifier; |
187 | struct fwnode_handle *fwnode = dev_fwnode(rkisp1->dev); |
188 | struct fwnode_handle *ep; |
189 | unsigned int index = 0; |
190 | int ret = 0; |
191 | |
192 | v4l2_async_nf_init(notifier: ntf, v4l2_dev: &rkisp1->v4l2_dev); |
193 | |
194 | ntf->ops = &rkisp1_subdev_notifier_ops; |
195 | |
196 | fwnode_graph_for_each_endpoint(fwnode, ep) { |
197 | struct fwnode_handle *port; |
198 | struct v4l2_fwnode_endpoint vep = { }; |
199 | struct rkisp1_sensor_async *rk_asd; |
200 | struct fwnode_handle *source; |
201 | u32 reg = 0; |
202 | |
203 | /* Select the bus type based on the port. */ |
204 | port = fwnode_get_parent(fwnode: ep); |
205 | fwnode_property_read_u32(fwnode: port, propname: "reg" , val: ®); |
206 | fwnode_handle_put(fwnode: port); |
207 | |
208 | switch (reg) { |
209 | case 0: |
210 | /* MIPI CSI-2 port */ |
211 | if (!rkisp1_has_feature(rkisp1, MIPI_CSI2)) { |
212 | dev_err(rkisp1->dev, |
213 | "internal CSI must be available for port 0\n" ); |
214 | ret = -EINVAL; |
215 | break; |
216 | } |
217 | |
218 | vep.bus_type = V4L2_MBUS_CSI2_DPHY; |
219 | break; |
220 | |
221 | case 1: |
222 | /* |
223 | * Parallel port. The bus-type property in DT is |
224 | * mandatory for port 1, it will be used to determine if |
225 | * it's PARALLEL or BT656. |
226 | */ |
227 | vep.bus_type = V4L2_MBUS_UNKNOWN; |
228 | break; |
229 | } |
230 | |
231 | /* Parse the endpoint and validate the bus type. */ |
232 | ret = v4l2_fwnode_endpoint_parse(fwnode: ep, vep: &vep); |
233 | if (ret) { |
234 | dev_err(rkisp1->dev, "failed to parse endpoint %pfw\n" , |
235 | ep); |
236 | break; |
237 | } |
238 | |
239 | if (vep.base.port == 1) { |
240 | if (vep.bus_type != V4L2_MBUS_PARALLEL && |
241 | vep.bus_type != V4L2_MBUS_BT656) { |
242 | dev_err(rkisp1->dev, |
243 | "port 1 must be parallel or BT656\n" ); |
244 | ret = -EINVAL; |
245 | break; |
246 | } |
247 | } |
248 | |
249 | /* Add the async subdev to the notifier. */ |
250 | source = fwnode_graph_get_remote_endpoint(fwnode: ep); |
251 | if (!source) { |
252 | dev_err(rkisp1->dev, |
253 | "endpoint %pfw has no remote endpoint\n" , |
254 | ep); |
255 | ret = -ENODEV; |
256 | break; |
257 | } |
258 | |
259 | rk_asd = v4l2_async_nf_add_fwnode(ntf, source, |
260 | struct rkisp1_sensor_async); |
261 | if (IS_ERR(ptr: rk_asd)) { |
262 | fwnode_handle_put(fwnode: source); |
263 | ret = PTR_ERR(ptr: rk_asd); |
264 | break; |
265 | } |
266 | |
267 | rk_asd->index = index++; |
268 | rk_asd->source_ep = source; |
269 | rk_asd->mbus_type = vep.bus_type; |
270 | rk_asd->port = vep.base.port; |
271 | |
272 | if (vep.bus_type == V4L2_MBUS_CSI2_DPHY) { |
273 | rk_asd->mbus_flags = vep.bus.mipi_csi2.flags; |
274 | rk_asd->lanes = vep.bus.mipi_csi2.num_data_lanes; |
275 | } else { |
276 | rk_asd->mbus_flags = vep.bus.parallel.flags; |
277 | } |
278 | |
279 | dev_dbg(rkisp1->dev, "registered ep id %d, bus type %u, %u lanes\n" , |
280 | vep.base.id, rk_asd->mbus_type, rk_asd->lanes); |
281 | } |
282 | |
283 | if (ret) { |
284 | fwnode_handle_put(fwnode: ep); |
285 | v4l2_async_nf_cleanup(notifier: ntf); |
286 | return ret; |
287 | } |
288 | |
289 | if (!index) |
290 | dev_dbg(rkisp1->dev, "no remote subdevice found\n" ); |
291 | |
292 | ret = v4l2_async_nf_register(notifier: ntf); |
293 | if (ret) { |
294 | v4l2_async_nf_cleanup(notifier: ntf); |
295 | return ret; |
296 | } |
297 | |
298 | return 0; |
299 | } |
300 | |
301 | /* ---------------------------------------------------------------------------- |
302 | * Power |
303 | */ |
304 | |
305 | static int __maybe_unused rkisp1_runtime_suspend(struct device *dev) |
306 | { |
307 | struct rkisp1_device *rkisp1 = dev_get_drvdata(dev); |
308 | |
309 | rkisp1->irqs_enabled = false; |
310 | /* Make sure the IRQ handler will see the above */ |
311 | mb(); |
312 | |
313 | /* |
314 | * Wait until any running IRQ handler has returned. The IRQ handler |
315 | * may get called even after this (as it's a shared interrupt line) |
316 | * but the 'irqs_enabled' flag will make the handler return immediately. |
317 | */ |
318 | for (unsigned int il = 0; il < ARRAY_SIZE(rkisp1->irqs); ++il) { |
319 | if (rkisp1->irqs[il] == -1) |
320 | continue; |
321 | |
322 | /* Skip if the irq line is the same as previous */ |
323 | if (il == 0 || rkisp1->irqs[il - 1] != rkisp1->irqs[il]) |
324 | synchronize_irq(irq: rkisp1->irqs[il]); |
325 | } |
326 | |
327 | clk_bulk_disable_unprepare(num_clks: rkisp1->clk_size, clks: rkisp1->clks); |
328 | return pinctrl_pm_select_sleep_state(dev); |
329 | } |
330 | |
331 | static int __maybe_unused rkisp1_runtime_resume(struct device *dev) |
332 | { |
333 | struct rkisp1_device *rkisp1 = dev_get_drvdata(dev); |
334 | int ret; |
335 | |
336 | ret = pinctrl_pm_select_default_state(dev); |
337 | if (ret) |
338 | return ret; |
339 | ret = clk_bulk_prepare_enable(num_clks: rkisp1->clk_size, clks: rkisp1->clks); |
340 | if (ret) |
341 | return ret; |
342 | |
343 | rkisp1->irqs_enabled = true; |
344 | /* Make sure the IRQ handler will see the above */ |
345 | mb(); |
346 | |
347 | return 0; |
348 | } |
349 | |
350 | static const struct dev_pm_ops rkisp1_pm_ops = { |
351 | SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, |
352 | pm_runtime_force_resume) |
353 | SET_RUNTIME_PM_OPS(rkisp1_runtime_suspend, rkisp1_runtime_resume, NULL) |
354 | }; |
355 | |
356 | /* ---------------------------------------------------------------------------- |
357 | * Core |
358 | */ |
359 | |
360 | static int rkisp1_create_links(struct rkisp1_device *rkisp1) |
361 | { |
362 | unsigned int dev_count = rkisp1_path_count(rkisp1); |
363 | unsigned int i; |
364 | int ret; |
365 | |
366 | if (rkisp1_has_feature(rkisp1, MIPI_CSI2)) { |
367 | /* Link the CSI receiver to the ISP. */ |
368 | ret = media_create_pad_link(source: &rkisp1->csi.sd.entity, |
369 | source_pad: RKISP1_CSI_PAD_SRC, |
370 | sink: &rkisp1->isp.sd.entity, |
371 | sink_pad: RKISP1_ISP_PAD_SINK_VIDEO, |
372 | MEDIA_LNK_FL_ENABLED); |
373 | if (ret) |
374 | return ret; |
375 | } |
376 | |
377 | /* create ISP->RSZ->CAP links */ |
378 | for (i = 0; i < dev_count; i++) { |
379 | struct media_entity *resizer = |
380 | &rkisp1->resizer_devs[i].sd.entity; |
381 | struct media_entity *capture = |
382 | &rkisp1->capture_devs[i].vnode.vdev.entity; |
383 | |
384 | ret = media_create_pad_link(source: &rkisp1->isp.sd.entity, |
385 | source_pad: RKISP1_ISP_PAD_SOURCE_VIDEO, |
386 | sink: resizer, sink_pad: RKISP1_RSZ_PAD_SINK, |
387 | MEDIA_LNK_FL_ENABLED); |
388 | if (ret) |
389 | return ret; |
390 | |
391 | ret = media_create_pad_link(source: resizer, source_pad: RKISP1_RSZ_PAD_SRC, |
392 | sink: capture, sink_pad: 0, |
393 | MEDIA_LNK_FL_ENABLED | |
394 | MEDIA_LNK_FL_IMMUTABLE); |
395 | if (ret) |
396 | return ret; |
397 | } |
398 | |
399 | /* params links */ |
400 | ret = media_create_pad_link(source: &rkisp1->params.vnode.vdev.entity, source_pad: 0, |
401 | sink: &rkisp1->isp.sd.entity, |
402 | sink_pad: RKISP1_ISP_PAD_SINK_PARAMS, |
403 | MEDIA_LNK_FL_ENABLED | |
404 | MEDIA_LNK_FL_IMMUTABLE); |
405 | if (ret) |
406 | return ret; |
407 | |
408 | /* 3A stats links */ |
409 | return media_create_pad_link(source: &rkisp1->isp.sd.entity, |
410 | source_pad: RKISP1_ISP_PAD_SOURCE_STATS, |
411 | sink: &rkisp1->stats.vnode.vdev.entity, sink_pad: 0, |
412 | MEDIA_LNK_FL_ENABLED | |
413 | MEDIA_LNK_FL_IMMUTABLE); |
414 | } |
415 | |
416 | static void rkisp1_entities_unregister(struct rkisp1_device *rkisp1) |
417 | { |
418 | if (rkisp1_has_feature(rkisp1, MIPI_CSI2)) |
419 | rkisp1_csi_unregister(rkisp1); |
420 | rkisp1_params_unregister(rkisp1); |
421 | rkisp1_stats_unregister(rkisp1); |
422 | rkisp1_capture_devs_unregister(rkisp1); |
423 | rkisp1_resizer_devs_unregister(rkisp1); |
424 | rkisp1_isp_unregister(rkisp1); |
425 | } |
426 | |
427 | static int rkisp1_entities_register(struct rkisp1_device *rkisp1) |
428 | { |
429 | int ret; |
430 | |
431 | ret = rkisp1_isp_register(rkisp1); |
432 | if (ret) |
433 | goto error; |
434 | |
435 | ret = rkisp1_resizer_devs_register(rkisp1); |
436 | if (ret) |
437 | goto error; |
438 | |
439 | ret = rkisp1_capture_devs_register(rkisp1); |
440 | if (ret) |
441 | goto error; |
442 | |
443 | ret = rkisp1_stats_register(rkisp1); |
444 | if (ret) |
445 | goto error; |
446 | |
447 | ret = rkisp1_params_register(rkisp1); |
448 | if (ret) |
449 | goto error; |
450 | |
451 | if (rkisp1_has_feature(rkisp1, MIPI_CSI2)) { |
452 | ret = rkisp1_csi_register(rkisp1); |
453 | if (ret) |
454 | goto error; |
455 | } |
456 | |
457 | ret = rkisp1_create_links(rkisp1); |
458 | if (ret) |
459 | goto error; |
460 | |
461 | return 0; |
462 | |
463 | error: |
464 | rkisp1_entities_unregister(rkisp1); |
465 | return ret; |
466 | } |
467 | |
468 | static irqreturn_t rkisp1_isr(int irq, void *ctx) |
469 | { |
470 | irqreturn_t ret = IRQ_NONE; |
471 | |
472 | /* |
473 | * Call rkisp1_capture_isr() first to handle the frame that |
474 | * potentially completed using the current frame_sequence number before |
475 | * it is potentially incremented by rkisp1_isp_isr() in the vertical |
476 | * sync. |
477 | */ |
478 | |
479 | if (rkisp1_capture_isr(irq, ctx) == IRQ_HANDLED) |
480 | ret = IRQ_HANDLED; |
481 | |
482 | if (rkisp1_isp_isr(irq, ctx) == IRQ_HANDLED) |
483 | ret = IRQ_HANDLED; |
484 | |
485 | if (rkisp1_csi_isr(irq, ctx) == IRQ_HANDLED) |
486 | ret = IRQ_HANDLED; |
487 | |
488 | return ret; |
489 | } |
490 | |
491 | static const char * const px30_isp_clks[] = { |
492 | "isp" , |
493 | "aclk" , |
494 | "hclk" , |
495 | "pclk" , |
496 | }; |
497 | |
498 | static const struct rkisp1_isr_data px30_isp_isrs[] = { |
499 | { "isp" , rkisp1_isp_isr, BIT(RKISP1_IRQ_ISP) }, |
500 | { "mi" , rkisp1_capture_isr, BIT(RKISP1_IRQ_MI) }, |
501 | { "mipi" , rkisp1_csi_isr, BIT(RKISP1_IRQ_MIPI) }, |
502 | }; |
503 | |
504 | static const struct rkisp1_info px30_isp_info = { |
505 | .clks = px30_isp_clks, |
506 | .clk_size = ARRAY_SIZE(px30_isp_clks), |
507 | .isrs = px30_isp_isrs, |
508 | .isr_size = ARRAY_SIZE(px30_isp_isrs), |
509 | .isp_ver = RKISP1_V12, |
510 | .features = RKISP1_FEATURE_MIPI_CSI2 |
511 | | RKISP1_FEATURE_SELF_PATH |
512 | | RKISP1_FEATURE_DUAL_CROP, |
513 | }; |
514 | |
515 | static const char * const rk3399_isp_clks[] = { |
516 | "isp" , |
517 | "aclk" , |
518 | "hclk" , |
519 | }; |
520 | |
521 | static const struct rkisp1_isr_data rk3399_isp_isrs[] = { |
522 | { NULL, rkisp1_isr, BIT(RKISP1_IRQ_ISP) | BIT(RKISP1_IRQ_MI) | BIT(RKISP1_IRQ_MIPI) }, |
523 | }; |
524 | |
525 | static const struct rkisp1_info rk3399_isp_info = { |
526 | .clks = rk3399_isp_clks, |
527 | .clk_size = ARRAY_SIZE(rk3399_isp_clks), |
528 | .isrs = rk3399_isp_isrs, |
529 | .isr_size = ARRAY_SIZE(rk3399_isp_isrs), |
530 | .isp_ver = RKISP1_V10, |
531 | .features = RKISP1_FEATURE_MIPI_CSI2 |
532 | | RKISP1_FEATURE_SELF_PATH |
533 | | RKISP1_FEATURE_DUAL_CROP, |
534 | }; |
535 | |
536 | static const char * const imx8mp_isp_clks[] = { |
537 | "isp" , |
538 | "hclk" , |
539 | "aclk" , |
540 | }; |
541 | |
542 | static const struct rkisp1_isr_data imx8mp_isp_isrs[] = { |
543 | { NULL, rkisp1_isr, BIT(RKISP1_IRQ_ISP) | BIT(RKISP1_IRQ_MI) }, |
544 | }; |
545 | |
546 | static const struct rkisp1_info imx8mp_isp_info = { |
547 | .clks = imx8mp_isp_clks, |
548 | .clk_size = ARRAY_SIZE(imx8mp_isp_clks), |
549 | .isrs = imx8mp_isp_isrs, |
550 | .isr_size = ARRAY_SIZE(imx8mp_isp_isrs), |
551 | .isp_ver = RKISP1_V_IMX8MP, |
552 | .features = RKISP1_FEATURE_MAIN_STRIDE |
553 | | RKISP1_FEATURE_DMA_34BIT, |
554 | }; |
555 | |
556 | static const struct of_device_id rkisp1_of_match[] = { |
557 | { |
558 | .compatible = "rockchip,px30-cif-isp" , |
559 | .data = &px30_isp_info, |
560 | }, |
561 | { |
562 | .compatible = "rockchip,rk3399-cif-isp" , |
563 | .data = &rk3399_isp_info, |
564 | }, |
565 | { |
566 | .compatible = "fsl,imx8mp-isp" , |
567 | .data = &imx8mp_isp_info, |
568 | }, |
569 | {}, |
570 | }; |
571 | MODULE_DEVICE_TABLE(of, rkisp1_of_match); |
572 | |
573 | static int rkisp1_probe(struct platform_device *pdev) |
574 | { |
575 | const struct rkisp1_info *info; |
576 | struct device *dev = &pdev->dev; |
577 | struct rkisp1_device *rkisp1; |
578 | struct v4l2_device *v4l2_dev; |
579 | unsigned int i; |
580 | u64 dma_mask; |
581 | int ret, irq; |
582 | u32 cif_id; |
583 | |
584 | rkisp1 = devm_kzalloc(dev, size: sizeof(*rkisp1), GFP_KERNEL); |
585 | if (!rkisp1) |
586 | return -ENOMEM; |
587 | |
588 | info = of_device_get_match_data(dev); |
589 | rkisp1->info = info; |
590 | |
591 | dev_set_drvdata(dev, data: rkisp1); |
592 | rkisp1->dev = dev; |
593 | |
594 | dma_mask = rkisp1_has_feature(rkisp1, DMA_34BIT) ? DMA_BIT_MASK(34) : |
595 | DMA_BIT_MASK(32); |
596 | |
597 | ret = dma_set_mask_and_coherent(dev, mask: dma_mask); |
598 | if (ret) |
599 | return ret; |
600 | |
601 | mutex_init(&rkisp1->stream_lock); |
602 | |
603 | rkisp1->base_addr = devm_platform_ioremap_resource(pdev, index: 0); |
604 | if (IS_ERR(ptr: rkisp1->base_addr)) |
605 | return PTR_ERR(ptr: rkisp1->base_addr); |
606 | |
607 | for (unsigned int il = 0; il < ARRAY_SIZE(rkisp1->irqs); ++il) |
608 | rkisp1->irqs[il] = -1; |
609 | |
610 | for (i = 0; i < info->isr_size; i++) { |
611 | irq = info->isrs[i].name |
612 | ? platform_get_irq_byname(pdev, info->isrs[i].name) |
613 | : platform_get_irq(pdev, i); |
614 | if (irq < 0) |
615 | return irq; |
616 | |
617 | for (unsigned int il = 0; il < ARRAY_SIZE(rkisp1->irqs); ++il) { |
618 | if (info->isrs[i].line_mask & BIT(il)) |
619 | rkisp1->irqs[il] = irq; |
620 | } |
621 | |
622 | ret = devm_request_irq(dev, irq, handler: info->isrs[i].isr, IRQF_SHARED, |
623 | devname: dev_driver_string(dev), dev_id: dev); |
624 | if (ret) { |
625 | dev_err(dev, "request irq failed: %d\n" , ret); |
626 | return ret; |
627 | } |
628 | } |
629 | |
630 | for (i = 0; i < info->clk_size; i++) |
631 | rkisp1->clks[i].id = info->clks[i]; |
632 | ret = devm_clk_bulk_get(dev, num_clks: info->clk_size, clks: rkisp1->clks); |
633 | if (ret) |
634 | return ret; |
635 | rkisp1->clk_size = info->clk_size; |
636 | |
637 | if (info->isp_ver == RKISP1_V_IMX8MP) { |
638 | unsigned int id; |
639 | |
640 | rkisp1->gasket = syscon_regmap_lookup_by_phandle_args(np: dev->of_node, |
641 | property: "fsl,blk-ctrl" , |
642 | arg_count: 1, out_args: &id); |
643 | if (IS_ERR(ptr: rkisp1->gasket)) { |
644 | ret = PTR_ERR(ptr: rkisp1->gasket); |
645 | dev_err(dev, "failed to get gasket: %d\n" , ret); |
646 | return ret; |
647 | } |
648 | |
649 | rkisp1->gasket_id = id; |
650 | } |
651 | |
652 | pm_runtime_enable(dev: &pdev->dev); |
653 | |
654 | ret = pm_runtime_resume_and_get(dev: &pdev->dev); |
655 | if (ret) |
656 | goto err_pm_runtime_disable; |
657 | |
658 | cif_id = rkisp1_read(rkisp1, RKISP1_CIF_VI_ID); |
659 | dev_dbg(rkisp1->dev, "CIF_ID 0x%08x\n" , cif_id); |
660 | |
661 | pm_runtime_put(dev: &pdev->dev); |
662 | |
663 | rkisp1->media_dev.hw_revision = info->isp_ver; |
664 | strscpy(rkisp1->media_dev.model, RKISP1_DRIVER_NAME, |
665 | sizeof(rkisp1->media_dev.model)); |
666 | rkisp1->media_dev.dev = &pdev->dev; |
667 | strscpy(rkisp1->media_dev.bus_info, RKISP1_BUS_INFO, |
668 | sizeof(rkisp1->media_dev.bus_info)); |
669 | media_device_init(mdev: &rkisp1->media_dev); |
670 | |
671 | v4l2_dev = &rkisp1->v4l2_dev; |
672 | v4l2_dev->mdev = &rkisp1->media_dev; |
673 | strscpy(v4l2_dev->name, RKISP1_DRIVER_NAME, sizeof(v4l2_dev->name)); |
674 | |
675 | ret = v4l2_device_register(dev: rkisp1->dev, v4l2_dev: &rkisp1->v4l2_dev); |
676 | if (ret) |
677 | goto err_media_dev_cleanup; |
678 | |
679 | ret = media_device_register(&rkisp1->media_dev); |
680 | if (ret) { |
681 | dev_err(dev, "Failed to register media device: %d\n" , ret); |
682 | goto err_unreg_v4l2_dev; |
683 | } |
684 | |
685 | if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2) { |
686 | ret = rkisp1_csi_init(rkisp1); |
687 | if (ret) |
688 | goto err_unreg_media_dev; |
689 | } |
690 | |
691 | ret = rkisp1_entities_register(rkisp1); |
692 | if (ret) |
693 | goto err_cleanup_csi; |
694 | |
695 | ret = rkisp1_subdev_notifier_register(rkisp1); |
696 | if (ret) |
697 | goto err_unreg_entities; |
698 | |
699 | rkisp1_debug_init(rkisp1); |
700 | |
701 | return 0; |
702 | |
703 | err_unreg_entities: |
704 | rkisp1_entities_unregister(rkisp1); |
705 | err_cleanup_csi: |
706 | if (rkisp1_has_feature(rkisp1, MIPI_CSI2)) |
707 | rkisp1_csi_cleanup(rkisp1); |
708 | err_unreg_media_dev: |
709 | media_device_unregister(mdev: &rkisp1->media_dev); |
710 | err_unreg_v4l2_dev: |
711 | v4l2_device_unregister(v4l2_dev: &rkisp1->v4l2_dev); |
712 | err_media_dev_cleanup: |
713 | media_device_cleanup(mdev: &rkisp1->media_dev); |
714 | err_pm_runtime_disable: |
715 | pm_runtime_disable(dev: &pdev->dev); |
716 | return ret; |
717 | } |
718 | |
719 | static void rkisp1_remove(struct platform_device *pdev) |
720 | { |
721 | struct rkisp1_device *rkisp1 = platform_get_drvdata(pdev); |
722 | |
723 | v4l2_async_nf_unregister(notifier: &rkisp1->notifier); |
724 | v4l2_async_nf_cleanup(notifier: &rkisp1->notifier); |
725 | |
726 | rkisp1_entities_unregister(rkisp1); |
727 | if (rkisp1_has_feature(rkisp1, MIPI_CSI2)) |
728 | rkisp1_csi_cleanup(rkisp1); |
729 | rkisp1_debug_cleanup(rkisp1); |
730 | |
731 | media_device_unregister(mdev: &rkisp1->media_dev); |
732 | v4l2_device_unregister(v4l2_dev: &rkisp1->v4l2_dev); |
733 | |
734 | media_device_cleanup(mdev: &rkisp1->media_dev); |
735 | |
736 | pm_runtime_disable(dev: &pdev->dev); |
737 | } |
738 | |
739 | static struct platform_driver rkisp1_drv = { |
740 | .driver = { |
741 | .name = RKISP1_DRIVER_NAME, |
742 | .of_match_table = of_match_ptr(rkisp1_of_match), |
743 | .pm = &rkisp1_pm_ops, |
744 | }, |
745 | .probe = rkisp1_probe, |
746 | .remove_new = rkisp1_remove, |
747 | }; |
748 | |
749 | module_platform_driver(rkisp1_drv); |
750 | MODULE_DESCRIPTION("Rockchip ISP1 platform driver" ); |
751 | MODULE_LICENSE("Dual MIT/GPL" ); |
752 | |