Linux Audio

Check our new training course

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