diff options
author | YoungJun Cho <yj44.cho@samsung.com> | 2014-07-17 05:01:21 -0400 |
---|---|---|
committer | Inki Dae <daeinki@gmail.com> | 2014-08-03 03:52:15 -0400 |
commit | 3854fab24e899c02439657956ab1d2c85001958c (patch) | |
tree | 111c35831a6b1f341b62bd1d13f21fbb4c2d4372 | |
parent | e17ddecc3aa519b7e59edf490e34ac036be1f8b8 (diff) |
drm/exynos: fimd: support LCD I80 interface
To support MIPI command mode based I80 interface panel,
FIMD should do followings:
- Sets LCD I80 interface timings configuration.
- Uses "lcd_sys" as an IRQ resource and sets relevant IRQ configuration.
- Sets LCD block configuration for I80 interface.
- Sets ideal(pixel) clock is 2 times faster than the original one
to generate frame done IRQ prior to the next TE signal.
- Implements trigger feature that transfers image data if there is page
flip request, and implements TE handler to call trigger function.
Signed-off-by: YoungJun Cho <yj44.cho@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
-rw-r--r-- | drivers/gpu/drm/exynos/Kconfig | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_fimd.c | 276 | ||||
-rw-r--r-- | include/video/samsung_fimd.h | 3 |
3 files changed, 235 insertions, 45 deletions
diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index 178d2a9672a8..9ba1aaeb8070 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig | |||
@@ -28,6 +28,7 @@ config DRM_EXYNOS_FIMD | |||
28 | bool "Exynos DRM FIMD" | 28 | bool "Exynos DRM FIMD" |
29 | depends on DRM_EXYNOS && !FB_S3C | 29 | depends on DRM_EXYNOS && !FB_S3C |
30 | select FB_MODE_HELPERS | 30 | select FB_MODE_HELPERS |
31 | select MFD_SYSCON | ||
31 | help | 32 | help |
32 | Choose this option if you want to use Exynos FIMD for DRM. | 33 | Choose this option if you want to use Exynos FIMD for DRM. |
33 | 34 | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 33161ad38201..28a3168e24a7 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c | |||
@@ -20,6 +20,8 @@ | |||
20 | #include <linux/of_device.h> | 20 | #include <linux/of_device.h> |
21 | #include <linux/pm_runtime.h> | 21 | #include <linux/pm_runtime.h> |
22 | #include <linux/component.h> | 22 | #include <linux/component.h> |
23 | #include <linux/mfd/syscon.h> | ||
24 | #include <linux/regmap.h> | ||
23 | 25 | ||
24 | #include <video/of_display_timing.h> | 26 | #include <video/of_display_timing.h> |
25 | #include <video/of_videomode.h> | 27 | #include <video/of_videomode.h> |
@@ -61,6 +63,24 @@ | |||
61 | /* color key value register for hardware window 1 ~ 4. */ | 63 | /* color key value register for hardware window 1 ~ 4. */ |
62 | #define WKEYCON1_BASE(x) ((WKEYCON1 + 0x140) + ((x - 1) * 8)) | 64 | #define WKEYCON1_BASE(x) ((WKEYCON1 + 0x140) + ((x - 1) * 8)) |
63 | 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 | |||
64 | /* FIMD has totally five hardware windows. */ | 84 | /* FIMD has totally five hardware windows. */ |
65 | #define WINDOWS_NR 5 | 85 | #define WINDOWS_NR 5 |
66 | 86 | ||
@@ -68,10 +88,14 @@ | |||
68 | 88 | ||
69 | struct fimd_driver_data { | 89 | struct fimd_driver_data { |
70 | unsigned int timing_base; | 90 | unsigned int timing_base; |
91 | unsigned int lcdblk_offset; | ||
92 | unsigned int lcdblk_vt_shift; | ||
93 | unsigned int lcdblk_bypass_shift; | ||
71 | 94 | ||
72 | unsigned int has_shadowcon:1; | 95 | unsigned int has_shadowcon:1; |
73 | unsigned int has_clksel:1; | 96 | unsigned int has_clksel:1; |
74 | unsigned int has_limited_fmt:1; | 97 | unsigned int has_limited_fmt:1; |
98 | unsigned int has_vidoutcon:1; | ||
75 | }; | 99 | }; |
76 | 100 | ||
77 | static struct fimd_driver_data s3c64xx_fimd_driver_data = { | 101 | static struct fimd_driver_data s3c64xx_fimd_driver_data = { |
@@ -82,12 +106,19 @@ static struct fimd_driver_data s3c64xx_fimd_driver_data = { | |||
82 | 106 | ||
83 | static struct fimd_driver_data exynos4_fimd_driver_data = { | 107 | static struct fimd_driver_data exynos4_fimd_driver_data = { |
84 | .timing_base = 0x0, | 108 | .timing_base = 0x0, |
109 | .lcdblk_offset = 0x210, | ||
110 | .lcdblk_vt_shift = 10, | ||
111 | .lcdblk_bypass_shift = 1, | ||
85 | .has_shadowcon = 1, | 112 | .has_shadowcon = 1, |
86 | }; | 113 | }; |
87 | 114 | ||
88 | static struct fimd_driver_data exynos5_fimd_driver_data = { | 115 | static struct fimd_driver_data exynos5_fimd_driver_data = { |
89 | .timing_base = 0x20000, | 116 | .timing_base = 0x20000, |
117 | .lcdblk_offset = 0x214, | ||
118 | .lcdblk_vt_shift = 24, | ||
119 | .lcdblk_bypass_shift = 15, | ||
90 | .has_shadowcon = 1, | 120 | .has_shadowcon = 1, |
121 | .has_vidoutcon = 1, | ||
91 | }; | 122 | }; |
92 | 123 | ||
93 | struct fimd_win_data { | 124 | struct fimd_win_data { |
@@ -112,15 +143,22 @@ struct fimd_context { | |||
112 | struct clk *bus_clk; | 143 | struct clk *bus_clk; |
113 | struct clk *lcd_clk; | 144 | struct clk *lcd_clk; |
114 | void __iomem *regs; | 145 | void __iomem *regs; |
146 | struct regmap *sysreg; | ||
115 | struct drm_display_mode mode; | 147 | struct drm_display_mode mode; |
116 | struct fimd_win_data win_data[WINDOWS_NR]; | 148 | struct fimd_win_data win_data[WINDOWS_NR]; |
117 | unsigned int default_win; | 149 | unsigned int default_win; |
118 | unsigned long irq_flags; | 150 | unsigned long irq_flags; |
151 | u32 vidcon0; | ||
119 | u32 vidcon1; | 152 | u32 vidcon1; |
153 | u32 vidout_con; | ||
154 | u32 i80ifcon; | ||
155 | bool i80_if; | ||
120 | bool suspended; | 156 | bool suspended; |
121 | int pipe; | 157 | int pipe; |
122 | wait_queue_head_t wait_vsync_queue; | 158 | wait_queue_head_t wait_vsync_queue; |
123 | atomic_t wait_vsync_event; | 159 | atomic_t wait_vsync_event; |
160 | atomic_t win_updated; | ||
161 | atomic_t triggering; | ||
124 | 162 | ||
125 | struct exynos_drm_panel_info panel; | 163 | struct exynos_drm_panel_info panel; |
126 | struct fimd_driver_data *driver_data; | 164 | struct fimd_driver_data *driver_data; |
@@ -243,6 +281,14 @@ static u32 fimd_calc_clkdiv(struct fimd_context *ctx, | |||
243 | unsigned long ideal_clk = mode->htotal * mode->vtotal * mode->vrefresh; | 281 | unsigned long ideal_clk = mode->htotal * mode->vtotal * mode->vrefresh; |
244 | u32 clkdiv; | 282 | u32 clkdiv; |
245 | 283 | ||
284 | if (ctx->i80_if) { | ||
285 | /* | ||
286 | * The frame done interrupt should be occurred prior to the | ||
287 | * next TE signal. | ||
288 | */ | ||
289 | ideal_clk *= 2; | ||
290 | } | ||
291 | |||
246 | /* Find the clock divider value that gets us closest to ideal_clk */ | 292 | /* Find the clock divider value that gets us closest to ideal_clk */ |
247 | clkdiv = DIV_ROUND_UP(clk_get_rate(ctx->lcd_clk), ideal_clk); | 293 | clkdiv = DIV_ROUND_UP(clk_get_rate(ctx->lcd_clk), ideal_clk); |
248 | 294 | ||
@@ -271,11 +317,10 @@ static void fimd_commit(struct exynos_drm_manager *mgr) | |||
271 | { | 317 | { |
272 | struct fimd_context *ctx = mgr->ctx; | 318 | struct fimd_context *ctx = mgr->ctx; |
273 | struct drm_display_mode *mode = &ctx->mode; | 319 | struct drm_display_mode *mode = &ctx->mode; |
274 | struct fimd_driver_data *driver_data; | 320 | struct fimd_driver_data *driver_data = ctx->driver_data; |
275 | u32 val, clkdiv, vidcon1; | 321 | void *timing_base = ctx->regs + driver_data->timing_base; |
276 | int vsync_len, vbpd, vfpd, hsync_len, hbpd, hfpd; | 322 | u32 val, clkdiv; |
277 | 323 | ||
278 | driver_data = ctx->driver_data; | ||
279 | if (ctx->suspended) | 324 | if (ctx->suspended) |
280 | return; | 325 | return; |
281 | 326 | ||
@@ -283,33 +328,65 @@ static void fimd_commit(struct exynos_drm_manager *mgr) | |||
283 | if (mode->htotal == 0 || mode->vtotal == 0) | 328 | if (mode->htotal == 0 || mode->vtotal == 0) |
284 | return; | 329 | return; |
285 | 330 | ||
286 | /* setup polarity values */ | 331 | if (ctx->i80_if) { |
287 | vidcon1 = ctx->vidcon1; | 332 | val = ctx->i80ifcon | I80IFEN_ENABLE; |
288 | if (mode->flags & DRM_MODE_FLAG_NVSYNC) | 333 | writel(val, timing_base + I80IFCONFAx(0)); |
289 | vidcon1 |= VIDCON1_INV_VSYNC; | 334 | |
290 | if (mode->flags & DRM_MODE_FLAG_NHSYNC) | 335 | /* disable auto frame rate */ |
291 | vidcon1 |= VIDCON1_INV_HSYNC; | 336 | writel(0, timing_base + I80IFCONFBx(0)); |
292 | writel(vidcon1, ctx->regs + driver_data->timing_base + VIDCON1); | 337 | |
293 | 338 | /* set video type selection to I80 interface */ | |
294 | /* setup vertical timing values. */ | 339 | if (ctx->sysreg && regmap_update_bits(ctx->sysreg, |
295 | vsync_len = mode->crtc_vsync_end - mode->crtc_vsync_start; | 340 | driver_data->lcdblk_offset, |
296 | vbpd = mode->crtc_vtotal - mode->crtc_vsync_end; | 341 | 0x3 << driver_data->lcdblk_vt_shift, |
297 | vfpd = mode->crtc_vsync_start - mode->crtc_vdisplay; | 342 | 0x1 << driver_data->lcdblk_vt_shift)) { |
298 | 343 | DRM_ERROR("Failed to update sysreg for I80 i/f.\n"); | |
299 | val = VIDTCON0_VBPD(vbpd - 1) | | 344 | return; |
300 | VIDTCON0_VFPD(vfpd - 1) | | 345 | } |
301 | VIDTCON0_VSPW(vsync_len - 1); | 346 | } else { |
302 | writel(val, ctx->regs + driver_data->timing_base + VIDTCON0); | 347 | int vsync_len, vbpd, vfpd, hsync_len, hbpd, hfpd; |
303 | 348 | u32 vidcon1; | |
304 | /* setup horizontal timing values. */ | 349 | |
305 | hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start; | 350 | /* setup polarity values */ |
306 | hbpd = mode->crtc_htotal - mode->crtc_hsync_end; | 351 | vidcon1 = ctx->vidcon1; |
307 | hfpd = mode->crtc_hsync_start - mode->crtc_hdisplay; | 352 | if (mode->flags & DRM_MODE_FLAG_NVSYNC) |
308 | 353 | vidcon1 |= VIDCON1_INV_VSYNC; | |
309 | val = VIDTCON1_HBPD(hbpd - 1) | | 354 | if (mode->flags & DRM_MODE_FLAG_NHSYNC) |
310 | VIDTCON1_HFPD(hfpd - 1) | | 355 | vidcon1 |= VIDCON1_INV_HSYNC; |
311 | VIDTCON1_HSPW(hsync_len - 1); | 356 | writel(vidcon1, ctx->regs + driver_data->timing_base + VIDCON1); |
312 | writel(val, ctx->regs + driver_data->timing_base + VIDTCON1); | 357 | |
358 | /* setup vertical timing values. */ | ||
359 | vsync_len = mode->crtc_vsync_end - mode->crtc_vsync_start; | ||
360 | vbpd = mode->crtc_vtotal - mode->crtc_vsync_end; | ||
361 | vfpd = mode->crtc_vsync_start - mode->crtc_vdisplay; | ||
362 | |||
363 | val = VIDTCON0_VBPD(vbpd - 1) | | ||
364 | VIDTCON0_VFPD(vfpd - 1) | | ||
365 | VIDTCON0_VSPW(vsync_len - 1); | ||
366 | writel(val, ctx->regs + driver_data->timing_base + VIDTCON0); | ||
367 | |||
368 | /* setup horizontal timing values. */ | ||
369 | hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start; | ||
370 | hbpd = mode->crtc_htotal - mode->crtc_hsync_end; | ||
371 | hfpd = mode->crtc_hsync_start - mode->crtc_hdisplay; | ||
372 | |||
373 | val = VIDTCON1_HBPD(hbpd - 1) | | ||
374 | VIDTCON1_HFPD(hfpd - 1) | | ||
375 | VIDTCON1_HSPW(hsync_len - 1); | ||
376 | writel(val, ctx->regs + driver_data->timing_base + VIDTCON1); | ||
377 | } | ||
378 | |||
379 | if (driver_data->has_vidoutcon) | ||
380 | writel(ctx->vidout_con, timing_base + VIDOUT_CON); | ||
381 | |||
382 | /* set bypass selection */ | ||
383 | if (ctx->sysreg && regmap_update_bits(ctx->sysreg, | ||
384 | driver_data->lcdblk_offset, | ||
385 | 0x1 << driver_data->lcdblk_bypass_shift, | ||
386 | 0x1 << driver_data->lcdblk_bypass_shift)) { | ||
387 | DRM_ERROR("Failed to update sysreg for bypass setting.\n"); | ||
388 | return; | ||
389 | } | ||
313 | 390 | ||
314 | /* setup horizontal and vertical display size. */ | 391 | /* setup horizontal and vertical display size. */ |
315 | val = VIDTCON2_LINEVAL(mode->vdisplay - 1) | | 392 | val = VIDTCON2_LINEVAL(mode->vdisplay - 1) | |
@@ -322,7 +399,8 @@ static void fimd_commit(struct exynos_drm_manager *mgr) | |||
322 | * fields of register with prefix '_F' would be updated | 399 | * fields of register with prefix '_F' would be updated |
323 | * at vsync(same as dma start) | 400 | * at vsync(same as dma start) |
324 | */ | 401 | */ |
325 | val = VIDCON0_ENVID | VIDCON0_ENVID_F; | 402 | val = ctx->vidcon0; |
403 | val |= VIDCON0_ENVID | VIDCON0_ENVID_F; | ||
326 | 404 | ||
327 | if (ctx->driver_data->has_clksel) | 405 | if (ctx->driver_data->has_clksel) |
328 | val |= VIDCON0_CLKSEL_LCD; | 406 | val |= VIDCON0_CLKSEL_LCD; |
@@ -660,6 +738,9 @@ static void fimd_win_commit(struct exynos_drm_manager *mgr, int zpos) | |||
660 | } | 738 | } |
661 | 739 | ||
662 | win_data->enabled = true; | 740 | win_data->enabled = true; |
741 | |||
742 | if (ctx->i80_if) | ||
743 | atomic_set(&ctx->win_updated, 1); | ||
663 | } | 744 | } |
664 | 745 | ||
665 | static void fimd_win_disable(struct exynos_drm_manager *mgr, int zpos) | 746 | static void fimd_win_disable(struct exynos_drm_manager *mgr, int zpos) |
@@ -838,6 +919,58 @@ static void fimd_dpms(struct exynos_drm_manager *mgr, int mode) | |||
838 | } | 919 | } |
839 | } | 920 | } |
840 | 921 | ||
922 | static void fimd_trigger(struct device *dev) | ||
923 | { | ||
924 | struct exynos_drm_manager *mgr = get_fimd_manager(dev); | ||
925 | struct fimd_context *ctx = mgr->ctx; | ||
926 | struct fimd_driver_data *driver_data = ctx->driver_data; | ||
927 | void *timing_base = ctx->regs + driver_data->timing_base; | ||
928 | u32 reg; | ||
929 | |||
930 | atomic_set(&ctx->triggering, 1); | ||
931 | |||
932 | reg = readl(ctx->regs + VIDINTCON0); | ||
933 | reg |= (VIDINTCON0_INT_ENABLE | VIDINTCON0_INT_I80IFDONE | | ||
934 | VIDINTCON0_INT_SYSMAINCON); | ||
935 | writel(reg, ctx->regs + VIDINTCON0); | ||
936 | |||
937 | reg = readl(timing_base + TRIGCON); | ||
938 | reg |= (TRGMODE_I80_RGB_ENABLE_I80 | SWTRGCMD_I80_RGB_ENABLE); | ||
939 | writel(reg, timing_base + TRIGCON); | ||
940 | } | ||
941 | |||
942 | static void fimd_te_handler(struct exynos_drm_manager *mgr) | ||
943 | { | ||
944 | struct fimd_context *ctx = mgr->ctx; | ||
945 | |||
946 | /* Checks the crtc is detached already from encoder */ | ||
947 | if (ctx->pipe < 0 || !ctx->drm_dev) | ||
948 | return; | ||
949 | |||
950 | /* | ||
951 | * Skips to trigger if in triggering state, because multiple triggering | ||
952 | * requests can cause panel reset. | ||
953 | */ | ||
954 | if (atomic_read(&ctx->triggering)) | ||
955 | return; | ||
956 | |||
957 | /* | ||
958 | * If there is a page flip request, triggers and handles the page flip | ||
959 | * event so that current fb can be updated into panel GRAM. | ||
960 | */ | ||
961 | if (atomic_add_unless(&ctx->win_updated, -1, 0)) | ||
962 | fimd_trigger(ctx->dev); | ||
963 | |||
964 | /* Wakes up vsync event queue */ | ||
965 | if (atomic_read(&ctx->wait_vsync_event)) { | ||
966 | atomic_set(&ctx->wait_vsync_event, 0); | ||
967 | wake_up(&ctx->wait_vsync_queue); | ||
968 | |||
969 | if (!atomic_read(&ctx->triggering)) | ||
970 | drm_handle_vblank(ctx->drm_dev, ctx->pipe); | ||
971 | } | ||
972 | } | ||
973 | |||
841 | static struct exynos_drm_manager_ops fimd_manager_ops = { | 974 | static struct exynos_drm_manager_ops fimd_manager_ops = { |
842 | .dpms = fimd_dpms, | 975 | .dpms = fimd_dpms, |
843 | .mode_fixup = fimd_mode_fixup, | 976 | .mode_fixup = fimd_mode_fixup, |
@@ -849,6 +982,7 @@ static struct exynos_drm_manager_ops fimd_manager_ops = { | |||
849 | .win_mode_set = fimd_win_mode_set, | 982 | .win_mode_set = fimd_win_mode_set, |
850 | .win_commit = fimd_win_commit, | 983 | .win_commit = fimd_win_commit, |
851 | .win_disable = fimd_win_disable, | 984 | .win_disable = fimd_win_disable, |
985 | .te_handler = fimd_te_handler, | ||
852 | }; | 986 | }; |
853 | 987 | ||
854 | static struct exynos_drm_manager fimd_manager = { | 988 | static struct exynos_drm_manager fimd_manager = { |
@@ -859,26 +993,40 @@ static struct exynos_drm_manager fimd_manager = { | |||
859 | static irqreturn_t fimd_irq_handler(int irq, void *dev_id) | 993 | static irqreturn_t fimd_irq_handler(int irq, void *dev_id) |
860 | { | 994 | { |
861 | struct fimd_context *ctx = (struct fimd_context *)dev_id; | 995 | struct fimd_context *ctx = (struct fimd_context *)dev_id; |
862 | u32 val; | 996 | u32 val, clear_bit; |
863 | 997 | ||
864 | val = readl(ctx->regs + VIDINTCON1); | 998 | val = readl(ctx->regs + VIDINTCON1); |
865 | 999 | ||
866 | if (val & VIDINTCON1_INT_FRAME) | 1000 | clear_bit = ctx->i80_if ? VIDINTCON1_INT_I80 : VIDINTCON1_INT_FRAME; |
867 | /* VSYNC interrupt */ | 1001 | if (val & clear_bit) |
868 | writel(VIDINTCON1_INT_FRAME, ctx->regs + VIDINTCON1); | 1002 | writel(clear_bit, ctx->regs + VIDINTCON1); |
869 | 1003 | ||
870 | /* check the crtc is detached already from encoder */ | 1004 | /* check the crtc is detached already from encoder */ |
871 | if (ctx->pipe < 0 || !ctx->drm_dev) | 1005 | if (ctx->pipe < 0 || !ctx->drm_dev) |
872 | goto out; | 1006 | goto out; |
873 | 1007 | ||
874 | drm_handle_vblank(ctx->drm_dev, ctx->pipe); | 1008 | if (ctx->i80_if) { |
875 | exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe); | 1009 | /* unset I80 frame done interrupt */ |
1010 | val = readl(ctx->regs + VIDINTCON0); | ||
1011 | val &= ~(VIDINTCON0_INT_I80IFDONE | VIDINTCON0_INT_SYSMAINCON); | ||
1012 | writel(val, ctx->regs + VIDINTCON0); | ||
876 | 1013 | ||
877 | /* set wait vsync event to zero and wake up queue. */ | 1014 | /* exit triggering mode */ |
878 | if (atomic_read(&ctx->wait_vsync_event)) { | 1015 | atomic_set(&ctx->triggering, 0); |
879 | atomic_set(&ctx->wait_vsync_event, 0); | 1016 | |
880 | wake_up(&ctx->wait_vsync_queue); | 1017 | drm_handle_vblank(ctx->drm_dev, ctx->pipe); |
1018 | exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe); | ||
1019 | } else { | ||
1020 | drm_handle_vblank(ctx->drm_dev, ctx->pipe); | ||
1021 | exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe); | ||
1022 | |||
1023 | /* set wait vsync event to zero and wake up queue. */ | ||
1024 | if (atomic_read(&ctx->wait_vsync_event)) { | ||
1025 | atomic_set(&ctx->wait_vsync_event, 0); | ||
1026 | wake_up(&ctx->wait_vsync_queue); | ||
1027 | } | ||
881 | } | 1028 | } |
1029 | |||
882 | out: | 1030 | out: |
883 | return IRQ_HANDLED; | 1031 | return IRQ_HANDLED; |
884 | } | 1032 | } |
@@ -923,6 +1071,7 @@ static int fimd_probe(struct platform_device *pdev) | |||
923 | { | 1071 | { |
924 | struct device *dev = &pdev->dev; | 1072 | struct device *dev = &pdev->dev; |
925 | struct fimd_context *ctx; | 1073 | struct fimd_context *ctx; |
1074 | struct device_node *i80_if_timings; | ||
926 | struct resource *res; | 1075 | struct resource *res; |
927 | int ret = -EINVAL; | 1076 | int ret = -EINVAL; |
928 | 1077 | ||
@@ -944,12 +1093,51 @@ static int fimd_probe(struct platform_device *pdev) | |||
944 | 1093 | ||
945 | ctx->dev = dev; | 1094 | ctx->dev = dev; |
946 | ctx->suspended = true; | 1095 | ctx->suspended = true; |
1096 | ctx->driver_data = drm_fimd_get_driver_data(pdev); | ||
947 | 1097 | ||
948 | if (of_property_read_bool(dev->of_node, "samsung,invert-vden")) | 1098 | if (of_property_read_bool(dev->of_node, "samsung,invert-vden")) |
949 | ctx->vidcon1 |= VIDCON1_INV_VDEN; | 1099 | ctx->vidcon1 |= VIDCON1_INV_VDEN; |
950 | if (of_property_read_bool(dev->of_node, "samsung,invert-vclk")) | 1100 | if (of_property_read_bool(dev->of_node, "samsung,invert-vclk")) |
951 | ctx->vidcon1 |= VIDCON1_INV_VCLK; | 1101 | ctx->vidcon1 |= VIDCON1_INV_VCLK; |
952 | 1102 | ||
1103 | i80_if_timings = of_get_child_by_name(dev->of_node, "i80-if-timings"); | ||
1104 | if (i80_if_timings) { | ||
1105 | u32 val; | ||
1106 | |||
1107 | ctx->i80_if = true; | ||
1108 | |||
1109 | if (ctx->driver_data->has_vidoutcon) | ||
1110 | ctx->vidout_con |= VIDOUT_CON_F_I80_LDI0; | ||
1111 | else | ||
1112 | ctx->vidcon0 |= VIDCON0_VIDOUT_I80_LDI0; | ||
1113 | /* | ||
1114 | * The user manual describes that this "DSI_EN" bit is required | ||
1115 | * to enable I80 24-bit data interface. | ||
1116 | */ | ||
1117 | ctx->vidcon0 |= VIDCON0_DSI_EN; | ||
1118 | |||
1119 | if (of_property_read_u32(i80_if_timings, "cs-setup", &val)) | ||
1120 | val = 0; | ||
1121 | ctx->i80ifcon = LCD_CS_SETUP(val); | ||
1122 | if (of_property_read_u32(i80_if_timings, "wr-setup", &val)) | ||
1123 | val = 0; | ||
1124 | ctx->i80ifcon |= LCD_WR_SETUP(val); | ||
1125 | if (of_property_read_u32(i80_if_timings, "wr-active", &val)) | ||
1126 | val = 1; | ||
1127 | ctx->i80ifcon |= LCD_WR_ACTIVE(val); | ||
1128 | if (of_property_read_u32(i80_if_timings, "wr-hold", &val)) | ||
1129 | val = 0; | ||
1130 | ctx->i80ifcon |= LCD_WR_HOLD(val); | ||
1131 | } | ||
1132 | of_node_put(i80_if_timings); | ||
1133 | |||
1134 | ctx->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node, | ||
1135 | "samsung,sysreg"); | ||
1136 | if (IS_ERR(ctx->sysreg)) { | ||
1137 | dev_warn(dev, "failed to get system register.\n"); | ||
1138 | ctx->sysreg = NULL; | ||
1139 | } | ||
1140 | |||
953 | ctx->bus_clk = devm_clk_get(dev, "fimd"); | 1141 | ctx->bus_clk = devm_clk_get(dev, "fimd"); |
954 | if (IS_ERR(ctx->bus_clk)) { | 1142 | if (IS_ERR(ctx->bus_clk)) { |
955 | dev_err(dev, "failed to get bus clock\n"); | 1143 | dev_err(dev, "failed to get bus clock\n"); |
@@ -972,7 +1160,8 @@ static int fimd_probe(struct platform_device *pdev) | |||
972 | goto err_del_component; | 1160 | goto err_del_component; |
973 | } | 1161 | } |
974 | 1162 | ||
975 | res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "vsync"); | 1163 | res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, |
1164 | ctx->i80_if ? "lcd_sys" : "vsync"); | ||
976 | if (!res) { | 1165 | if (!res) { |
977 | dev_err(dev, "irq request failed.\n"); | 1166 | dev_err(dev, "irq request failed.\n"); |
978 | ret = -ENXIO; | 1167 | ret = -ENXIO; |
@@ -986,7 +1175,6 @@ static int fimd_probe(struct platform_device *pdev) | |||
986 | goto err_del_component; | 1175 | goto err_del_component; |
987 | } | 1176 | } |
988 | 1177 | ||
989 | ctx->driver_data = drm_fimd_get_driver_data(pdev); | ||
990 | init_waitqueue_head(&ctx->wait_vsync_queue); | 1178 | init_waitqueue_head(&ctx->wait_vsync_queue); |
991 | atomic_set(&ctx->wait_vsync_event, 0); | 1179 | atomic_set(&ctx->wait_vsync_event, 0); |
992 | 1180 | ||
diff --git a/include/video/samsung_fimd.h b/include/video/samsung_fimd.h index b0393209679b..eaad58b5be4a 100644 --- a/include/video/samsung_fimd.h +++ b/include/video/samsung_fimd.h | |||
@@ -19,6 +19,7 @@ | |||
19 | /* VIDCON0 */ | 19 | /* VIDCON0 */ |
20 | 20 | ||
21 | #define VIDCON0 0x00 | 21 | #define VIDCON0 0x00 |
22 | #define VIDCON0_DSI_EN (1 << 30) | ||
22 | #define VIDCON0_INTERLACE (1 << 29) | 23 | #define VIDCON0_INTERLACE (1 << 29) |
23 | #define VIDCON0_VIDOUT_MASK (0x7 << 26) | 24 | #define VIDCON0_VIDOUT_MASK (0x7 << 26) |
24 | #define VIDCON0_VIDOUT_SHIFT 26 | 25 | #define VIDCON0_VIDOUT_SHIFT 26 |
@@ -355,7 +356,7 @@ | |||
355 | #define VIDINTCON0_INT_ENABLE (1 << 0) | 356 | #define VIDINTCON0_INT_ENABLE (1 << 0) |
356 | 357 | ||
357 | #define VIDINTCON1 0x134 | 358 | #define VIDINTCON1 0x134 |
358 | #define VIDINTCON1_INT_I180 (1 << 2) | 359 | #define VIDINTCON1_INT_I80 (1 << 2) |
359 | #define VIDINTCON1_INT_FRAME (1 << 1) | 360 | #define VIDINTCON1_INT_FRAME (1 << 1) |
360 | #define VIDINTCON1_INT_FIFO (1 << 0) | 361 | #define VIDINTCON1_INT_FIFO (1 << 0) |
361 | 362 | ||