Version:  2.0.40 2.2.26 2.4.37 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18

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

  1 /* exynos_drm_fimd.c
  2  *
  3  * Copyright (C) 2011 Samsung Electronics Co.Ltd
  4  * Authors:
  5  *      Joonyoung Shim <jy0922.shim@samsung.com>
  6  *      Inki Dae <inki.dae@samsung.com>
  7  *
  8  * This program is free software; you can redistribute  it and/or modify it
  9  * under  the terms of  the GNU General  Public License as published by the
 10  * Free Software Foundation;  either version 2 of the  License, or (at your
 11  * option) any later version.
 12  *
 13  */
 14 #include <drm/drmP.h>
 15 
 16 #include <linux/kernel.h>
 17 #include <linux/platform_device.h>
 18 #include <linux/clk.h>
 19 #include <linux/of.h>
 20 #include <linux/of_device.h>
 21 #include <linux/pm_runtime.h>
 22 #include <linux/component.h>
 23 #include <linux/mfd/syscon.h>
 24 #include <linux/regmap.h>
 25 
 26 #include <video/of_display_timing.h>
 27 #include <video/of_videomode.h>
 28 #include <video/samsung_fimd.h>
 29 #include <drm/exynos_drm.h>
 30 
 31 #include "exynos_drm_drv.h"
 32 #include "exynos_drm_fbdev.h"
 33 #include "exynos_drm_crtc.h"
 34 #include "exynos_drm_iommu.h"
 35 
 36 /*
 37  * FIMD stands for Fully Interactive Mobile Display and
 38  * as a display controller, it transfers contents drawn on memory
 39  * to a LCD Panel through Display Interfaces such as RGB or
 40  * CPU Interface.
 41  */
 42 
 43 #define FIMD_DEFAULT_FRAMERATE 60
 44 #define MIN_FB_WIDTH_FOR_16WORD_BURST 128
 45 
 46 /* position control register for hardware window 0, 2 ~ 4.*/
 47 #define VIDOSD_A(win)           (VIDOSD_BASE + 0x00 + (win) * 16)
 48 #define VIDOSD_B(win)           (VIDOSD_BASE + 0x04 + (win) * 16)
 49 /*
 50  * size control register for hardware windows 0 and alpha control register
 51  * for hardware windows 1 ~ 4
 52  */
 53 #define VIDOSD_C(win)           (VIDOSD_BASE + 0x08 + (win) * 16)
 54 /* size control register for hardware windows 1 ~ 2. */
 55 #define VIDOSD_D(win)           (VIDOSD_BASE + 0x0C + (win) * 16)
 56 
 57 #define VIDWx_BUF_START(win, buf)       (VIDW_BUF_START(buf) + (win) * 8)
 58 #define VIDWx_BUF_END(win, buf)         (VIDW_BUF_END(buf) + (win) * 8)
 59 #define VIDWx_BUF_SIZE(win, buf)        (VIDW_BUF_SIZE(buf) + (win) * 4)
 60 
 61 /* color key control register for hardware window 1 ~ 4. */
 62 #define WKEYCON0_BASE(x)                ((WKEYCON0 + 0x140) + ((x - 1) * 8))
 63 /* color key value register for hardware window 1 ~ 4. */
 64 #define WKEYCON1_BASE(x)                ((WKEYCON1 + 0x140) + ((x - 1) * 8))
 65 
 66 /* I80 / RGB trigger control register */
 67 #define TRIGCON                         0x1A4
 68 #define TRGMODE_I80_RGB_ENABLE_I80      (1 << 0)
 69 #define SWTRGCMD_I80_RGB_ENABLE         (1 << 1)
 70 
 71 /* display mode change control register except exynos4 */
 72 #define VIDOUT_CON                      0x000
 73 #define VIDOUT_CON_F_I80_LDI0           (0x2 << 8)
 74 
 75 /* I80 interface control for main LDI register */
 76 #define I80IFCONFAx(x)                  (0x1B0 + (x) * 4)
 77 #define I80IFCONFBx(x)                  (0x1B8 + (x) * 4)
 78 #define LCD_CS_SETUP(x)                 ((x) << 16)
 79 #define LCD_WR_SETUP(x)                 ((x) << 12)
 80 #define LCD_WR_ACTIVE(x)                ((x) << 8)
 81 #define LCD_WR_HOLD(x)                  ((x) << 4)
 82 #define I80IFEN_ENABLE                  (1 << 0)
 83 
 84 /* FIMD has totally five hardware windows. */
 85 #define WINDOWS_NR      5
 86 
 87 #define get_fimd_manager(mgr)   platform_get_drvdata(to_platform_device(dev))
 88 
 89 struct fimd_driver_data {
 90         unsigned int timing_base;
 91         unsigned int lcdblk_offset;
 92         unsigned int lcdblk_vt_shift;
 93         unsigned int lcdblk_bypass_shift;
 94 
 95         unsigned int has_shadowcon:1;
 96         unsigned int has_clksel:1;
 97         unsigned int has_limited_fmt:1;
 98         unsigned int has_vidoutcon:1;
 99 };
