1 /*
2  * Copyright (C) 2012 Samsung Electronics Co.Ltd
3  * Authors:
4  *	YoungJun Cho <yj44.cho@samsung.com>
5  *	Eunchul Kim <chulspro.kim@samsung.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundationr
10  */
11 
12 #include <linux/kernel.h>
13 #include <linux/err.h>
14 #include <linux/interrupt.h>
15 #include <linux/io.h>
16 #include <linux/platform_device.h>
17 #include <linux/clk.h>
18 #include <linux/pm_runtime.h>
19 
20 #include <drm/drmP.h>
21 #include <drm/exynos_drm.h>
22 #include "regs-rotator.h"
23 #include "exynos_drm.h"
24 #include "exynos_drm_drv.h"
25 #include "exynos_drm_ipp.h"
26 
27 /*
28  * Rotator supports image crop/rotator and input/output DMA operations.
29  * input DMA reads image data from the memory.
30  * output DMA writes image data to memory.
31  *
32  * M2M operation : supports crop/scale/rotation/csc so on.
33  * Memory ----> Rotator H/W ----> Memory.
34  */
35 
36 /*
37  * TODO
38  * 1. check suspend/resume api if needed.
39  * 2. need to check use case platform_device_id.
40  * 3. check src/dst size with, height.
41  * 4. need to add supported list in prop_list.
42  */
43 
44 #define get_rot_context(dev)	platform_get_drvdata(to_platform_device(dev))
45 #define get_ctx_from_ippdrv(ippdrv)	container_of(ippdrv,\
46 					struct rot_context, ippdrv);
47 #define rot_read(offset)		readl(rot->regs + (offset))
48 #define rot_write(cfg, offset)	writel(cfg, rot->regs + (offset))
49 
50 enum rot_irq_status {
51 	ROT_IRQ_STATUS_COMPLETE	= 8,
52 	ROT_IRQ_STATUS_ILLEGAL	= 9,
53 };
54 
55 /*
56  * A structure of limitation.
57  *
58  * @min_w: minimum width.
59  * @min_h: minimum height.
60  * @max_w: maximum width.
61  * @max_h: maximum height.
62  * @align: align size.
63  */
64 struct rot_limit {
65 	u32	min_w;
66 	u32	min_h;
67 	u32	max_w;
68 	u32	max_h;
69 	u32	align;
70 };
71 
72 /*
73  * A structure of limitation table.
74  *
75  * @ycbcr420_2p: case of YUV.
76  * @rgb888: case of RGB.
77  */
78 struct rot_limit_table {
79 	struct rot_limit	ycbcr420_2p;
80 	struct rot_limit	rgb888;
81 };
82 
83 /*
84  * A structure of rotator context.
85  * @ippdrv: prepare initialization using ippdrv.
86  * @regs_res: register resources.
87  * @regs: memory mapped io registers.
88  * @clock: rotator gate clock.
89  * @limit_tbl: limitation of rotator.
90  * @irq: irq number.
91  * @cur_buf_id: current operation buffer id.
92  * @suspended: suspended state.
93  */
94 struct rot_context {
95 	struct exynos_drm_ippdrv	ippdrv;
96 	struct resource	*regs_res;
97 	void __iomem	*regs;
98 	struct clk	*clock;
99 	struct rot_limit_table	*limit_tbl;
100 	int	irq;
101 	int	cur_buf_id[EXYNOS_DRM_OPS_MAX];
102 	bool	suspended;
103 };
104 
105 static void rotator_reg_set_irq(struct rot_context *rot, bool enable)
106 {
107 	u32 val = rot_read(ROT_CONFIG);
108 
109 	if (enable == true)
110 		val |= ROT_CONFIG_IRQ;
111 	else
112 		val &= ~ROT_CONFIG_IRQ;
113 
114 	rot_write(val, ROT_CONFIG);
115 }
116 
117 static u32 rotator_reg_get_fmt(struct rot_context *rot)
118 {
119 	u32 val = rot_read(ROT_CONTROL);
120 
121 	val &= ROT_CONTROL_FMT_MASK;
122 
123 	return val;
124 }
125 
126 static enum rot_irq_status rotator_reg_get_irq_status(struct rot_context *rot)
127 {
128 	u32 val = rot_read(ROT_STATUS);
129 
130 	val = ROT_STATUS_IRQ(val);
131 
132 	if (val == ROT_STATUS_IRQ_VAL_COMPLETE)
133 		return ROT_IRQ_STATUS_COMPLETE;
134 
135 	return ROT_IRQ_STATUS_ILLEGAL;
136 }
137 
138 static irqreturn_t rotator_irq_handler(int irq, void *arg)
139 {
140 	struct rot_context *rot = arg;
141 	struct exynos_drm_ippdrv *ippdrv = &rot->ippdrv;
142 	struct drm_exynos_ipp_cmd_node *c_node = ippdrv->c_node;
143 	struct drm_exynos_ipp_event_work *event_work = c_node->event_work;
144 	enum rot_irq_status irq_status;
145 	u32 val;
146 
147 	/* Get execution result */
148 	irq_status = rotator_reg_get_irq_status(rot);
149 
150 	/* clear status */
151 	val = rot_read(ROT_STATUS);
152 	val |= ROT_STATUS_IRQ_PENDING((u32)irq_status);
153 	rot_write(val, ROT_STATUS);
154 
155 	if (irq_status == ROT_IRQ_STATUS_COMPLETE) {
156 		event_work->ippdrv = ippdrv;
157 		event_work->buf_id[EXYNOS_DRM_OPS_DST] =
158 			rot->cur_buf_id[EXYNOS_DRM_OPS_DST];
159 		queue_work(ippdrv->event_workq,
160 			(struct work_struct *)event_work);
161 	} else {
162 		DRM_ERROR("the SFR is set illegally\n");
163 	}
164 
165 	return IRQ_HANDLED;
166 }
167 
168 static void rotator_align_size(struct rot_context *rot, u32 fmt, u32 *hsize,
169 		u32 *vsize)
170 {
171 	struct rot_limit_table *limit_tbl = rot->limit_tbl;
172 	struct rot_limit *limit;
173 	u32 mask, val;
174 
175 	/* Get size limit */
176 	if (fmt == ROT_CONTROL_FMT_RGB888)
177 		limit = &limit_tbl->rgb888;
178 	else
179 		limit = &limit_tbl->ycbcr420_2p;
180 
181 	/* Get mask for rounding to nearest aligned val */
182 	mask = ~((1 << limit->align) - 1);
183 
184 	/* Set aligned width */
185 	val = ROT_ALIGN(*hsize, limit->align, mask);
186 	if (val < limit->min_w)
187 		*hsize = ROT_MIN(limit->min_w, mask);
188 	else if (val > limit->max_w)
189 		*hsize = ROT_MAX(limit->max_w, mask);
190 	else
191 		*hsize = val;
192 
193 	/* Set aligned height */
194 	val = ROT_ALIGN(*vsize, limit->align, mask);
195 	if (val < limit->min_h)
196 		*vsize = ROT_MIN(limit->min_h, mask);
197 	else if (val > limit->max_h)
198 		*vsize = ROT_MAX(limit->max_h, mask);
199 	else
200 		*vsize = val;
201 }
202 
203 static int rotator_src_set_fmt(struct device *dev, u32 fmt)
204 {
205 	struct rot_context *rot = dev_get_drvdata(dev);
206 	u32 val;
207 
208 	val = rot_read(ROT_CONTROL);
209 	val &= ~ROT_CONTROL_FMT_MASK;
210 
211 	switch (fmt) {
212 	case DRM_FORMAT_NV12:
213 		val |= ROT_CONTROL_FMT_YCBCR420_2P;
214 		break;
215 	case DRM_FORMAT_XRGB8888:
216 		val |= ROT_CONTROL_FMT_RGB888;
217 		break;
218 	default:
219 		DRM_ERROR("invalid image format\n");
220 		return -EINVAL;
221 	}
222 
223 	rot_write(val, ROT_CONTROL);
224 
225 	return 0;
226 }
227 
228 static inline bool rotator_check_reg_fmt(u32 fmt)
229 {
230 	if ((fmt == ROT_CONTROL_FMT_YCBCR420_2P) ||
231 	    (fmt == ROT_CONTROL_FMT_RGB888))
232 		return true;
233 
234 	return false;
235 }
236 
237 static int rotator_src_set_size(struct device *dev, int swap,
238 		struct drm_exynos_pos *pos,
239 		struct drm_exynos_sz *sz)
240 {
241 	struct rot_context *rot = dev_get_drvdata(dev);
242 	u32 fmt, hsize, vsize;
243 	u32 val;
244 
245 	/* Get format */
246 	fmt = rotator_reg_get_fmt(rot);
247 	if (!rotator_check_reg_fmt(fmt)) {
248 		DRM_ERROR("invalid format.\n");
249 		return -EINVAL;
250 	}
251 
252 	/* Align buffer size */
253 	hsize = sz->hsize;
254 	vsize = sz->vsize;
255 	rotator_align_size(rot, fmt, &hsize, &vsize);
256 
257 	/* Set buffer size configuration */
258 	val = ROT_SET_BUF_SIZE_H(vsize) | ROT_SET_BUF_SIZE_W(hsize);
259 	rot_write(val, ROT_SRC_BUF_SIZE);
260 
261 	/* Set crop image position configuration */
262 	val = ROT_CROP_POS_Y(pos->y) | ROT_CROP_POS_X(pos->x);
263 	rot_write(val, ROT_SRC_CROP_POS);
264 	val = ROT_SRC_CROP_SIZE_H(pos->h) | ROT_SRC_CROP_SIZE_W(pos->w);
265 	rot_write(val, ROT_SRC_CROP_SIZE);
266 
267 	return 0;
268 }
269 
270 static int rotator_src_set_addr(struct device *dev,
271 		struct drm_exynos_ipp_buf_info *buf_info,
272 		u32 buf_id, enum drm_exynos_ipp_buf_type buf_type)
273 {
274 	struct rot_context *rot = dev_get_drvdata(dev);
275 	dma_addr_t addr[EXYNOS_DRM_PLANAR_MAX];
276 	u32 val, fmt, hsize, vsize;
277 	int i;
278 
279 	/* Set current buf_id */
280 	rot->cur_buf_id[EXYNOS_DRM_OPS_SRC] = buf_id;
281 
282 	switch (buf_type) {
283 	case IPP_BUF_ENQUEUE:
284 		/* Set address configuration */
285 		for_each_ipp_planar(i)
286 			addr[i] = buf_info->base[i];
287 
288 		/* Get format */
289 		fmt = rotator_reg_get_fmt(rot);
290 		if (!rotator_check_reg_fmt(fmt)) {
291 			DRM_ERROR("invalid format.\n");
292 			return -EINVAL;
293 		}
294 
295 		/* Re-set cb planar for NV12 format */
296 		if ((fmt == ROT_CONTROL_FMT_YCBCR420_2P) &&
297 		    !addr[EXYNOS_DRM_PLANAR_CB]) {
298 
299 			val = rot_read(ROT_SRC_BUF_SIZE);
300 			hsize = ROT_GET_BUF_SIZE_W(val);
301 			vsize = ROT_GET_BUF_SIZE_H(val);
302 
303 			/* Set cb planar */
304 			addr[EXYNOS_DRM_PLANAR_CB] =
305 				addr[EXYNOS_DRM_PLANAR_Y] + hsize * vsize;
306 		}
307 
308 		for_each_ipp_planar(i)
309 			rot_write(addr[i], ROT_SRC_BUF_ADDR(i));
310 		break;
311 	case IPP_BUF_DEQUEUE:
312 		for_each_ipp_planar(i)
313 			rot_write(0x0, ROT_SRC_BUF_ADDR(i));
314 		break;
315 	default:
316 		/* Nothing to do */
317 		break;
318 	}
319 
320 	return 0;
321 }
322 
323 static int rotator_dst_set_transf(struct device *dev,
324 		enum drm_exynos_degree degree,
325 		enum drm_exynos_flip flip, bool *swap)
326 {
327 	struct rot_context *rot = dev_get_drvdata(dev);
328 	u32 val;
329 
330 	/* Set transform configuration */
331 	val = rot_read(ROT_CONTROL);
332 	val &= ~ROT_CONTROL_FLIP_MASK;
333 
334 	switch (flip) {
335 	case EXYNOS_DRM_FLIP_VERTICAL:
336 		val |= ROT_CONTROL_FLIP_VERTICAL;
337 		break;
338 	case EXYNOS_DRM_FLIP_HORIZONTAL:
339 		val |= ROT_CONTROL_FLIP_HORIZONTAL;
340 		break;
341 	default:
342 		/* Flip None */
343 		break;
344 	}
345 
346 	val &= ~ROT_CONTROL_ROT_MASK;
347 
348 	switch (degree) {
349 	case EXYNOS_DRM_DEGREE_90:
350 		val |= ROT_CONTROL_ROT_90;
351 		break;
352 	case EXYNOS_DRM_DEGREE_180:
353 		val |= ROT_CONTROL_ROT_180;
354 		break;
355 	case EXYNOS_DRM_DEGREE_270:
356 		val |= ROT_CONTROL_ROT_270;
357 		break;
358 	default:
359 		/* Rotation 0 Degree */
360 		break;
361 	}
362 
363 	rot_write(val, ROT_CONTROL);
364 
365 	/* Check degree for setting buffer size swap */
366 	if ((degree == EXYNOS_DRM_DEGREE_90) ||
367 	    (degree == EXYNOS_DRM_DEGREE_270))
368 		*swap = true;
369 	else
370 		*swap = false;
371 
372 	return 0;
373 }
374 
375 static int rotator_dst_set_size(struct device *dev, int swap,
376 		struct drm_exynos_pos *pos,
377 		struct drm_exynos_sz *sz)
378 {
379 	struct rot_context *rot = dev_get_drvdata(dev);
380 	u32 val, fmt, hsize, vsize;
381 
382 	/* Get format */
383 	fmt = rotator_reg_get_fmt(rot);
384 	if (!rotator_check_reg_fmt(fmt)) {
385 		DRM_ERROR("invalid format.\n");
386 		return -EINVAL;
387 	}
388 
389 	/* Align buffer size */
390 	hsize = sz->hsize;
391 	vsize = sz->vsize;
392 	rotator_align_size(rot, fmt, &hsize, &vsize);
393 
394 	/* Set buffer size configuration */
395 	val = ROT_SET_BUF_SIZE_H(vsize) | ROT_SET_BUF_SIZE_W(hsize);
396 	rot_write(val, ROT_DST_BUF_SIZE);
397 
398 	/* Set crop image position configuration */
399 	val = ROT_CROP_POS_Y(pos->y) | ROT_CROP_POS_X(pos->x);
400 	rot_write(val, ROT_DST_CROP_POS);
401 
402 	return 0;
403 }
404 
405 static int rotator_dst_set_addr(struct device *dev,
406 		struct drm_exynos_ipp_buf_info *buf_info,
407 		u32 buf_id, enum drm_exynos_ipp_buf_type buf_type)
408 {
409 	struct rot_context *rot = dev_get_drvdata(dev);
410 	dma_addr_t addr[EXYNOS_DRM_PLANAR_MAX];
411 	u32 val, fmt, hsize, vsize;
412 	int i;
413 
414 	/* Set current buf_id */
415 	rot->cur_buf_id[EXYNOS_DRM_OPS_DST] = buf_id;
416 
417 	switch (buf_type) {
418 	case IPP_BUF_ENQUEUE:
419 		/* Set address configuration */
420 		for_each_ipp_planar(i)
421 			addr[i] = buf_info->base[i];
422 
423 		/* Get format */
424 		fmt = rotator_reg_get_fmt(rot);
425 		if (!rotator_check_reg_fmt(fmt)) {
426 			DRM_ERROR("invalid format.\n");
427 			return -EINVAL;
428 		}
429 
430 		/* Re-set cb planar for NV12 format */
431 		if ((fmt == ROT_CONTROL_FMT_YCBCR420_2P) &&
432 		    !addr[EXYNOS_DRM_PLANAR_CB]) {
433 			/* Get buf size */
434 			val = rot_read(ROT_DST_BUF_SIZE);
435 
436 			hsize = ROT_GET_BUF_SIZE_W(val);
437 			vsize = ROT_GET_BUF_SIZE_H(val);
438 
439 			/* Set cb planar */
440 			addr[EXYNOS_DRM_PLANAR_CB] =
441 				addr[EXYNOS_DRM_PLANAR_Y] + hsize * vsize;
442 		}
443 
444 		for_each_ipp_planar(i)
445 			rot_write(addr[i], ROT_DST_BUF_ADDR(i));
446 		break;
447 	case IPP_BUF_DEQUEUE:
448 		for_each_ipp_planar(i)
449 			rot_write(0x0, ROT_DST_BUF_ADDR(i));
450 		break;
451 	default:
452 		/* Nothing to do */
453 		break;
454 	}
455 
456 	return 0;
457 }
458 
459 static struct exynos_drm_ipp_ops rot_src_ops = {
460 	.set_fmt	=	rotator_src_set_fmt,
461 	.set_size	=	rotator_src_set_size,
462 	.set_addr	=	rotator_src_set_addr,
463 };
464 
465 static struct exynos_drm_ipp_ops rot_dst_ops = {
466 	.set_transf	=	rotator_dst_set_transf,
467 	.set_size	=	rotator_dst_set_size,
468 	.set_addr	=	rotator_dst_set_addr,
469 };
470 
471 static int rotator_init_prop_list(struct exynos_drm_ippdrv *ippdrv)
472 {
473 	struct drm_exynos_ipp_prop_list *prop_list = &ippdrv->prop_list;
474 
475 	prop_list->version = 1;
476 	prop_list->flip = (1 << EXYNOS_DRM_FLIP_VERTICAL) |
477 				(1 << EXYNOS_DRM_FLIP_HORIZONTAL);
478 	prop_list->degree = (1 << EXYNOS_DRM_DEGREE_0) |
479 				(1 << EXYNOS_DRM_DEGREE_90) |
480 				(1 << EXYNOS_DRM_DEGREE_180) |
481 				(1 << EXYNOS_DRM_DEGREE_270);
482 	prop_list->csc = 0;
483 	prop_list->crop = 0;
484 	prop_list->scale = 0;
485 
486 	return 0;
487 }
488 
489 static inline bool rotator_check_drm_fmt(u32 fmt)
490 {
491 	switch (fmt) {
492 	case DRM_FORMAT_XRGB8888:
493 	case DRM_FORMAT_NV12:
494 		return true;
495 	default:
496 		DRM_DEBUG_KMS("not support format\n");
497 		return false;
498 	}
499 }
500 
501 static inline bool rotator_check_drm_flip(enum drm_exynos_flip flip)
502 {
503 	switch (flip) {
504 	case EXYNOS_DRM_FLIP_NONE:
505 	case EXYNOS_DRM_FLIP_VERTICAL:
506 	case EXYNOS_DRM_FLIP_HORIZONTAL:
507 	case EXYNOS_DRM_FLIP_BOTH:
508 		return true;
509 	default:
510 		DRM_DEBUG_KMS("invalid flip\n");
511 		return false;
512 	}
513 }
514 
515 static int rotator_ippdrv_check_property(struct device *dev,
516 		struct drm_exynos_ipp_property *property)
517 {
518 	struct drm_exynos_ipp_config *src_config =
519 					&property->config[EXYNOS_DRM_OPS_SRC];
520 	struct drm_exynos_ipp_config *dst_config =
521 					&property->config[EXYNOS_DRM_OPS_DST];
522 	struct drm_exynos_pos *src_pos = &src_config->pos;
523 	struct drm_exynos_pos *dst_pos = &dst_config->pos;
524 	struct drm_exynos_sz *src_sz = &src_config->sz;
525 	struct drm_exynos_sz *dst_sz = &dst_config->sz;
526 	bool swap = false;
527 
528 	/* Check format configuration */
529 	if (src_config->fmt != dst_config->fmt) {
530 		DRM_DEBUG_KMS("not support csc feature\n");
531 		return -EINVAL;
532 	}
533 
534 	if (!rotator_check_drm_fmt(dst_config->fmt)) {
535 		DRM_DEBUG_KMS("invalid format\n");
536 		return -EINVAL;
537 	}
538 
539 	/* Check transform configuration */
540 	if (src_config->degree != EXYNOS_DRM_DEGREE_0) {
541 		DRM_DEBUG_KMS("not support source-side rotation\n");
542 		return -EINVAL;
543 	}
544 
545 	switch (dst_config->degree) {
546 	case EXYNOS_DRM_DEGREE_90:
547 	case EXYNOS_DRM_DEGREE_270:
548 		swap = true;
549 	case EXYNOS_DRM_DEGREE_0:
550 	case EXYNOS_DRM_DEGREE_180:
551 		/* No problem */
552 		break;
553 	default:
554 		DRM_DEBUG_KMS("invalid degree\n");
555 		return -EINVAL;
556 	}
557 
558 	if (src_config->flip != EXYNOS_DRM_FLIP_NONE) {
559 		DRM_DEBUG_KMS("not support source-side flip\n");
560 		return -EINVAL;
561 	}
562 
563 	if (!rotator_check_drm_flip(dst_config->flip)) {
564 		DRM_DEBUG_KMS("invalid flip\n");
565 		return -EINVAL;
566 	}
567 
568 	/* Check size configuration */
569 	if ((src_pos->x + src_pos->w > src_sz->hsize) ||
570 		(src_pos->y + src_pos->h > src_sz->vsize)) {
571 		DRM_DEBUG_KMS("out of source buffer bound\n");
572 		return -EINVAL;
573 	}
574 
575 	if (swap) {
576 		if ((dst_pos->x + dst_pos->h > dst_sz->vsize) ||
577 			(dst_pos->y + dst_pos->w > dst_sz->hsize)) {
578 			DRM_DEBUG_KMS("out of destination buffer bound\n");
579 			return -EINVAL;
580 		}
581 
582 		if ((src_pos->w != dst_pos->h) || (src_pos->h != dst_pos->w)) {
583 			DRM_DEBUG_KMS("not support scale feature\n");
584 			return -EINVAL;
585 		}
586 	} else {
587 		if ((dst_pos->x + dst_pos->w > dst_sz->hsize) ||
588 			(dst_pos->y + dst_pos->h > dst_sz->vsize)) {
589 			DRM_DEBUG_KMS("out of destination buffer bound\n");
590 			return -EINVAL;
591 		}
592 
593 		if ((src_pos->w != dst_pos->w) || (src_pos->h != dst_pos->h)) {
594 			DRM_DEBUG_KMS("not support scale feature\n");
595 			return -EINVAL;
596 		}
597 	}
598 
599 	return 0;
600 }
601 
602 static int rotator_ippdrv_start(struct device *dev, enum drm_exynos_ipp_cmd cmd)
603 {
604 	struct rot_context *rot = dev_get_drvdata(dev);
605 	u32 val;
606 
607 	if (rot->suspended) {
608 		DRM_ERROR("suspended state\n");
609 		return -EPERM;
610 	}
611 
612 	if (cmd != IPP_CMD_M2M) {
613 		DRM_ERROR("not support cmd: %d\n", cmd);
614 		return -EINVAL;
615 	}
616 
617 	/* Set interrupt enable */
618 	rotator_reg_set_irq(rot, true);
619 
620 	val = rot_read(ROT_CONTROL);
621 	val |= ROT_CONTROL_START;
622 
623 	rot_write(val, ROT_CONTROL);
624 
625 	return 0;
626 }
627 
628 static struct rot_limit_table rot_limit_tbl_4210 = {
629 	.ycbcr420_2p = {
630 		.min_w = 32,
631 		.min_h = 32,
632 		.max_w = SZ_64K,
633 		.max_h = SZ_64K,
634 		.align = 3,
635 	},
636 	.rgb888 = {
637 		.min_w = 8,
638 		.min_h = 8,
639 		.max_w = SZ_16K,
640 		.max_h = SZ_16K,
641 		.align = 2,
642 	},
643 };
644 
645 static struct rot_limit_table rot_limit_tbl_4x12 = {
646 	.ycbcr420_2p = {
647 		.min_w = 32,
648 		.min_h = 32,
649 		.max_w = SZ_32K,
650 		.max_h = SZ_32K,
651 		.align = 3,
652 	},
653 	.rgb888 = {
654 		.min_w = 8,
655 		.min_h = 8,
656 		.max_w = SZ_8K,
657 		.max_h = SZ_8K,
658 		.align = 2,
659 	},
660 };
661 
662 static struct rot_limit_table rot_limit_tbl_5250 = {
663 	.ycbcr420_2p = {
664 		.min_w = 32,
665 		.min_h = 32,
666 		.max_w = SZ_32K,
667 		.max_h = SZ_32K,
668 		.align = 3,
669 	},
670 	.rgb888 = {
671 		.min_w = 8,
672 		.min_h = 8,
673 		.max_w = SZ_8K,
674 		.max_h = SZ_8K,
675 		.align = 1,
676 	},
677 };
678 
679 static const struct of_device_id exynos_rotator_match[] = {
680 	{
681 		.compatible = "samsung,exynos4210-rotator",
682 		.data = &rot_limit_tbl_4210,
683 	},
684 	{
685 		.compatible = "samsung,exynos4212-rotator",
686 		.data = &rot_limit_tbl_4x12,
687 	},
688 	{
689 		.compatible = "samsung,exynos5250-rotator",
690 		.data = &rot_limit_tbl_5250,
691 	},
692 	{},
693 };
694 MODULE_DEVICE_TABLE(of, exynos_rotator_match);
695 
696 static int rotator_probe(struct platform_device *pdev)
697 {
698 	struct device *dev = &pdev->dev;
699 	struct rot_context *rot;
700 	struct exynos_drm_ippdrv *ippdrv;
701 	const struct of_device_id *match;
702 	int ret;
703 
704 	if (!dev->of_node) {
705 		dev_err(dev, "cannot find of_node.\n");
706 		return -ENODEV;
707 	}
708 
709 	rot = devm_kzalloc(dev, sizeof(*rot), GFP_KERNEL);
710 	if (!rot)
711 		return -ENOMEM;
712 
713 	match = of_match_node(exynos_rotator_match, dev->of_node);
714 	if (!match) {
715 		dev_err(dev, "failed to match node\n");
716 		return -ENODEV;
717 	}
718 	rot->limit_tbl = (struct rot_limit_table *)match->data;
719 
720 	rot->regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
721 	rot->regs = devm_ioremap_resource(dev, rot->regs_res);
722 	if (IS_ERR(rot->regs))
723 		return PTR_ERR(rot->regs);
724 
725 	rot->irq = platform_get_irq(pdev, 0);
726 	if (rot->irq < 0) {
727 		dev_err(dev, "failed to get irq\n");
728 		return rot->irq;
729 	}
730 
731 	ret = devm_request_threaded_irq(dev, rot->irq, NULL,
732 			rotator_irq_handler, IRQF_ONESHOT, "drm_rotator", rot);
733 	if (ret < 0) {
734 		dev_err(dev, "failed to request irq\n");
735 		return ret;
736 	}
737 
738 	rot->clock = devm_clk_get(dev, "rotator");
739 	if (IS_ERR(rot->clock)) {
740 		dev_err(dev, "failed to get clock\n");
741 		return PTR_ERR(rot->clock);
742 	}
743 
744 	pm_runtime_enable(dev);
745 
746 	ippdrv = &rot->ippdrv;
747 	ippdrv->dev = dev;
748 	ippdrv->ops[EXYNOS_DRM_OPS_SRC] = &rot_src_ops;
749 	ippdrv->ops[EXYNOS_DRM_OPS_DST] = &rot_dst_ops;
750 	ippdrv->check_property = rotator_ippdrv_check_property;
751 	ippdrv->start = rotator_ippdrv_start;
752 	ret = rotator_init_prop_list(ippdrv);
753 	if (ret < 0) {
754 		dev_err(dev, "failed to init property list.\n");
755 		goto err_ippdrv_register;
756 	}
757 
758 	DRM_DEBUG_KMS("ippdrv[0x%x]\n", (int)ippdrv);
759 
760 	platform_set_drvdata(pdev, rot);
761 
762 	ret = exynos_drm_ippdrv_register(ippdrv);
763 	if (ret < 0) {
764 		dev_err(dev, "failed to register drm rotator device\n");
765 		goto err_ippdrv_register;
766 	}
767 
768 	dev_info(dev, "The exynos rotator is probed successfully\n");
769 
770 	return 0;
771 
772 err_ippdrv_register:
773 	pm_runtime_disable(dev);
774 	return ret;
775 }
776 
777 static int rotator_remove(struct platform_device *pdev)
778 {
779 	struct device *dev = &pdev->dev;
780 	struct rot_context *rot = dev_get_drvdata(dev);
781 	struct exynos_drm_ippdrv *ippdrv = &rot->ippdrv;
782 
783 	exynos_drm_ippdrv_unregister(ippdrv);
784 
785 	pm_runtime_disable(dev);
786 
787 	return 0;
788 }
789 
790 static int rotator_clk_crtl(struct rot_context *rot, bool enable)
791 {
792 	if (enable) {
793 		clk_enable(rot->clock);
794 		rot->suspended = false;
795 	} else {
796 		clk_disable(rot->clock);
797 		rot->suspended = true;
798 	}
799 
800 	return 0;
801 }
802 
803 
804 #ifdef CONFIG_PM_SLEEP
805 static int rotator_suspend(struct device *dev)
806 {
807 	struct rot_context *rot = dev_get_drvdata(dev);
808 
809 	if (pm_runtime_suspended(dev))
810 		return 0;
811 
812 	return rotator_clk_crtl(rot, false);
813 }
814 
815 static int rotator_resume(struct device *dev)
816 {
817 	struct rot_context *rot = dev_get_drvdata(dev);
818 
819 	if (!pm_runtime_suspended(dev))
820 		return rotator_clk_crtl(rot, true);
821 
822 	return 0;
823 }
824 #endif
825 
826 #ifdef CONFIG_PM_RUNTIME
827 static int rotator_runtime_suspend(struct device *dev)
828 {
829 	struct rot_context *rot = dev_get_drvdata(dev);
830 
831 	return  rotator_clk_crtl(rot, false);
832 }
833 
834 static int rotator_runtime_resume(struct device *dev)
835 {
836 	struct rot_context *rot = dev_get_drvdata(dev);
837 
838 	return  rotator_clk_crtl(rot, true);
839 }
840 #endif
841 
842 static const struct dev_pm_ops rotator_pm_ops = {
843 	SET_SYSTEM_SLEEP_PM_OPS(rotator_suspend, rotator_resume)
844 	SET_RUNTIME_PM_OPS(rotator_runtime_suspend, rotator_runtime_resume,
845 									NULL)
846 };
847 
848 struct platform_driver rotator_driver = {
849 	.probe		= rotator_probe,
850 	.remove		= rotator_remove,
851 	.driver		= {
852 		.name	= "exynos-rot",
853 		.owner	= THIS_MODULE,
854 		.pm	= &rotator_pm_ops,
855 		.of_match_table = exynos_rotator_match,
856 	},
857 };
858