xref: /linux/drivers/media/platform/arm/mali-c55/mali-c55-core.c (revision 24f171c7e145f43b9f187578e89b0982ce87e54c)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * ARM Mali-C55 ISP Driver - Core driver code
4  *
5  * Copyright (C) 2025 Ideas on Board Oy
6  */
7 
8 #include <linux/bitops.h>
9 #include <linux/cleanup.h>
10 #include <linux/clk.h>
11 #include <linux/delay.h>
12 #include <linux/device.h>
13 #include <linux/interrupt.h>
14 #include <linux/iopoll.h>
15 #include <linux/ioport.h>
16 #include <linux/mod_devicetable.h>
17 #include <linux/of.h>
18 #include <linux/of_reserved_mem.h>
19 #include <linux/platform_device.h>
20 #include <linux/pm_runtime.h>
21 #include <linux/reset.h>
22 #include <linux/slab.h>
23 #include <linux/string.h>
24 
25 #include <media/media-entity.h>
26 #include <media/v4l2-device.h>
27 #include <media/v4l2-mc.h>
28 #include <media/videobuf2-core.h>
29 #include <media/videobuf2-dma-contig.h>
30 
31 #include "mali-c55-common.h"
32 #include "mali-c55-registers.h"
33 
34 static const char * const mali_c55_interrupt_names[] = {
35 	[MALI_C55_IRQ_ISP_START] = "ISP start",
36 	[MALI_C55_IRQ_ISP_DONE] = "ISP done",
37 	[MALI_C55_IRQ_MCM_ERROR] = "Multi-context management error",
38 	[MALI_C55_IRQ_BROKEN_FRAME_ERROR] = "Broken frame error",
39 	[MALI_C55_IRQ_MET_AF_DONE] = "AF metering done",
40 	[MALI_C55_IRQ_MET_AEXP_DONE] = "AEXP metering done",
41 	[MALI_C55_IRQ_MET_AWB_DONE] = "AWB metering done",
42 	[MALI_C55_IRQ_AEXP_1024_DONE] = "AEXP 1024-bit histogram done",
43 	[MALI_C55_IRQ_IRIDIX_MET_DONE] = "Iridix metering done",
44 	[MALI_C55_IRQ_LUT_INIT_DONE] = "LUT memory init done",
45 	[MALI_C55_IRQ_FR_Y_DONE] = "Full resolution Y plane DMA done",
46 	[MALI_C55_IRQ_FR_UV_DONE] = "Full resolution U/V plane DMA done",
47 	[MALI_C55_IRQ_DS_Y_DONE] = "Downscale Y plane DMA done",
48 	[MALI_C55_IRQ_DS_UV_DONE] = "Downscale U/V plane DMA done",
49 	[MALI_C55_IRQ_LINEARIZATION_DONE] = "Linearisation done",
50 	[MALI_C55_IRQ_RAW_FRONTEND_DONE] = "Raw frontend processing done",
51 	[MALI_C55_IRQ_NOISE_REDUCTION_DONE] = "Noise reduction done",
52 	[MALI_C55_IRQ_IRIDIX_DONE] = "Iridix done",
53 	[MALI_C55_IRQ_BAYER2RGB_DONE] = "Bayer to RGB conversion done",
54 	[MALI_C55_IRQ_WATCHDOG_TIMER] = "Watchdog timer timed out",
55 	[MALI_C55_IRQ_FRAME_COLLISION] = "Frame collision error",
56 	[MALI_C55_IRQ_UNUSED] = "IRQ bit unused",
57 	[MALI_C55_IRQ_DMA_ERROR] = "DMA error",
58 	[MALI_C55_IRQ_INPUT_STOPPED] = "Input port safely stopped",
59 	[MALI_C55_IRQ_MET_AWB_TARGET1_HIT] = "AWB metering target 1 address hit",
60 	[MALI_C55_IRQ_MET_AWB_TARGET2_HIT] = "AWB metering target 2 address hit"
61 };
62 
63 static const unsigned int config_space_addrs[] = {
64 	[MALI_C55_CONFIG_PING] = 0x0ab6c,
65 	[MALI_C55_CONFIG_PONG] = 0x22b2c,
66 };
67 
68 static const char * const mali_c55_clk_names[MALI_C55_NUM_CLKS] = {
69 	"vclk",
70 	"aclk",
71 	"hclk",
72 };
73 
74 static const char * const mali_c55_reset_names[MALI_C55_NUM_RESETS] = {
75 	"vresetn",
76 	"aresetn",
77 	"hresetn",
78 };
79 
80 /*
81  * System IO
82  *
83  * The Mali-C55 ISP has up to two configuration register spaces (called 'ping'
84  * and 'pong'), with the expectation that the 'active' space will be left
85  * untouched whilst a frame is being processed and the 'inactive' space
86  * configured ready to be switched to during the blanking period before the next
87  * frame processing starts. These spaces should ideally be set via DMA transfer
88  * from a buffer rather than through individual register set operations. There
89  * is also a shared global register space which should be set normally. For now
90  * though we will simply use a CPU write and target DMA transfers of the config
91  * space in the future.
92  *
93  * As groundwork for that path any read/write call that is made to an address
94  * within those config spaces should infact be directed to a buffer that was
95  * allocated to hold them rather than the IO memory itself. The actual copy of
96  * that buffer to IO mem will happen on interrupt.
97  */
98 
99 void mali_c55_write(struct mali_c55 *mali_c55, unsigned int addr, u32 val)
100 {
101 	WARN_ON(addr >= MALI_C55_REG_CONFIG_SPACES_OFFSET);
102 
103 	writel(val, mali_c55->base + addr);
104 }
105 
106 u32 mali_c55_read(struct mali_c55 *mali_c55, unsigned int addr)
107 {
108 	WARN_ON(addr >= MALI_C55_REG_CONFIG_SPACES_OFFSET);
109 
110 	return readl(mali_c55->base + addr);
111 }
112 
113 void mali_c55_update_bits(struct mali_c55 *mali_c55, unsigned int addr,
114 			  u32 mask, u32 val)
115 {
116 	u32 orig, new;
117 
118 	orig = mali_c55_read(mali_c55, addr);
119 
120 	new = orig & ~mask;
121 	new |= val & mask;
122 
123 	if (new != orig)
124 		mali_c55_write(mali_c55, addr, new);
125 }
126 
127 static void __mali_c55_ctx_write(struct mali_c55_context *ctx,
128 				 unsigned int addr, u32 val)
129 {
130 	addr = (addr - MALI_C55_REG_CONFIG_SPACES_OFFSET) / 4;
131 	ctx->registers[addr] = val;
132 }
133 
134 void mali_c55_ctx_write(struct mali_c55 *mali_c55, unsigned int addr, u32 val)
135 {
136 	struct mali_c55_context *ctx = mali_c55_get_active_context(mali_c55);
137 
138 	WARN_ON(addr < MALI_C55_REG_CONFIG_SPACES_OFFSET);
139 
140 	spin_lock(&ctx->lock);
141 	__mali_c55_ctx_write(ctx, addr, val);
142 	spin_unlock(&ctx->lock);
143 }
144 
145 static u32 __mali_c55_ctx_read(struct mali_c55_context *ctx, unsigned int addr)
146 {
147 	addr = (addr - MALI_C55_REG_CONFIG_SPACES_OFFSET) / 4;
148 	return ctx->registers[addr];
149 }
150 
151 u32 mali_c55_ctx_read(struct mali_c55 *mali_c55, unsigned int addr)
152 {
153 	struct mali_c55_context *ctx = mali_c55_get_active_context(mali_c55);
154 	u32 val;
155 
156 	WARN_ON(addr < MALI_C55_REG_CONFIG_SPACES_OFFSET);
157 
158 	spin_lock(&ctx->lock);
159 	val = __mali_c55_ctx_read(ctx, addr);
160 	spin_unlock(&ctx->lock);
161 
162 	return val;
163 }
164 
165 void mali_c55_ctx_update_bits(struct mali_c55 *mali_c55, unsigned int addr,
166 			      u32 mask, u32 val)
167 {
168 	struct mali_c55_context *ctx = mali_c55_get_active_context(mali_c55);
169 	u32 orig, tmp;
170 
171 	WARN_ON(addr < MALI_C55_REG_CONFIG_SPACES_OFFSET);
172 
173 	spin_lock(&ctx->lock);
174 
175 	orig = __mali_c55_ctx_read(ctx, addr);
176 
177 	tmp = orig & ~mask;
178 	tmp |= val & mask;
179 
180 	if (tmp != orig)
181 		__mali_c55_ctx_write(ctx, addr, tmp);
182 
183 	spin_unlock(&ctx->lock);
184 }
185 
186 int mali_c55_config_write(struct mali_c55_context *ctx,
187 			  enum mali_c55_config_spaces cfg_space,
188 			  bool force_synchronous)
189 {
190 	struct mali_c55 *mali_c55 = ctx->mali_c55;
191 
192 	memcpy_toio(mali_c55->base + config_space_addrs[cfg_space],
193 		    ctx->registers, MALI_C55_CONFIG_SPACE_SIZE);
194 
195 	return 0;
196 }
197 
198 struct mali_c55_context *mali_c55_get_active_context(struct mali_c55 *mali_c55)
199 {
200 	return &mali_c55->context;
201 }
202 
203 static void mali_c55_remove_links(struct mali_c55 *mali_c55)
204 {
205 	unsigned int i;
206 
207 	media_entity_remove_links(&mali_c55->tpg.sd.entity);
208 	media_entity_remove_links(&mali_c55->isp.sd.entity);
209 
210 	for (i = 0; i < MALI_C55_NUM_RSZS; i++)
211 		media_entity_remove_links(&mali_c55->resizers[i].sd.entity);
212 
213 	for (i = 0; i < MALI_C55_NUM_CAP_DEVS; i++)
214 		media_entity_remove_links(&mali_c55->cap_devs[i].vdev.entity);
215 }
216 
217 static int mali_c55_create_links(struct mali_c55 *mali_c55)
218 {
219 	int ret;
220 
221 	/* Test pattern generator to ISP */
222 	ret = media_create_pad_link(&mali_c55->tpg.sd.entity, 0,
223 				    &mali_c55->isp.sd.entity,
224 				    MALI_C55_ISP_PAD_SINK_VIDEO, 0);
225 	if (ret) {
226 		dev_err(mali_c55->dev, "failed to link TPG and ISP\n");
227 		goto err_remove_links;
228 	}
229 
230 	/* Full resolution resizer pipe. */
231 	ret = media_create_pad_link(&mali_c55->isp.sd.entity,
232 			MALI_C55_ISP_PAD_SOURCE_VIDEO,
233 			&mali_c55->resizers[MALI_C55_RSZ_FR].sd.entity,
234 			MALI_C55_RSZ_SINK_PAD,
235 			MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
236 	if (ret) {
237 		dev_err(mali_c55->dev, "failed to link ISP and FR resizer\n");
238 		goto err_remove_links;
239 	}
240 
241 	/* Full resolution bypass. */
242 	ret = media_create_pad_link(&mali_c55->isp.sd.entity,
243 				    MALI_C55_ISP_PAD_SOURCE_BYPASS,
244 				    &mali_c55->resizers[MALI_C55_RSZ_FR].sd.entity,
245 				    MALI_C55_RSZ_SINK_BYPASS_PAD,
246 				    MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
247 	if (ret) {
248 		dev_err(mali_c55->dev, "failed to link ISP and FR resizer\n");
249 		goto err_remove_links;
250 	}
251 
252 	/* Resizer pipe to video capture nodes. */
253 	ret = media_create_pad_link(&mali_c55->resizers[0].sd.entity,
254 			MALI_C55_RSZ_SOURCE_PAD,
255 			&mali_c55->cap_devs[MALI_C55_CAP_DEV_FR].vdev.entity,
256 			0, MEDIA_LNK_FL_ENABLED);
257 	if (ret) {
258 		dev_err(mali_c55->dev,
259 			"failed to link FR resizer and video device\n");
260 		goto err_remove_links;
261 	}
262 
263 	/* The downscale pipe is an optional hardware block */
264 	if (mali_c55->capabilities & MALI_C55_GPS_DS_PIPE_FITTED) {
265 		ret = media_create_pad_link(&mali_c55->isp.sd.entity,
266 			MALI_C55_ISP_PAD_SOURCE_VIDEO,
267 			&mali_c55->resizers[MALI_C55_RSZ_DS].sd.entity,
268 			MALI_C55_RSZ_SINK_PAD,
269 			MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
270 		if (ret) {
271 			dev_err(mali_c55->dev,
272 				"failed to link ISP and DS resizer\n");
273 			goto err_remove_links;
274 		}
275 
276 		ret = media_create_pad_link(&mali_c55->resizers[1].sd.entity,
277 			MALI_C55_RSZ_SOURCE_PAD,
278 			&mali_c55->cap_devs[MALI_C55_CAP_DEV_DS].vdev.entity,
279 			0, MEDIA_LNK_FL_ENABLED);
280 		if (ret) {
281 			dev_err(mali_c55->dev,
282 				"failed to link DS resizer and video device\n");
283 			goto err_remove_links;
284 		}
285 	}
286 
287 	ret = media_create_pad_link(&mali_c55->isp.sd.entity,
288 				    MALI_C55_ISP_PAD_SOURCE_STATS,
289 				    &mali_c55->stats.vdev.entity, 0,
290 				    MEDIA_LNK_FL_ENABLED);
291 	if (ret) {
292 		dev_err(mali_c55->dev,
293 			"failed to link ISP and 3a stats node\n");
294 		goto err_remove_links;
295 	}
296 
297 	ret = media_create_pad_link(&mali_c55->params.vdev.entity, 0,
298 				    &mali_c55->isp.sd.entity,
299 				    MALI_C55_ISP_PAD_SINK_PARAMS,
300 				    MEDIA_LNK_FL_ENABLED);
301 	if (ret) {
302 		dev_err(mali_c55->dev,
303 			"failed to link ISP and parameters video node\n");
304 		goto err_remove_links;
305 	}
306 
307 	return 0;
308 
309 err_remove_links:
310 	mali_c55_remove_links(mali_c55);
311 	return ret;
312 }
313 
314 static void mali_c55_unregister_entities(struct mali_c55 *mali_c55)
315 {
316 	mali_c55_remove_links(mali_c55);
317 	mali_c55_unregister_tpg(mali_c55);
318 	mali_c55_unregister_isp(mali_c55);
319 	mali_c55_unregister_resizers(mali_c55);
320 	mali_c55_unregister_capture_devs(mali_c55);
321 	mali_c55_unregister_params(mali_c55);
322 	mali_c55_unregister_stats(mali_c55);
323 }
324 
325 static void mali_c55_swap_next_config(struct mali_c55 *mali_c55)
326 {
327 	struct mali_c55_context *ctx = mali_c55_get_active_context(mali_c55);
328 
329 	mali_c55_config_write(ctx, mali_c55->next_config ?
330 			      MALI_C55_CONFIG_PING : MALI_C55_CONFIG_PONG,
331 			      false);
332 
333 	mali_c55_update_bits(mali_c55, MALI_C55_REG_MCU_CONFIG,
334 		MALI_C55_REG_MCU_CONFIG_WRITE_MASK,
335 		MALI_C55_MCU_CONFIG_WRITE(mali_c55->next_config));
336 }
337 
338 static int mali_c55_register_entities(struct mali_c55 *mali_c55)
339 {
340 	int ret;
341 
342 	ret = mali_c55_register_tpg(mali_c55);
343 	if (ret)
344 		return ret;
345 
346 	ret = mali_c55_register_isp(mali_c55);
347 	if (ret)
348 		goto err_unregister_entities;
349 
350 	ret = mali_c55_register_resizers(mali_c55);
351 	if (ret)
352 		goto err_unregister_entities;
353 
354 	ret = mali_c55_register_capture_devs(mali_c55);
355 	if (ret)
356 		goto err_unregister_entities;
357 
358 	ret = mali_c55_register_params(mali_c55);
359 	if (ret)
360 		goto err_unregister_entities;
361 
362 	ret = mali_c55_register_stats(mali_c55);
363 	if (ret)
364 		goto err_unregister_entities;
365 
366 	ret = mali_c55_create_links(mali_c55);
367 	if (ret)
368 		goto err_unregister_entities;
369 
370 	return 0;
371 
372 err_unregister_entities:
373 	mali_c55_unregister_entities(mali_c55);
374 
375 	return ret;
376 }
377 
378 static int mali_c55_notifier_bound(struct v4l2_async_notifier *notifier,
379 				   struct v4l2_subdev *subdev,
380 				   struct v4l2_async_connection *asc)
381 {
382 	struct mali_c55 *mali_c55 = container_of(notifier,
383 						struct mali_c55, notifier);
384 	struct media_pad *pad = &mali_c55->isp.pads[MALI_C55_ISP_PAD_SINK_VIDEO];
385 	int ret;
386 
387 	/*
388 	 * By default we'll flag this link enabled and the TPG disabled, but
389 	 * no immutable flag because we need to be able to switch between the
390 	 * two.
391 	 */
392 	ret = v4l2_create_fwnode_links_to_pad(subdev, pad,
393 					      MEDIA_LNK_FL_ENABLED);
394 	if (ret)
395 		dev_err(mali_c55->dev, "failed to create link for %s\n",
396 			subdev->name);
397 
398 	return ret;
399 }
400 
401 static int mali_c55_notifier_complete(struct v4l2_async_notifier *notifier)
402 {
403 	struct mali_c55 *mali_c55 = container_of(notifier,
404 						struct mali_c55, notifier);
405 
406 	return v4l2_device_register_subdev_nodes(&mali_c55->v4l2_dev);
407 }
408 
409 static const struct v4l2_async_notifier_operations mali_c55_notifier_ops = {
410 	.bound = mali_c55_notifier_bound,
411 	.complete = mali_c55_notifier_complete,
412 };
413 
414 static int mali_c55_parse_endpoint(struct mali_c55 *mali_c55)
415 {
416 	struct v4l2_async_connection *asc;
417 	struct fwnode_handle *ep;
418 
419 	/*
420 	 * The ISP should have a single endpoint pointing to some flavour of
421 	 * CSI-2 receiver...but for now at least we do want everything to work
422 	 * normally even with no sensors connected, as we have the TPG. If we
423 	 * don't find a sensor just warn and return success.
424 	 */
425 	ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(mali_c55->dev),
426 					     0, 0, 0);
427 	if (!ep) {
428 		dev_warn(mali_c55->dev, "no local endpoint found\n");
429 		return 0;
430 	}
431 
432 	asc = v4l2_async_nf_add_fwnode_remote(&mali_c55->notifier, ep,
433 					      struct v4l2_async_connection);
434 	fwnode_handle_put(ep);
435 	if (IS_ERR(asc)) {
436 		dev_err(mali_c55->dev, "failed to add remote fwnode\n");
437 		return PTR_ERR(asc);
438 	}
439 
440 	return 0;
441 }
442 
443 static int mali_c55_media_frameworks_init(struct mali_c55 *mali_c55)
444 {
445 	int ret;
446 
447 	strscpy(mali_c55->media_dev.model, "ARM Mali-C55 ISP",
448 		sizeof(mali_c55->media_dev.model));
449 
450 	media_device_init(&mali_c55->media_dev);
451 
452 	ret = media_device_register(&mali_c55->media_dev);
453 	if (ret)
454 		goto err_cleanup_media_device;
455 
456 	mali_c55->v4l2_dev.mdev = &mali_c55->media_dev;
457 	ret = v4l2_device_register(mali_c55->dev, &mali_c55->v4l2_dev);
458 	if (ret) {
459 		dev_err(mali_c55->dev, "failed to register V4L2 device\n");
460 		goto err_unregister_media_device;
461 	};
462 
463 	mali_c55->notifier.ops = &mali_c55_notifier_ops;
464 	v4l2_async_nf_init(&mali_c55->notifier, &mali_c55->v4l2_dev);
465 
466 	ret = mali_c55_register_entities(mali_c55);
467 	if (ret) {
468 		dev_err(mali_c55->dev, "failed to register entities\n");
469 		goto err_cleanup_nf;
470 	}
471 
472 	ret = mali_c55_parse_endpoint(mali_c55);
473 	if (ret)
474 		goto err_cleanup_nf;
475 
476 	ret = v4l2_async_nf_register(&mali_c55->notifier);
477 	if (ret) {
478 		dev_err(mali_c55->dev, "failed to register notifier\n");
479 		goto err_unregister_entities;
480 	}
481 
482 	return 0;
483 
484 err_unregister_entities:
485 	mali_c55_unregister_entities(mali_c55);
486 err_cleanup_nf:
487 	v4l2_async_nf_cleanup(&mali_c55->notifier);
488 	v4l2_device_unregister(&mali_c55->v4l2_dev);
489 err_unregister_media_device:
490 	media_device_unregister(&mali_c55->media_dev);
491 err_cleanup_media_device:
492 	media_device_cleanup(&mali_c55->media_dev);
493 
494 	return ret;
495 }
496 
497 static void mali_c55_media_frameworks_deinit(struct mali_c55 *mali_c55)
498 {
499 	v4l2_async_nf_unregister(&mali_c55->notifier);
500 	mali_c55_unregister_entities(mali_c55);
501 	v4l2_async_nf_cleanup(&mali_c55->notifier);
502 	v4l2_device_unregister(&mali_c55->v4l2_dev);
503 	media_device_unregister(&mali_c55->media_dev);
504 	media_device_cleanup(&mali_c55->media_dev);
505 }
506 
507 bool mali_c55_pipeline_ready(struct mali_c55 *mali_c55)
508 {
509 	struct mali_c55_cap_dev *fr = &mali_c55->cap_devs[MALI_C55_CAP_DEV_FR];
510 	struct mali_c55_cap_dev *ds = &mali_c55->cap_devs[MALI_C55_CAP_DEV_DS];
511 	struct mali_c55_params *params = &mali_c55->params;
512 	struct mali_c55_stats *stats = &mali_c55->stats;
513 
514 	return vb2_start_streaming_called(&fr->queue) &&
515 	       (!(mali_c55->capabilities & MALI_C55_GPS_DS_PIPE_FITTED) ||
516 		vb2_start_streaming_called(&ds->queue)) &&
517 	       vb2_start_streaming_called(&params->queue) &&
518 	       vb2_start_streaming_called(&stats->queue);
519 }
520 
521 static int mali_c55_check_hwcfg(struct mali_c55 *mali_c55)
522 {
523 	u32 product, version, revision, capabilities;
524 
525 	product = mali_c55_read(mali_c55, MALI_C55_REG_PRODUCT);
526 	version = mali_c55_read(mali_c55, MALI_C55_REG_VERSION);
527 	revision = mali_c55_read(mali_c55, MALI_C55_REG_REVISION);
528 
529 	mali_c55->media_dev.hw_revision = version;
530 
531 	dev_info(mali_c55->dev, "Detected Mali-C55 ISP %u.%u.%u\n",
532 		 product, version, revision);
533 
534 	capabilities = mali_c55_read(mali_c55,
535 				     MALI_C55_REG_GLOBAL_PARAMETER_STATUS);
536 
537 	/*
538 	 * In its current iteration, the driver only supports inline mode. Given
539 	 * we cannot control input data timing in this mode, we cannot guarantee
540 	 * that the vertical blanking periods between frames will be long enough
541 	 * for us to write configuration data to the ISP during them. For that
542 	 * reason we can't really support single config space configuration
543 	 * until memory input mode is implemented.
544 	 */
545 	if (!(capabilities & MALI_C55_GPS_PONG_FITTED)) {
546 		dev_err(mali_c55->dev, "Pong config space not fitted.\n");
547 		return -EINVAL;
548 	}
549 
550 	mali_c55->capabilities = capabilities & 0xffff;
551 
552 	return 0;
553 }
554 
555 static irqreturn_t mali_c55_isr(int irq, void *context)
556 {
557 	struct device *dev = context;
558 	struct mali_c55 *mali_c55 = dev_get_drvdata(dev);
559 	unsigned long interrupt_status;
560 	u32 curr_config;
561 	unsigned int i;
562 
563 	interrupt_status = mali_c55_read(mali_c55,
564 					 MALI_C55_REG_INTERRUPT_STATUS_VECTOR);
565 	if (!interrupt_status)
566 		return IRQ_NONE;
567 
568 	mali_c55_write(mali_c55, MALI_C55_REG_INTERRUPT_CLEAR_VECTOR,
569 		       interrupt_status);
570 	mali_c55_write(mali_c55, MALI_C55_REG_INTERRUPT_CLEAR, 1);
571 	mali_c55_write(mali_c55, MALI_C55_REG_INTERRUPT_CLEAR, 0);
572 
573 	for_each_set_bit(i, &interrupt_status, MALI_C55_NUM_IRQ_BITS) {
574 		switch (i) {
575 		case MALI_C55_IRQ_ISP_START:
576 			mali_c55_isp_queue_event_sof(mali_c55);
577 
578 			mali_c55_set_next_buffer(&mali_c55->cap_devs[MALI_C55_CAP_DEV_FR]);
579 			if (mali_c55->capabilities & MALI_C55_GPS_DS_PIPE_FITTED)
580 				mali_c55_set_next_buffer(&mali_c55->cap_devs[MALI_C55_CAP_DEV_DS]);
581 
582 			/*
583 			 * When the ISP starts a frame we have some work to do:
584 			 *
585 			 * 1. Copy over the config for the **next** frame
586 			 * 2. Read out the metering stats for the **last** frame
587 			 */
588 
589 			curr_config = mali_c55_read(mali_c55,
590 						    MALI_C55_REG_PING_PONG_READ);
591 			curr_config &= MALI_C55_REG_PING_PONG_READ_MASK;
592 			curr_config >>= ffs(MALI_C55_REG_PING_PONG_READ_MASK) - 1;
593 			mali_c55->next_config = curr_config ^ 1;
594 
595 			/*
596 			 * Write the configuration parameters received from
597 			 * userspace into the configuration buffer, which will
598 			 * be transferred to the 'next' active config space at
599 			 * by mali_c55_swap_next_config().
600 			 */
601 			mali_c55_params_write_config(mali_c55);
602 
603 			mali_c55_stats_fill_buffer(mali_c55,
604 						   mali_c55->next_config ^ 1);
605 
606 			mali_c55_swap_next_config(mali_c55);
607 
608 			break;
609 		case MALI_C55_IRQ_ISP_DONE:
610 			/*
611 			 * TODO: Where the ISP has no Pong config fitted, we'd
612 			 * have to do the mali_c55_swap_next_config() call here.
613 			 */
614 			break;
615 		case MALI_C55_IRQ_FR_Y_DONE:
616 			mali_c55_set_plane_done(&mali_c55->cap_devs[MALI_C55_CAP_DEV_FR],
617 						MALI_C55_PLANE_Y);
618 			break;
619 		case MALI_C55_IRQ_FR_UV_DONE:
620 			mali_c55_set_plane_done(&mali_c55->cap_devs[MALI_C55_CAP_DEV_FR],
621 						MALI_C55_PLANE_UV);
622 			break;
623 		case MALI_C55_IRQ_DS_Y_DONE:
624 			mali_c55_set_plane_done(&mali_c55->cap_devs[MALI_C55_CAP_DEV_DS],
625 						MALI_C55_PLANE_Y);
626 			break;
627 		case MALI_C55_IRQ_DS_UV_DONE:
628 			mali_c55_set_plane_done(&mali_c55->cap_devs[MALI_C55_CAP_DEV_DS],
629 						MALI_C55_PLANE_UV);
630 			break;
631 		default:
632 			/*
633 			 * Only the above interrupts are currently unmasked. If
634 			 * we receive anything else here then something weird
635 			 * has gone on.
636 			 */
637 			dev_err(dev, "masked interrupt %s triggered\n",
638 				mali_c55_interrupt_names[i]);
639 		}
640 	}
641 
642 	return IRQ_HANDLED;
643 }
644 
645 static int mali_c55_init_context(struct mali_c55 *mali_c55,
646 				 struct resource *res)
647 {
648 	struct mali_c55_context *ctx = &mali_c55->context;
649 
650 	ctx->base = res->start;
651 	ctx->mali_c55 = mali_c55;
652 	spin_lock_init(&ctx->lock);
653 
654 	ctx->registers = kzalloc(MALI_C55_CONFIG_SPACE_SIZE, GFP_KERNEL);
655 	if (!ctx->registers)
656 		return -ENOMEM;
657 
658 	/*
659 	 * The allocated memory is empty, we need to load the default
660 	 * register settings. We just read Ping; it's identical to Pong.
661 	 */
662 	memcpy_fromio(ctx->registers,
663 		      mali_c55->base + config_space_addrs[MALI_C55_CONFIG_PING],
664 		      MALI_C55_CONFIG_SPACE_SIZE);
665 
666 	/*
667 	 * Some features of the ISP need to be disabled by default and only
668 	 * enabled at the same time as they're configured by a parameters buffer
669 	 */
670 
671 	/* Bypass the sqrt and square compression and expansion modules */
672 	mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_BYPASS_1,
673 				 MALI_C55_REG_BYPASS_1_FE_SQRT,
674 				 MALI_C55_REG_BYPASS_1_FE_SQRT);
675 	mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_BYPASS_3,
676 				 MALI_C55_REG_BYPASS_3_SQUARE_BE,
677 				 MALI_C55_REG_BYPASS_3_SQUARE_BE);
678 
679 	/* Bypass the temper module */
680 	mali_c55_ctx_write(mali_c55, MALI_C55_REG_BYPASS_2,
681 			   MALI_C55_REG_BYPASS_2_TEMPER);
682 
683 	/* Disable the temper module's DMA read/write */
684 	mali_c55_ctx_write(mali_c55, MALI_C55_REG_TEMPER_DMA_IO, 0x0);
685 
686 	/* Bypass the colour noise reduction  */
687 	mali_c55_ctx_write(mali_c55, MALI_C55_REG_BYPASS_4,
688 			   MALI_C55_REG_BYPASS_4_CNR);
689 
690 	/* Disable the sinter module */
691 	mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_SINTER_CONFIG,
692 				 MALI_C55_SINTER_ENABLE_MASK, 0);
693 
694 	/* Disable the RGB Gamma module for each output */
695 	mali_c55_ctx_write(mali_c55, MALI_C55_REG_FR_GAMMA_RGB_ENABLE, 0);
696 	mali_c55_ctx_write(mali_c55, MALI_C55_REG_DS_GAMMA_RGB_ENABLE, 0);
697 
698 	/* Disable the colour correction matrix */
699 	mali_c55_ctx_write(mali_c55, MALI_C55_REG_CCM_ENABLE, 0);
700 
701 	return 0;
702 }
703 
704 static void __mali_c55_power_off(struct mali_c55 *mali_c55)
705 {
706 	reset_control_bulk_assert(ARRAY_SIZE(mali_c55->resets), mali_c55->resets);
707 	clk_bulk_disable_unprepare(ARRAY_SIZE(mali_c55->clks), mali_c55->clks);
708 }
709 
710 static int __maybe_unused mali_c55_runtime_suspend(struct device *dev)
711 {
712 	struct mali_c55 *mali_c55 = dev_get_drvdata(dev);
713 
714 	if (irq_has_action(mali_c55->irqnum))
715 		free_irq(mali_c55->irqnum, dev);
716 	__mali_c55_power_off(mali_c55);
717 
718 	return 0;
719 }
720 
721 static int __mali_c55_power_on(struct mali_c55 *mali_c55)
722 {
723 	int ret;
724 	u32 val;
725 
726 	ret = clk_bulk_prepare_enable(ARRAY_SIZE(mali_c55->clks),
727 				      mali_c55->clks);
728 	if (ret) {
729 		dev_err(mali_c55->dev, "failed to enable clocks\n");
730 		return ret;
731 	}
732 
733 	ret = reset_control_bulk_deassert(ARRAY_SIZE(mali_c55->resets),
734 					  mali_c55->resets);
735 	if (ret) {
736 		dev_err(mali_c55->dev, "failed to deassert resets\n");
737 		return ret;
738 	}
739 
740 	/* Use "software only" context management. */
741 	mali_c55_update_bits(mali_c55, MALI_C55_REG_MCU_CONFIG,
742 			     MALI_C55_REG_MCU_CONFIG_OVERRIDE_MASK, 0x01);
743 
744 	/*
745 	 * Mask the interrupts and clear any that were set, then unmask the ones
746 	 * that we actually want to handle.
747 	 */
748 	mali_c55_write(mali_c55, MALI_C55_REG_INTERRUPT_MASK_VECTOR,
749 		       MALI_C55_INTERRUPT_MASK_ALL);
750 	mali_c55_write(mali_c55, MALI_C55_REG_INTERRUPT_CLEAR_VECTOR,
751 		       MALI_C55_INTERRUPT_MASK_ALL);
752 	mali_c55_write(mali_c55, MALI_C55_REG_INTERRUPT_CLEAR, 0x01);
753 	mali_c55_write(mali_c55, MALI_C55_REG_INTERRUPT_CLEAR, 0x00);
754 
755 	mali_c55_update_bits(mali_c55, MALI_C55_REG_INTERRUPT_MASK_VECTOR,
756 			     MALI_C55_INTERRUPT_BIT(MALI_C55_IRQ_ISP_START) |
757 			     MALI_C55_INTERRUPT_BIT(MALI_C55_IRQ_ISP_DONE) |
758 			     MALI_C55_INTERRUPT_BIT(MALI_C55_IRQ_FR_Y_DONE) |
759 			     MALI_C55_INTERRUPT_BIT(MALI_C55_IRQ_FR_UV_DONE) |
760 			     MALI_C55_INTERRUPT_BIT(MALI_C55_IRQ_DS_Y_DONE) |
761 			     MALI_C55_INTERRUPT_BIT(MALI_C55_IRQ_DS_UV_DONE),
762 			     0x00);
763 
764 	/* Set safe stop to ensure we're in a non-streaming state */
765 	mali_c55_write(mali_c55, MALI_C55_REG_INPUT_MODE_REQUEST,
766 		       MALI_C55_INPUT_SAFE_STOP);
767 	readl_poll_timeout(mali_c55->base + MALI_C55_REG_MODE_STATUS,
768 			   val, !val, 10 * USEC_PER_MSEC, 250 * USEC_PER_MSEC);
769 
770 	return 0;
771 }
772 
773 static int __maybe_unused mali_c55_runtime_resume(struct device *dev)
774 {
775 	struct mali_c55 *mali_c55 = dev_get_drvdata(dev);
776 	int ret;
777 
778 	ret = __mali_c55_power_on(mali_c55);
779 	if (ret)
780 		return ret;
781 
782 	/*
783 	 * The driver needs to transfer large amounts of register settings to
784 	 * the ISP each frame, using either a DMA transfer or memcpy. We use a
785 	 * threaded IRQ to avoid disabling interrupts the entire time that's
786 	 * happening.
787 	 */
788 	ret = request_threaded_irq(mali_c55->irqnum, NULL, mali_c55_isr,
789 				   IRQF_ONESHOT, dev_driver_string(dev), dev);
790 	if (ret) {
791 		__mali_c55_power_off(mali_c55);
792 		dev_err(dev, "failed to request irq\n");
793 	}
794 
795 	return ret;
796 }
797 
798 static const struct dev_pm_ops mali_c55_pm_ops = {
799 	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
800 				pm_runtime_force_resume)
801 	SET_RUNTIME_PM_OPS(mali_c55_runtime_suspend, mali_c55_runtime_resume,
802 			   NULL)
803 };
804 
805 static int mali_c55_probe(struct platform_device *pdev)
806 {
807 	struct device *dev = &pdev->dev;
808 	struct mali_c55 *mali_c55;
809 	struct resource *res;
810 	int ret;
811 
812 	mali_c55 = devm_kzalloc(dev, sizeof(*mali_c55), GFP_KERNEL);
813 	if (!mali_c55)
814 		return -ENOMEM;
815 
816 	mali_c55->dev = dev;
817 	platform_set_drvdata(pdev, mali_c55);
818 
819 	mali_c55->base = devm_platform_get_and_ioremap_resource(pdev, 0,
820 								&res);
821 	if (IS_ERR(mali_c55->base))
822 		return dev_err_probe(dev, PTR_ERR(mali_c55->base),
823 				     "failed to map IO memory\n");
824 
825 	for (unsigned int i = 0; i < ARRAY_SIZE(mali_c55_clk_names); i++)
826 		mali_c55->clks[i].id = mali_c55_clk_names[i];
827 
828 	ret = devm_clk_bulk_get(dev, ARRAY_SIZE(mali_c55->clks), mali_c55->clks);
829 	if (ret)
830 		return dev_err_probe(dev, ret, "failed to acquire clocks\n");
831 
832 	for (unsigned int i = 0; i < ARRAY_SIZE(mali_c55_reset_names); i++)
833 		mali_c55->resets[i].id = mali_c55_reset_names[i];
834 
835 	ret = devm_reset_control_bulk_get_optional_shared(dev,
836 			ARRAY_SIZE(mali_c55_reset_names), mali_c55->resets);
837 	if (ret)
838 		return dev_err_probe(dev, ret, "failed to acquire resets\n");
839 
840 	of_reserved_mem_device_init(dev);
841 	vb2_dma_contig_set_max_seg_size(dev, UINT_MAX);
842 
843 	ret = __mali_c55_power_on(mali_c55);
844 	if (ret)
845 		return dev_err_probe(dev, ret, "failed to power on\n");
846 
847 	ret = mali_c55_check_hwcfg(mali_c55);
848 	if (ret)
849 		goto err_power_off;
850 
851 	ret = mali_c55_init_context(mali_c55, res);
852 	if (ret)
853 		goto err_power_off;
854 
855 	mali_c55->media_dev.dev = dev;
856 
857 	pm_runtime_set_autosuspend_delay(&pdev->dev, 2000);
858 	pm_runtime_use_autosuspend(&pdev->dev);
859 	pm_runtime_set_active(&pdev->dev);
860 	pm_runtime_enable(&pdev->dev);
861 
862 	ret = mali_c55_media_frameworks_init(mali_c55);
863 	if (ret)
864 		goto err_free_context_registers;
865 
866 	pm_runtime_idle(&pdev->dev);
867 
868 	mali_c55->irqnum = platform_get_irq(pdev, 0);
869 	if (mali_c55->irqnum < 0) {
870 		ret = mali_c55->irqnum;
871 		dev_err(dev, "failed to get interrupt\n");
872 		goto err_deinit_media_frameworks;
873 	}
874 
875 	return 0;
876 
877 err_deinit_media_frameworks:
878 	mali_c55_media_frameworks_deinit(mali_c55);
879 	pm_runtime_disable(&pdev->dev);
880 err_free_context_registers:
881 	kfree(mali_c55->context.registers);
882 err_power_off:
883 	__mali_c55_power_off(mali_c55);
884 
885 	return ret;
886 }
887 
888 static void mali_c55_remove(struct platform_device *pdev)
889 {
890 	struct mali_c55 *mali_c55 = platform_get_drvdata(pdev);
891 
892 	kfree(mali_c55->context.registers);
893 	mali_c55_media_frameworks_deinit(mali_c55);
894 }
895 
896 static const struct of_device_id mali_c55_of_match[] = {
897 	{ .compatible = "arm,mali-c55", },
898 	{ /* Sentinel */ },
899 };
900 MODULE_DEVICE_TABLE(of, mali_c55_of_match);
901 
902 static struct platform_driver mali_c55_driver = {
903 	.driver = {
904 		.name = "mali-c55",
905 		.of_match_table = mali_c55_of_match,
906 		.pm = &mali_c55_pm_ops,
907 	},
908 	.probe = mali_c55_probe,
909 	.remove = mali_c55_remove,
910 };
911 
912 module_platform_driver(mali_c55_driver);
913 
914 MODULE_AUTHOR("Daniel Scally <dan.scally@ideasonboard.com>");
915 MODULE_AUTHOR("Jacopo Mondi <jacopo.mondi@ideasonboard.com>");
916 MODULE_DESCRIPTION("ARM Mali-C55 ISP platform driver");
917 MODULE_LICENSE("GPL");
918