100 
101 static struct fimd_driver_data s3c64xx_fimd_driver_data = {
102         .timing_base = 0x0,
103         .has_clksel = 1,
104         .has_limited_fmt = 1,
105 };
106 
107 static struct fimd_driver_data exynos3_fimd_driver_data = {
108         .timing_base = 0x20000,
109         .lcdblk_offset = 0x210,
110         .lcdblk_bypass_shift = 1,
111         .has_shadowcon = 1,
112         .has_vidoutcon = 1,
113 };
114 
115 static struct fimd_driver_data exynos4_fimd_driver_data = {
116         .timing_base = 0x0,
117         .lcdblk_offset = 0x210,
118         .lcdblk_vt_shift = 10,
119         .lcdblk_bypass_shift = 1,
120         .has_shadowcon = 1,
121 };
122 
123 static struct fimd_driver_data exynos5_fimd_driver_data = {
124         .timing_base = 0x20000,
125         .lcdblk_offset = 0x214,
126         .lcdblk_vt_shift = 24,
127         .lcdblk_bypass_shift = 15,
128         .has_shadowcon = 1,
129         .has_vidoutcon = 1,
130 };
131 
132 struct fimd_win_data {
133         unsigned int            offset_x;
134         unsigned int            offset_y;
135         unsigned int            ovl_width;
136         unsigned int            ovl_height;
137         unsigned int            fb_width;
138         unsigned int            fb_height;
139         unsigned int            bpp;
140         unsigned int            pixel_format;
141         dma_addr_t              dma_addr;
142         unsigned int            buf_offsize;
143         unsigned int            line_size;      /* bytes */
144         bool                    enabled;
145         bool                    resume;
146 };
147 
148 struct fimd_context {
149         struct device                   *dev;
150         struct drm_device               *drm_dev;
151         struct clk                      *bus_clk;
152         struct clk                      *lcd_clk;
153         void __iomem                    *regs;
154         struct regmap                   *sysreg;
155         struct drm_display_mode         mode;
156         struct fimd_win_data            win_data[WINDOWS_NR];
157         unsigned int                    default_win;
158         unsigned long                   irq_flags;
159         u32                             vidcon0;
160         u32                             vidcon1;
161         u32                             vidout_con;
162         u32                             i80ifcon;
163         bool                            i80_if;
164         bool                            suspended;
165         int                             pipe;
166         wait_queue_head_t               wait_vsync_queue;
167         atomic_t                        wait_vsync_event;
168         atomic_t                        win_updated;
169         atomic_t                        triggering;
170 
171         struct exynos_drm_panel_info panel;
172         struct fimd_driver_data *driver_data;
173         struct exynos_drm_display *display;
174 };
175 
176 static const struct of_device_id fimd_driver_dt_match[] = {
177         { .compatible = "samsung,s3c6400-fimd",
178           .data = &s3c64xx_fimd_driver_data },
179         { .compatible = "samsung,exynos3250-fimd",
180           .data = &exynos3_fimd_driver_data },
181         { .compatible = "samsung,exynos4210-fimd",
182           .data = &exynos4_fimd_driver_data },
183         { .compatible = "samsung,exynos5250-fimd",
184           .data = &exynos5_fimd_driver_data },
185         {},
186 };
187 MODULE_DEVICE_TABLE(of, fimd_driver_dt_match);
188 
189 static inline struct fimd_driver_data *drm_fimd_get_driver_data(
190         struct platform_device *pdev)
191 {
192         const struct of_device_id *of_id =
193                         of_match_device(fimd_driver_dt_match, &pdev->dev);
194 
195         return (struct fimd_driver_data *)of_id->data;
196 }
197 
198 static void fimd_wait_for_vblank(struct exynos_drm_manager *mgr)
199 {
200         struct fimd_context *ctx = mgr->ctx;
201 
202         if (ctx->suspended)
203                 return;
204 
205         atomic_set(&ctx->wait_vsync_event, 1);
206 
207         /*
208          * wait for FIMD to signal VSYNC interrupt or return after
209          * timeout which is set to 50ms (refresh rate of 20).
210          */
211         if (!wait_event_timeout(ctx->wait_vsync_queue,
212                                 !atomic_read(&ctx->wait_vsync_event),
213                                 HZ/20))
214                 DRM_DEBUG_KMS("vblank wait timed out.\n");
215 }
216 
217 static void fimd_clear_channel(struct exynos_drm_manager *mgr)
218 {
219         struct fimd_context *ctx = mgr->ctx;
220         int win, ch_enabled = 0;
221 
222         DRM_DEBUG_KMS("%s\n", __FILE__);
223 
224         /* Check if any channel is enabled. */
225         for (win = 0; win < WINDOWS_NR; win++) {
226                 u32 val = readl(ctx->regs + WINCON(win));
227 
228                 if (val & WINCONx_ENWIN) {
229                         /* wincon */
230                         val &= ~WINCONx_ENWIN;
231                         writel(val, ctx->regs + WINCON(win));
232 
233                         /* unprotect windows */
234                         if (ctx->driver_data->has_shadowcon) {
235                                 val = readl(ctx->regs + SHADOWCON);
236                                 val &= ~SHADOWCON_CHx_ENABLE(win);
237                                 writel(val, ctx->regs + SHADOWCON);
238                         }
239                         ch_enabled = 1;
240                 }
241         }
242 
243         /* Wait for vsync, as disable channel takes effect at next vsync */
244         if (ch_enabled) {
245                 unsigned int state = ctx->suspended;
246 
247                 ctx->suspended = 0;
248                 fimd_wait_for_vblank(mgr);
249                 ctx->suspended = state;
250         }
251 }
252 
253 static int fimd_mgr_initialize(struct exynos_drm_manager *mgr,
254                         struct drm_device *drm_dev)
255 {
256         struct fimd_context *ctx = mgr->ctx;
257         struct exynos_drm_private *priv;
258         priv = drm_dev->dev_private;
259 
260         mgr->drm_dev = ctx->drm_dev = drm_dev;
261         mgr->pipe = ctx->pipe = priv->pipe++;
262 
263         /* attach this sub driver to iommu mapping if supported. */
264         if (is_drm_iommu_supported(ctx->drm_dev)) {
265                 /*
266                  * If any channel is already active, iommu will throw
267                  * a PAGE FAULT when enabled. So clear any channel if enabled.
268                  */
269                 fimd_clear_channel(mgr);
270                 drm_iommu_attach_device(ctx->drm_dev, ctx->dev);
271         }
272 
273         return 0;
274 }
275 
276 static void fimd_mgr_remove(struct exynos_drm_manager *mgr)
277 {
278         struct fimd_context *ctx = mgr->ctx;
279 
280         /* detach this sub driver from iommu mapping if supported. */
281         if (is_drm_iommu_supported(ctx->drm_dev))
282                 drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
283 }
284 
285 static u32 fimd_calc_clkdiv(struct fimd_context *ctx,
286                 const struct drm_display_mode *mode)
287 {
288         unsigned long ideal_clk = mode->htotal * mode->vtotal * mode->vrefresh;
289         u32 clkdiv;
290 
291         if (ctx->i80_if) {
292                 /*
293                  * The frame done interrupt should be occurred prior to the
294                  * next TE signal.
295                  */
296                 ideal_clk *= 2;
297         }
298 
299         /* Find the clock divider value that gets us closest to ideal_clk */
300         clkdiv = DIV_ROUND_UP(clk_get_rate(ctx->lcd_clk), ideal_clk);
301 
302         return (clkdiv < 0x100) ? clkdiv : 0xff;
303 }
304 
305 static bool fimd_mode_fixup(struct exynos_drm_manager *mgr,
306                 const struct drm_display_mode *mode,
307                 struct drm_display_mode *adjusted_mode)
308 {
309         if (adjusted_mode->vrefresh == 0)
310                 adjusted_mode->vrefresh = FIMD_DEFAULT_FRAMERATE;
311 
312         return true;
313 }
314 
315 static void fimd_mode_set(struct exynos_drm_manager *mgr,
316                 const struct drm_display_mode *in_mode)
317 {
318         struct fimd_context *ctx = mgr->ctx;
319 
320         drm_mode_copy(&ctx->mode, in_mode);
321 }
322 
323 static void fimd_commit(struct exynos_drm_manager *mgr)
324 {
325         struct fimd_context *ctx = mgr->ctx;
326         struct drm_display_mode *mode = &ctx->mode;
327         struct fimd_driver_data *driver_data = ctx->driver_data;
328         void *timing_base = ctx->regs + driver_data->timing_base;
329         u32 val, clkdiv;
330 
331         if (ctx->suspended)
332                 return;
333 
334         /* nothing to do if we haven't set the mode yet */
335         if (mode->htotal == 0 || mode->vtotal == 0)
336                 return;
337 
338         if (ctx->i80_if) {
339                 val = ctx->i80ifcon | I80IFEN_ENABLE;
340                 writel(val, timing_base + I80IFCONFAx(0));
341 
342                 /* disable auto frame rate */
343                 writel(0, timing_base + I80IFCONFBx(0));
344 
345                 /* set video type selection to I80 interface */
346                 if (ctx->sysreg && regmap_update_bits(ctx->sysreg,
347                                         driver_data->lcdblk_offset,
348                                         0x3 << driver_data->lcdblk_vt_shift,
349                                         0x1 << driver_data->lcdblk_vt_shift)) {
350                         DRM_ERROR("Failed to update sysreg for I80 i/f.\n");
351                         return;
352                 }
353         } else {
354                 int vsync_len, vbpd, vfpd, hsync_len, hbpd, hfpd;
355                 u32 vidcon1;
356 
357                 /* setup polarity values */
358                 vidcon1 = ctx->vidcon1;
359                 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
360                         vidcon1 |= VIDCON1_INV_VSYNC;
361                 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
362                         vidcon1 |= VIDCON1_INV_HSYNC;
363                 writel(vidcon1, ctx->regs + driver_data->timing_base + VIDCON1);
364 
365                 /* setup vertical timing values. */
366                 vsync_len = mode->crtc_vsync_end - mode->crtc_vsync_start;
367                 vbpd = mode->crtc_vtotal - mode->crtc_vsync_end;
368                 vfpd = mode->crtc_vsync_start - mode->crtc_vdisplay;
369 
370                 val = VIDTCON0_VBPD(vbpd - 1) |
371                         VIDTCON0_VFPD(vfpd - 1) |
372                         VIDTCON0_VSPW(vsync_len - 1);
373                 writel(val, ctx->regs + driver_data->timing_base + VIDTCON0);
374 
375                 /* setup horizontal timing values.  */
376                 hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start;
377                 hbpd = mode->crtc_htotal - mode->crtc_hsync_end;
378                 hfpd = mode->crtc_hsync_start - mode->crtc_hdisplay;
379 
380                 val = VIDTCON1_HBPD(hbpd - 1) |
381                         VIDTCON1_HFPD(hfpd - 1) |
382                         VIDTCON1_HSPW(hsync_len - 1);
383                 writel(val, ctx->regs + driver_data->timing_base + VIDTCON1);
384         }
385 
386         if (driver_data->has_vidoutcon)
387                 writel(ctx->vidout_con, timing_base + VIDOUT_CON);
388 
389         /* set bypass selection */
390         if (ctx->sysreg && regmap_update_bits(ctx->sysreg,
391                                 driver_data->lcdblk_offset,
392                                 0x1 << driver_data->lcdblk_bypass_shift,
393                                 0x1 << driver_data->lcdblk_bypass_shift)) {
394                 DRM_ERROR("Failed to update sysreg for bypass setting.\n");
395                 return;
396         }
397 
398         /* setup horizontal and vertical display size. */
399         val = VIDTCON2_LINEVAL(mode->vdisplay - 1) |
400                VIDTCON2_HOZVAL(mode->hdisplay - 1) |
401                VIDTCON2_LINEVAL_E(mode->vdisplay - 1) |
402                VIDTCON2_HOZVAL_E(mode->hdisplay - 1);
403         writel(val, ctx->regs + driver_data->timing_base + VIDTCON2);
404 
405         /*
406          * fields of register with prefix '_F' would be updated
407          * at vsync(same as dma start)
408          */
409         val = ctx->vidcon0;
410         val |= VIDCON0_ENVID | VIDCON0_ENVID_F;
411 
412         if (ctx->driver_data->has_clksel)
413                 val |= VIDCON0_CLKSEL_LCD;
414 
415         clkdiv = fimd_calc_clkdiv(ctx, mode);
416         if (clkdiv > 1)
417                 val |= VIDCON0_CLKVAL_F(clkdiv - 1) | VIDCON0_CLKDIR;
418 
419         writel(val, ctx->regs + VIDCON0);
420 }
421 
422 static int fimd_enable_vblank(struct exynos_drm_manager *mgr)
423 {
424         struct fimd_context *ctx = mgr->ctx;
425         u32 val;
426 
427         if (ctx->suspended)
428                 return -EPERM;
429 
430         if (!test_and_set_bit(0, &ctx->irq_flags)) {
431                 val = readl(ctx->regs + VIDINTCON0);
432 
433                 val |= VIDINTCON0_INT_ENABLE;
434                 val |= VIDINTCON0_INT_FRAME;
435 
436                 val &= ~VIDINTCON0_FRAMESEL0_MASK;
437                 val |= VIDINTCON0_FRAMESEL0_VSYNC;
438                 val &= ~VIDINTCON0_FRAMESEL1_MASK;
439                 val |= VIDINTCON0_FRAMESEL1_NONE;
440 
441                 writel(val, ctx->regs + VIDINTCON0);
442         }
443 
444         return 0;
445 }
446 
447 static void fimd_disable_vblank(struct exynos_drm_manager *mgr)
448 {
449         struct fimd_context *ctx = mgr->ctx;
450         u32 val;
451 
452         if (ctx->suspended)
453                 return;
454 
455         if (test_and_clear_bit(0, &ctx->irq_flags)) {
456                 val = readl(ctx->regs + VIDINTCON0);
457 
458                 val &= ~VIDINTCON0_INT_FRAME;
459                 val &= ~VIDINTCON0_INT_ENABLE;
460 
461                 writel(val, ctx->regs + VIDINTCON0);
462         }
463 }
464 
465 static void fimd_win_mode_set(struct exynos_drm_manager *mgr,
466                         struct exynos_drm_overlay *overlay)
467 {
468         struct fimd_context *ctx = mgr->ctx;
469         struct fimd_win_data *win_data;
470         int win;
471         unsigned long offset;
472 
473         if (!overlay) {
474                 DRM_ERROR("overlay is NULL\n");
475                 return;
476         }
477 
478         win = overlay->zpos;
479         if (win == DEFAULT_ZPOS)
480                 win = ctx->default_win;
481 
482         if (win < 0 || win >= WINDOWS_NR)
483                 return;
484 
485         offset = overlay->fb_x * (overlay->bpp >> 3);
486         offset += overlay->fb_y * overlay->pitch;
487 
488         DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset, overlay->pitch);
489 
490         win_data = &ctx->win_data[win];
491 
492         win_data->offset_x = overlay->crtc_x;
493         win_data->offset_y = overlay->crtc_y;
494         win_data->ovl_width = overlay->crtc_width;
495         win_data->ovl_height = overlay->crtc_height;
496         win_data->fb_width = overlay->fb_width;
497         win_data->fb_height = overlay->fb_height;
498         win_data->dma_addr = overlay->dma_addr[0] + offset;
499         win_data->bpp = overlay->bpp;
500         win_data->pixel_format = overlay->pixel_format;
501         win_data->buf_offsize = (overlay->fb_width - overlay->crtc_width) *
502                                 (overlay->bpp >> 3);
503         win_data->line_size = overlay->crtc_width * (overlay->bpp >> 3);
504 
505         DRM_DEBUG_KMS("offset_x = %d, offset_y = %d\n",
506                         win_data->offset_x, win_data->offset_y);
507         DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
508                         win_data->ovl_width, win_data->ovl_height);
509         DRM_DEBUG_KMS("paddr = 0x%lx\n", (unsigned long)win_data->dma_addr);
510         DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n",
511                         overlay->fb_width, overlay->crtc_width);
512 }
513 
514 static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win)
515 {
516         struct fimd_win_data *win_data = &ctx->win_data[win];
517         unsigned long val;
518 
519         val = WINCONx_ENWIN;
520 
521         /*
522          * In case of s3c64xx, window 0 doesn't support alpha channel.
523          * So the request format is ARGB8888 then change it to XRGB8888.
524          */
525         if (ctx->driver_data->has_limited_fmt && !win) {
526                 if (win_data->pixel_format == DRM_FORMAT_ARGB8888)
527                         win_data->pixel_format = DRM_FORMAT_XRGB8888;
528         }
529 
530         switch (win_data->pixel_format) {
531         case DRM_FORMAT_C8:
532                 val |= WINCON0_BPPMODE_8BPP_PALETTE;
533                 val |= WINCONx_BURSTLEN_8WORD;
534                 val |= WINCONx_BYTSWP;
535                 break;
536         case DRM_FORMAT_XRGB1555:
537                 val |= WINCON0_BPPMODE_16BPP_1555;
538                 val |= WINCONx_HAWSWP;
539                 val |= WINCONx_BURSTLEN_16WORD;
540                 break;
541         case DRM_FORMAT_RGB565:
542                 val |= WINCON0_BPPMODE_16BPP_565;
543                 val |= WINCONx_HAWSWP;
544                 val |= WINCONx_BURSTLEN_16WORD;
545                 break;
546         case DRM_FORMAT_XRGB8888:
547                 val |= WINCON0_BPPMODE_24BPP_888;
548                 val |= WINCONx_WSWP;
549                 val |= WINCONx_BURSTLEN_16WORD;
550                 break;
551         case DRM_FORMAT_ARGB8888:
552                 val |= WINCON1_BPPMODE_25BPP_A1888
553                         | WINCON1_BLD_PIX | WINCON1_ALPHA_SEL;
554                 val |= WINCONx_WSWP;
555                 val |= WINCONx_BURSTLEN_16WORD;
556                 break;
557         default:
558                 DRM_DEBUG_KMS("invalid pixel size so using unpacked 24bpp.\n");
559 
560                 val |= WINCON0_BPPMODE_24BPP_888;
561                 val |= WINCONx_WSWP;
562                 val |= WINCONx_BURSTLEN_16WORD;
563                 break;
564         }
565 
566         DRM_DEBUG_KMS("bpp = %d\n", win_data->bpp);
567 
568         /*
569          * In case of exynos, setting dma-burst to 16Word causes permanent
570          * tearing for very small buffers, e.g. cursor buffer. Burst Mode
571          * switching which is based on overlay size is not recommended as
572          * overlay size varies alot towards the end of the screen and rapid
573          * movement causes unstable DMA which results into iommu crash/tear.
574          */
575 
576         if (win_data->fb_width < MIN_FB_WIDTH_FOR_16WORD_BURST) {
577                 val &= ~WINCONx_BURSTLEN_MASK;
578                 val |= WINCONx_BURSTLEN_4WORD;
579         }
580 
581         writel(val, ctx->regs + WINCON(win));
582 }
583 
584 static void fimd_win_set_colkey(struct fimd_context *ctx, unsigned int win)
585 {
586         unsigned int keycon0 = 0, keycon1 = 0;
587 
588         keycon0 = ~(WxKEYCON0_KEYBL_EN | WxKEYCON0_KEYEN_F |
589                         WxKEYCON0_DIRCON) | WxKEYCON0_COMPKEY(0);
590 
591         keycon1 = WxKEYCON1_COLVAL(0xffffffff);
592 
593         writel(keycon0, ctx->regs + WKEYCON0_BASE(win));
594         writel(keycon1, ctx->regs + WKEYCON1_BASE(win));
595 }
596 
597 /**
598  * shadow_protect_win() - disable updating values from shadow registers at vsync
599  *
600  * @win: window to protect registers for
601  * @protect: 1 to protect (disable updates)
602  */
603 static void fimd_shadow_protect_win(struct fimd_context *ctx,
604                                                         int win, bool protect)
605 {
606         u32 reg, bits, val;
607 
608         if (ctx->driver_data->has_shadowcon) {
609                 reg = SHADOWCON;
610                 bits = SHADOWCON_WINx_PROTECT(win);
611         } else {
612                 reg = PRTCON;
613                 bits = PRTCON_PROTECT;
614         }
615 
616         val = readl(ctx->regs + reg);
617         if (protect)
618                 val |= bits;
619         else
620                 val &= ~bits;
621         writel(val, ctx->regs + reg);
622 }
623 
624 static void fimd_win_commit(struct exynos_drm_manager *mgr, int zpos)
625 {
626         struct fimd_context *ctx = mgr->ctx;
627         struct fimd_win_data *win_data;
628         int win = zpos;
629         unsigned long val, alpha, size;
630         unsigned int last_x;
631         unsigned int last_y;
632 
633         if (ctx->suspended)
634                 return;
635 
636         if (win == DEFAULT_ZPOS)
637                 win = ctx->default_win;
638 
639         if (win < 0 || win >= WINDOWS_NR)
640                 return;
641 
642         win_data = &ctx->win_data[win];
643 
644         /* If suspended, enable this on resume */
645         if (ctx->suspended) {
646                 win_data->resume = true;
647                 return;
648         }
649 
650         /*
651          * SHADOWCON/PRTCON register is used for enabling timing.
652          *
653          * for example, once only width value of a register is set,
654          * if the dma is started then fimd hardware could malfunction so
655          * with protect window setting, the register fields with prefix '_F'
656          * wouldn't be updated at vsync also but updated once unprotect window
657          * is set.
658          */
659 
660         /* protect windows */
661         fimd_shadow_protect_win(ctx, win, true);
662 
663         /* buffer start address */
664         val = (unsigned long)win_data->dma_addr;
665         writel(val, ctx->regs + VIDWx_BUF_START(win, 0));
666 
667         /* buffer end address */
668         size = win_data->fb_width * win_data->ovl_height * (win_data->bpp >> 3);
669         val = (unsigned long)(win_data->dma_addr + size);
670         writel(val, ctx->regs + VIDWx_BUF_END(win, 0));
671 
672         DRM_DEBUG_KMS("start addr = 0x%lx, end addr = 0x%lx, size = 0x%lx\n",
673                         (unsigned long)win_data->dma_addr, val, size);
674         DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
675                         win_data->ovl_width, win_data->ovl_height);
676 
677         /* buffer size */
678         val = VIDW_BUF_SIZE_OFFSET(win_data->buf_offsize) |
679                 VIDW_BUF_SIZE_PAGEWIDTH(win_data->line_size) |
680                 VIDW_BUF_SIZE_OFFSET_E(win_data->buf_offsize) |
681                 VIDW_BUF_SIZE_PAGEWIDTH_E(win_data->line_size);
682         writel(val, ctx->regs + VIDWx_BUF_SIZE(win, 0));
683 
684         /* OSD position */
685         val = VIDOSDxA_TOPLEFT_X(win_data->offset_x) |
686                 VIDOSDxA_TOPLEFT_Y(win_data->offset_y) |
687                 VIDOSDxA_TOPLEFT_X_E(win_data->offset_x) |
688                 VIDOSDxA_TOPLEFT_Y_E(win_data->offset_y);
689         writel(val, ctx->regs + VIDOSD_A(win));
690 
691         last_x = win_data->offset_x + win_data->ovl_width;
692         if (last_x)
693                 last_x--;
694         last_y = win_data->offset_y + win_data->ovl_height;
695         if (last_y)
696                 last_y--;
697 
698         val = VIDOSDxB_BOTRIGHT_X(last_x) | VIDOSDxB_BOTRIGHT_Y(last_y) |
699                 VIDOSDxB_BOTRIGHT_X_E(last_x) | VIDOSDxB_BOTRIGHT_Y_E(last_y);
700 
701         writel(val, ctx->regs + VIDOSD_B(win));
702 
703         DRM_DEBUG_KMS("osd pos: tx = %d, ty = %d, bx = %d, by = %d\n",
704                         win_data->offset_x, win_data->offset_y, last_x, last_y);
705 
706         /* hardware window 0 doesn't support alpha channel. */
707         if (win != 0) {
708                 /* OSD alpha */
709                 alpha = VIDISD14C_ALPHA1_R(0xf) |
710                         VIDISD14C_ALPHA1_G(0xf) |
711                         VIDISD14C_ALPHA1_B(0xf);
712 
713                 writel(alpha, ctx->regs + VIDOSD_C(win));
714         }
715 
716         /* OSD size */
717         if (win != 3 && win != 4) {
718                 u32 offset = VIDOSD_D(win);
719                 if (win == 0)
720                         offset = VIDOSD_C(win);
721                 val = win_data->ovl_width * win_data->ovl_height;
722                 writel(val, ctx->regs + offset);
723 
724                 DRM_DEBUG_KMS("osd size = 0x%x\n", (unsigned int)val);
725         }
726 
727         fimd_win_set_pixfmt(ctx, win);
728 
729         /* hardware window 0 doesn't support color key. */
730         if (win != 0)
731                 fimd_win_set_colkey(ctx, win);
732 
733         /* wincon */
734         val = readl(ctx->regs + WINCON(win));
735         val |= WINCONx_ENWIN;
736         writel(val, ctx->regs + WINCON(win));
737 
738         /* Enable DMA channel and unprotect windows */
739         fimd_shadow_protect_win(ctx, win, false);
740 
741         if (ctx->driver_data->has_shadowcon) {
742                 val = readl(ctx->regs + SHADOWCON);
743                 val |= SHADOWCON_CHx_ENABLE(win);
744                 writel(val, ctx->regs + SHADOWCON);
745         }
746 
747         win_data->enabled = true;
748 
749         if (ctx->i80_if)
750                 atomic_set(&ctx->win_updated, 1);
751 }
752 
753 static void fimd_win_disable(struct exynos_drm_manager *mgr, int zpos)
754 {
755         struct fimd_context *ctx = mgr->ctx;
756         struct fimd_win_data *win_data;
757         int win = zpos;
758         u32 val;
759 
760         if (win == DEFAULT_ZPOS)
761                 win = ctx->default_win;
762 
763         if (win < 0 || win >= WINDOWS_NR)
764                 return;
765 
766         win_data = &ctx->win_data[win];
767 
768         if (ctx->suspended) {
769                 /* do not resume this window*/
770                 win_data->resume = false;
771                 return;
772         }
773 
774         /* protect windows */
775         fimd_shadow_protect_win(ctx, win, true);
776 
777         /* wincon */
778         val = readl(ctx->regs + WINCON(win));
779         val &= ~WINCONx_ENWIN;
780         writel(val, ctx->regs + WINCON(win));
781 
782         /* unprotect windows */
783         if (ctx->driver_data->has_shadowcon) {
784                 val = readl(ctx->regs + SHADOWCON);
785                 val &= ~SHADOWCON_CHx_ENABLE(win);
786                 writel(val, ctx->regs + SHADOWCON);
787         }
788 
789         fimd_shadow_protect_win(ctx, win, false);
790 
791         win_data->enabled = false;
792 }
793 
794 static void fimd_window_suspend(struct exynos_drm_manager *mgr)
795 {
796         struct fimd_context *ctx = mgr->ctx;
797         struct fimd_win_data *win_data;
798         int i;
799 
800         for (i = 0; i < WINDOWS_NR; i++) {
801                 win_data = &ctx->win_data[i];
802                 win_data->resume = win_data->enabled;
803                 if (win_data->enabled)
804                         fimd_win_disable(mgr, i);
805         }
806         fimd_wait_for_vblank(mgr);
807 }
808 
809 static void fimd_window_resume(struct exynos_drm_manager *mgr)
810 {
811         struct fimd_context *ctx = mgr->ctx;
812         struct fimd_win_data *win_data;
813         int i;
814 
815         for (i = 0; i < WINDOWS_NR; i++) {
816                 win_data = &ctx->win_data[i];
817                 win_data->enabled = win_data->resume;
818                 win_data->resume = false;
819         }
820 }
821 
822 static void fimd_apply(struct exynos_drm_manager *mgr)
823 {
824         struct fimd_context *ctx = mgr->ctx;
825         struct fimd_win_data *win_data;
826         int i;
827 
828         for (i = 0; i < WINDOWS_NR; i++) {
829                 win_data = &ctx->win_data[i];
830                 if (win_data->enabled)
831                         fimd_win_commit(mgr, i);
832                 else
833                         fimd_win_disable(mgr, i);
834         }
835 
836         fimd_commit(mgr);
837 }
838 
839 static int fimd_poweron(struct exynos_drm_manager *mgr)
840 {
841         struct fimd_context *ctx = mgr->ctx;
842         int ret;
843 
844         if (!ctx->suspended)
845                 return 0;
846 
847         ctx->suspended = false;
848 
849         pm_runtime_get_sync(ctx->dev);
850 
851         ret = clk_prepare_enable(ctx->bus_clk);
852         if (ret < 0) {
853                 DRM_ERROR("Failed to prepare_enable the bus clk [%d]\n", ret);
854                 goto bus_clk_err;
855         }
856 
857         ret = clk_prepare_enable(ctx->lcd_clk);
858         if  (ret < 0) {
859                 DRM_ERROR("Failed to prepare_enable the lcd clk [%d]\n", ret);
860                 goto lcd_clk_err;
861         }
862 
863         /* if vblank was enabled status, enable it again. */
864         if (test_and_clear_bit(0, &ctx->irq_flags)) {
865                 ret = fimd_enable_vblank(mgr);
866                 if (ret) {
867                         DRM_ERROR("Failed to re-enable vblank [%d]\n", ret);
868                         goto enable_vblank_err;
869                 }
870         }
871 
872         fimd_window_resume(mgr);
873 
874         fimd_apply(mgr);
875 
876         return 0;
877 
878 enable_vblank_err:
879         clk_disable_unprepare(ctx->lcd_clk);
880 lcd_clk_err:
881         clk_disable_unprepare(ctx->bus_clk);
882 bus_clk_err:
883         ctx->suspended = true;
884         return ret;
885 }
886 
887 static int fimd_poweroff(struct exynos_drm_manager *mgr)
888 {
889         struct fimd_context *ctx = mgr->ctx;
890 
891         if (ctx->suspended)
892                 return 0;
893 
894         /*
895          * We need to make sure that all windows are disabled before we
896          * suspend that connector. Otherwise we might try to scan from
897          * a destroyed buffer later.
898          */
899         fimd_window_suspend(mgr);
900 
901         clk_disable_unprepare(ctx->lcd_clk);
902         clk_disable_unprepare(ctx->bus_clk);
903 
904         pm_runtime_put_sync(ctx->dev);
905 
906         ctx->suspended = true;
907         return 0;
908 }
909 
910 static void fimd_dpms(struct exynos_drm_manager *mgr, int mode)
911 {
912         DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode);
913 
914         switch (mode) {
915         case DRM_MODE_DPMS_ON:
916                 fimd_poweron(mgr);
917                 break;
918         case DRM_MODE_DPMS_STANDBY:
919         case DRM_MODE_DPMS_SUSPEND:
920         case DRM_MODE_DPMS_OFF:
921                 fimd_poweroff(mgr);
922                 break;
923         default:
924                 DRM_DEBUG_KMS("unspecified mode %d\n", mode);
925                 break;
926         }
927 }
928 
929 static void fimd_trigger(struct device *dev)
930 {
931         struct exynos_drm_manager *mgr = get_fimd_manager(dev);
932         struct fimd_context *ctx = mgr->ctx;
933         struct fimd_driver_data *driver_data = ctx->driver_data;
934         void *timing_base = ctx->regs + driver_data->timing_base;
935         u32 reg;
936 
937         atomic_set(&ctx->triggering, 1);
938 
939         reg = readl(ctx->regs + VIDINTCON0);
940         reg |= (VIDINTCON0_INT_ENABLE | VIDINTCON0_INT_I80IFDONE |
941                                                 VIDINTCON0_INT_SYSMAINCON);
942         writel(reg, ctx->regs + VIDINTCON0);
943 
944         reg = readl(timing_base + TRIGCON);
945         reg |= (TRGMODE_I80_RGB_ENABLE_I80 | SWTRGCMD_I80_RGB_ENABLE);
946         writel(reg, timing_base + TRIGCON);
947 }
948 
949 static void fimd_te_handler(struct exynos_drm_manager *mgr)
950 {
951         struct fimd_context *ctx = mgr->ctx;
952 
953         /* Checks the crtc is detached already from encoder */
954         if (ctx->pipe < 0 || !ctx->drm_dev)
955                 return;
956 
957          /*
958          * Skips to trigger if in triggering state, because multiple triggering
959          * requests can cause panel reset.
960          */
961         if (atomic_read(&ctx->triggering))
962                 return;
963 
964         /*
965          * If there is a page flip request, triggers and handles the page flip
966          * event so that current fb can be updated into panel GRAM.
967          */
968         if (atomic_add_unless(&ctx->win_updated, -1, 0))
969                 fimd_trigger(ctx->dev);
970 
971         /* Wakes up vsync event queue */
972         if (atomic_read(&ctx->wait_vsync_event)) {
973                 atomic_set(&ctx->wait_vsync_event, 0);
974                 wake_up(&ctx->wait_vsync_queue);
975 
976                 if (!atomic_read(&ctx->triggering))
977                         drm_handle_vblank(ctx->drm_dev, ctx->pipe);
978         }
979 }
980 
981 static struct exynos_drm_manager_ops fimd_manager_ops = {
982         .dpms = fimd_dpms,
983         .mode_fixup = fimd_mode_fixup,
984         .mode_set = fimd_mode_set,
985         .commit = fimd_commit,
986         .enable_vblank = fimd_enable_vblank,
987         .disable_vblank = fimd_disable_vblank,
988         .wait_for_vblank = fimd_wait_for_vblank,
989         .win_mode_set = fimd_win_mode_set,
990         .win_commit = fimd_win_commit,
991         .win_disable = fimd_win_disable,
992         .te_handler = fimd_te_handler,
993 };
994 
995 static struct exynos_drm_manager fimd_manager = {
996         .type = EXYNOS_DISPLAY_TYPE_LCD,
997         .ops = &fimd_manager_ops,
998 };
999 
1000 static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
1001 {
1002         struct fimd_context *ctx = (struct fimd_context *)dev_id;
1003         u32 val, clear_bit;
1004 
1005         val = readl(ctx->regs + VIDINTCON1);
1006 
1007         clear_bit = ctx->i80_if ? VIDINTCON1_INT_I80 : VIDINTCON1_INT_FRAME;
1008         if (val & clear_bit)
1009                 writel(clear_bit, ctx->regs + VIDINTCON1);
1010 
1011         /* check the crtc is detached already from encoder */
1012         if (ctx->pipe < 0 || !ctx->drm_dev)
1013                 goto out;
1014 
1015         if (ctx->i80_if) {
1016                 /* unset I80 frame done interrupt */
1017                 val = readl(ctx->regs + VIDINTCON0);
1018                 val &= ~(VIDINTCON0_INT_I80IFDONE | VIDINTCON0_INT_SYSMAINCON);
1019                 writel(val, ctx->regs + VIDINTCON0);
1020 
1021                 /* exit triggering mode */
1022                 atomic_set(&ctx->triggering, 0);
1023 
1024                 drm_handle_vblank(ctx->drm_dev, ctx->pipe);
1025                 exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
1026         } else {
1027                 drm_handle_vblank(ctx->drm_dev, ctx->pipe);
1028                 exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
1029 
1030                 /* set wait vsync event to zero and wake up queue. */
1031                 if (atomic_read(&ctx->wait_vsync_event)) {
1032                         atomic_set(&ctx->wait_vsync_event, 0);
1033                         wake_up(&ctx->wait_vsync_queue);
1034                 }
1035         }
1036 
1037 out:
1038         return IRQ_HANDLED;
1039 }
1040 
1041 static int fimd_bind(struct device *dev, struct device *master, void *data)
1042 {
1043         struct fimd_context *ctx = fimd_manager.ctx;
1044         struct drm_device *drm_dev = data;
1045 
1046         fimd_mgr_initialize(&fimd_manager, drm_dev);
1047         exynos_drm_crtc_create(&fimd_manager);
1048         if (ctx->display)
1049                 exynos_drm_create_enc_conn(drm_dev, ctx->display);
1050 
1051         return 0;
1052 
1053 }
1054 
1055 static void fimd_unbind(struct device *dev, struct device *master,
1056                         void *data)
1057 {
1058         struct exynos_drm_manager *mgr = dev_get_drvdata(dev);
1059         struct fimd_context *ctx = fimd_manager.ctx;
1060 
1061         fimd_dpms(mgr, DRM_MODE_DPMS_OFF);
1062 
1063         if (ctx->display)
1064                 exynos_dpi_remove(dev);
1065 
1066         fimd_mgr_remove(mgr);
1067 }
1068 
1069 static const struct component_ops fimd_component_ops = {
1070         .bind   = fimd_bind,
1071         .unbind = fimd_unbind,
1072 };
1073 
1074 static int fimd_probe(struct platform_device *pdev)
1075 {
1076         struct device *dev = &pdev->dev;
1077         struct fimd_context *ctx;
1078         struct device_node *i80_if_timings;
1079         struct resource *res;
1080         int ret = -EINVAL;
1081 
1082         ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC,
1083                                         fimd_manager.type);
1084         if (ret)
1085                 return ret;
1086 
1087         if (!dev->of_node) {
1088                 ret = -ENODEV;
1089                 goto err_del_component;
1090         }
1091 
1092         ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
1093         if (!ctx) {
1094                 ret = -ENOMEM;
1095                 goto err_del_component;
1096         }
1097 
1098         ctx->dev = dev;
1099         ctx->suspended = true;
1100         ctx->driver_data = drm_fimd_get_driver_data(pdev);
1101 
1102         if (of_property_read_bool(dev->of_node, "samsung,invert-vden"))
1103                 ctx->vidcon1 |= VIDCON1_INV_VDEN;
1104         if (of_property_read_bool(dev->of_node, "samsung,invert-vclk"))
1105                 ctx->vidcon1 |= VIDCON1_INV_VCLK;
1106 
1107         i80_if_timings = of_get_child_by_name(dev->of_node, "i80-if-timings");
1108         if (i80_if_timings) {
1109                 u32 val;
1110 
1111                 ctx->i80_if = true;
1112 
1113                 if (ctx->driver_data->has_vidoutcon)
1114                         ctx->vidout_con |= VIDOUT_CON_F_I80_LDI0;
1115                 else
1116                         ctx->vidcon0 |= VIDCON0_VIDOUT_I80_LDI0;
1117                 /*
1118                  * The user manual describes that this "DSI_EN" bit is required
1119                  * to enable I80 24-bit data interface.
1120                  */
1121                 ctx->vidcon0 |= VIDCON0_DSI_EN;
1122 
1123                 if (of_property_read_u32(i80_if_timings, "cs-setup", &val))
1124                         val = 0;
1125                 ctx->i80ifcon = LCD_CS_SETUP(val);
1126                 if (of_property_read_u32(i80_if_timings, "wr-setup", &val))
1127                         val = 0;
1128                 ctx->i80ifcon |= LCD_WR_SETUP(val);
1129                 if (of_property_read_u32(i80_if_timings, "wr-active", &val))
1130                         val = 1;
1131                 ctx->i80ifcon |= LCD_WR_ACTIVE(val);
1132                 if (of_property_read_u32(i80_if_timings, "wr-hold", &val))
1133                         val = 0;
1134                 ctx->i80ifcon |= LCD_WR_HOLD(val);
1135         }
1136         of_node_put(i80_if_timings);
1137 
1138         ctx->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node,
1139                                                         "samsung,sysreg");
1140         if (IS_ERR(ctx->sysreg)) {
1141                 dev_warn(dev, "failed to get system register.\n");
1142                 ctx->sysreg = NULL;
1143         }
1144 
1145         ctx->bus_clk = devm_clk_get(dev, "fimd");
1146         if (IS_ERR(ctx->bus_clk)) {
1147                 dev_err(dev, "failed to get bus clock\n");
1148                 ret = PTR_ERR(ctx->bus_clk);
1149                 goto err_del_component;
1150         }
1151 
1152         ctx->lcd_clk = devm_clk_get(dev, "sclk_fimd");
1153         if (IS_ERR(ctx->lcd_clk)) {
1154                 dev_err(dev, "failed to get lcd clock\n");
1155                 ret = PTR_ERR(ctx->lcd_clk);
1156                 goto err_del_component;
1157         }
1158 
1159         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1160 
1161         ctx->regs = devm_ioremap_resource(dev, res);
1162         if (IS_ERR(ctx->regs)) {
1163                 ret = PTR_ERR(ctx->regs);
1164                 goto err_del_component;
1165         }
1166 
1167         res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
1168                                            ctx->i80_if ? "lcd_sys" : "vsync");
1169         if (!res) {
1170                 dev_err(dev, "irq request failed.\n");
1171                 ret = -ENXIO;
1172                 goto err_del_component;
1173         }
1174 
1175         ret = devm_request_irq(dev, res->start, fimd_irq_handler,
1176                                                         0, "drm_fimd", ctx);
1177         if (ret) {
1178                 dev_err(dev, "irq request failed.\n");
1179                 goto err_del_component;
1180         }
1181 
1182         init_waitqueue_head(&ctx->wait_vsync_queue);
1183         atomic_set(&ctx->wait_vsync_event, 0);
1184 
1185         platform_set_drvdata(pdev, &fimd_manager);
1186 
1187         fimd_manager.ctx = ctx;
1188 
1189         ctx->display = exynos_dpi_probe(dev);
1190         if (IS_ERR(ctx->display))
1191                 return PTR_ERR(ctx->display);
1192 
1193         pm_runtime_enable(&pdev->dev);
1194 
1195         ret = component_add(&pdev->dev, &fimd_component_ops);
1196         if (ret)
1197                 goto err_disable_pm_runtime;
1198 
1199         return ret;
1200 
1201 err_disable_pm_runtime:
1202         pm_runtime_disable(&pdev->dev);
1203 
1204 err_del_component:
1205         exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
1206         return ret;
1207 }
1208 
1209 static int fimd_remove(struct platform_device *pdev)
1210 {
1211         pm_runtime_disable(&pdev->dev);
1212 
1213         component_del(&pdev->dev, &fimd_component_ops);
1214         exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
1215 
1216         return 0;
1217 }
1218 
1219 struct platform_driver fimd_driver = {
1220         .probe          = fimd_probe,
1221         .remove         = fimd_remove,
1222         .driver         = {
1223                 .name   = "exynos4-fb",
1224                 .owner  = THIS_MODULE,
1225                 .of_match_table = fimd_driver_dt_match,
1226         },
1227 };
1228 

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