Version:  2.0.40 2.2.26 2.4.37 3.9 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18 3.19 4.0 4.1 4.2 4.3 4.4 4.5 4.6

Linux/drivers/gpu/drm/exynos/exynos_drm_rotator.c

  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 
 49 enum 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  */
 63 struct 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  */
 77 struct 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  */
 93 struct 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 
104 static 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 
116 static 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 
125 static 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 
137 static 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 
166 static 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 
201 static 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 
226 static 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 
235 static 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 
268 static 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 
321 static 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 
373 static 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 
403 static 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 
457 static 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 
463 static 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 
469 static 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 
487 static 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 
499 static 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 
513 static 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 
600 static 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 
626 static 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 
643 static 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 
660 static 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 
677 static 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 };
692 MODULE_DEVICE_TABLE(of, exynos_rotator_match);
693 
694 static 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 
770 err_ippdrv_register:
771         pm_runtime_disable(dev);
772         return ret;
773 }
774 
775 static 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
789 static 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
804 static 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 
814 static 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 
825 static 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 
832 static 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 
840 static 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 
846 struct 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 };
856 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us