diff options
author | Dave Airlie <airlied@redhat.com> | 2017-08-28 20:37:36 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2017-08-28 20:37:36 -0400 |
commit | 7ebdb0dd52404907b8eac2bab476b43a8b8aa9f1 (patch) | |
tree | d54244823f1c17fc60c018d0aee0ccd53f49e1ba | |
parent | 095e2d04f9fa88a7c6923734ab4162833ff4f230 (diff) | |
parent | 5b7b1b7fa10145c014750b09ff4cf31ac4e1843a (diff) |
Merge tag 'exynos-drm-next-for-v4.14' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos into drm-next
Summary:
- Provide NV12MT pixel format support of Mixer driver in generic way.
- Refactor Exynos KMS drivers
. Refactoring to panel detection way
. Refactoring to setting up possible_crtcs
. Refactoring to video and command mode support
- Some cleanups
* tag 'exynos-drm-next-for-v4.14' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos:
drm/exynos: simplify set_pixfmt() in DECON and FIMD drivers
drm/exynos: consistent use of cpp
drm/exynos: mixer: remove src offset from mixer_graph_buffer()
drm/exynos: mixer: simplify mixer_graph_buffer()
drm/exynos: mixer: simplify vp_video_buffer()
drm/exynos: mixer: enable NV12MT support for the video plane
drm/exynos: mixer: fix chroma comment in vp_video_buffer()
arm64: dts: exynos: remove i80-if-timings nodes
dt-bindings: exynos5433-decon: remove i80-if-timings property
drm/exynos/decon5433: use mode info stored in CRTC to detect i80 mode
drm/exynos: add mode_valid callback to exynos_drm
drm/exynos/decon5433: refactor irq requesting code
drm/exynos/mic: use mode info stored in CRTC to detect i80 mode
drm/exynos/dsi: propagate info about command mode from panel
drm/exynos/dsi: refactor panel detection logic
drm/exynos: use helper to set possible crtcs
drm/exynos/decon5433: use readl_poll_timeout helpers
-rw-r--r-- | Documentation/devicetree/bindings/display/exynos/exynos5433-decon.txt | 12 | ||||
-rw-r--r-- | arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 124 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos7_drm_decon.c | 13 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_dp.c | 15 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_core.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_crtc.c | 33 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_crtc.h | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_dpi.c | 12 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_drv.h | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_dsi.c | 218 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_fb.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_fimd.c | 16 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_mic.c | 44 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_plane.c | 27 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_vidi.c | 15 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_hdmi.c | 25 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_mixer.c | 48 |
18 files changed, 299 insertions, 327 deletions
diff --git a/Documentation/devicetree/bindings/display/exynos/exynos5433-decon.txt b/Documentation/devicetree/bindings/display/exynos/exynos5433-decon.txt index 549c538b38a5..fc2588292a68 100644 --- a/Documentation/devicetree/bindings/display/exynos/exynos5433-decon.txt +++ b/Documentation/devicetree/bindings/display/exynos/exynos5433-decon.txt | |||
@@ -25,12 +25,6 @@ Required properties: | |||
25 | size-cells must 1 and 0, respectively. | 25 | size-cells must 1 and 0, respectively. |
26 | - port: contains an endpoint node which is connected to the endpoint in the mic | 26 | - port: contains an endpoint node which is connected to the endpoint in the mic |
27 | node. The reg value muset be 0. | 27 | node. The reg value muset be 0. |
28 | - i80-if-timings: specify whether the panel which is connected to decon uses | ||
29 | i80 lcd interface or mipi video interface. This node contains | ||
30 | no timing information as that of fimd does. Because there is | ||
31 | no register in decon to specify i80 interface timing value, | ||
32 | it is not needed, but make it remain to use same kind of node | ||
33 | in fimd and exynos7 decon. | ||
34 | 28 | ||
35 | Example: | 29 | Example: |
36 | SoC specific DT entry: | 30 | SoC specific DT entry: |
@@ -59,9 +53,3 @@ decon: decon@13800000 { | |||
59 | }; | 53 | }; |
60 | }; | 54 | }; |
61 | }; | 55 | }; |
62 | |||
63 | Board specific DT entry: | ||
64 | &decon { | ||
65 | i80-if-timings { | ||
66 | }; | ||
67 | }; | ||
diff --git a/arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi b/arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi index e2b0da2c0bc7..105b2938082f 100644 --- a/arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi +++ b/arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi | |||
@@ -280,9 +280,6 @@ | |||
280 | 280 | ||
281 | &decon { | 281 | &decon { |
282 | status = "okay"; | 282 | status = "okay"; |
283 | |||
284 | i80-if-timings { | ||
285 | }; | ||
286 | }; | 283 | }; |
287 | 284 | ||
288 | &decon_tv { | 285 | &decon_tv { |
@@ -1116,9 +1113,6 @@ | |||
1116 | 1113 | ||
1117 | &mic { | 1114 | &mic { |
1118 | status = "okay"; | 1115 | status = "okay"; |
1119 | |||
1120 | i80-if-timings { | ||
1121 | }; | ||
1122 | }; | 1116 | }; |
1123 | 1117 | ||
1124 | &pmu_system_controller { | 1118 | &pmu_system_controller { |
diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index 5792ca88ab7a..730b8d9db187 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/platform_device.h> | 13 | #include <linux/platform_device.h> |
14 | #include <linux/clk.h> | 14 | #include <linux/clk.h> |
15 | #include <linux/component.h> | 15 | #include <linux/component.h> |
16 | #include <linux/iopoll.h> | ||
16 | #include <linux/mfd/syscon.h> | 17 | #include <linux/mfd/syscon.h> |
17 | #include <linux/of_device.h> | 18 | #include <linux/of_device.h> |
18 | #include <linux/of_gpio.h> | 19 | #include <linux/of_gpio.h> |
@@ -33,9 +34,8 @@ | |||
33 | #define WINDOWS_NR 3 | 34 | #define WINDOWS_NR 3 |
34 | #define MIN_FB_WIDTH_FOR_16WORD_BURST 128 | 35 | #define MIN_FB_WIDTH_FOR_16WORD_BURST 128 |
35 | 36 | ||
36 | #define IFTYPE_I80 (1 << 0) | 37 | #define I80_HW_TRG (1 << 0) |
37 | #define I80_HW_TRG (1 << 1) | 38 | #define IFTYPE_HDMI (1 << 1) |
38 | #define IFTYPE_HDMI (1 << 2) | ||
39 | 39 | ||
40 | static const char * const decon_clks_name[] = { | 40 | static const char * const decon_clks_name[] = { |
41 | "pclk", | 41 | "pclk", |
@@ -57,6 +57,8 @@ struct decon_context { | |||
57 | struct regmap *sysreg; | 57 | struct regmap *sysreg; |
58 | struct clk *clks[ARRAY_SIZE(decon_clks_name)]; | 58 | struct clk *clks[ARRAY_SIZE(decon_clks_name)]; |
59 | unsigned int irq; | 59 | unsigned int irq; |
60 | unsigned int irq_vsync; | ||
61 | unsigned int irq_lcd_sys; | ||
60 | unsigned int te_irq; | 62 | unsigned int te_irq; |
61 | unsigned long out_type; | 63 | unsigned long out_type; |
62 | int first_win; | 64 | int first_win; |
@@ -90,7 +92,7 @@ static int decon_enable_vblank(struct exynos_drm_crtc *crtc) | |||
90 | u32 val; | 92 | u32 val; |
91 | 93 | ||
92 | val = VIDINTCON0_INTEN; | 94 | val = VIDINTCON0_INTEN; |
93 | if (ctx->out_type & IFTYPE_I80) | 95 | if (crtc->i80_mode) |
94 | val |= VIDINTCON0_FRAMEDONE; | 96 | val |= VIDINTCON0_FRAMEDONE; |
95 | else | 97 | else |
96 | val |= VIDINTCON0_INTFRMEN | VIDINTCON0_FRAMESEL_FP; | 98 | val |= VIDINTCON0_INTFRMEN | VIDINTCON0_FRAMESEL_FP; |
@@ -139,7 +141,7 @@ static u32 decon_get_frame_count(struct decon_context *ctx, bool end) | |||
139 | 141 | ||
140 | switch (status & (VIDCON1_VSTATUS_MASK | VIDCON1_I80_ACTIVE)) { | 142 | switch (status & (VIDCON1_VSTATUS_MASK | VIDCON1_I80_ACTIVE)) { |
141 | case VIDCON1_VSTATUS_VS: | 143 | case VIDCON1_VSTATUS_VS: |
142 | if (!(ctx->out_type & IFTYPE_I80)) | 144 | if (!(ctx->crtc->i80_mode)) |
143 | --frm; | 145 | --frm; |
144 | break; | 146 | break; |
145 | case VIDCON1_VSTATUS_BP: | 147 | case VIDCON1_VSTATUS_BP: |
@@ -166,7 +168,7 @@ static u32 decon_get_vblank_counter(struct exynos_drm_crtc *crtc) | |||
166 | 168 | ||
167 | static void decon_setup_trigger(struct decon_context *ctx) | 169 | static void decon_setup_trigger(struct decon_context *ctx) |
168 | { | 170 | { |
169 | if (!(ctx->out_type & (IFTYPE_I80 | I80_HW_TRG))) | 171 | if (!ctx->crtc->i80_mode && !(ctx->out_type & I80_HW_TRG)) |
170 | return; | 172 | return; |
171 | 173 | ||
172 | if (!(ctx->out_type & I80_HW_TRG)) { | 174 | if (!(ctx->out_type & I80_HW_TRG)) { |
@@ -206,7 +208,7 @@ static void decon_commit(struct exynos_drm_crtc *crtc) | |||
206 | val = VIDOUT_LCD_ON; | 208 | val = VIDOUT_LCD_ON; |
207 | if (interlaced) | 209 | if (interlaced) |
208 | val |= VIDOUT_INTERLACE_EN_F; | 210 | val |= VIDOUT_INTERLACE_EN_F; |
209 | if (ctx->out_type & IFTYPE_I80) { | 211 | if (crtc->i80_mode) { |
210 | val |= VIDOUT_COMMAND_IF; | 212 | val |= VIDOUT_COMMAND_IF; |
211 | } else { | 213 | } else { |
212 | val |= VIDOUT_RGB_IF; | 214 | val |= VIDOUT_RGB_IF; |
@@ -222,7 +224,7 @@ static void decon_commit(struct exynos_drm_crtc *crtc) | |||
222 | VIDTCON2_HOZVAL(m->hdisplay - 1); | 224 | VIDTCON2_HOZVAL(m->hdisplay - 1); |
223 | writel(val, ctx->addr + DECON_VIDTCON2); | 225 | writel(val, ctx->addr + DECON_VIDTCON2); |
224 | 226 | ||
225 | if (!(ctx->out_type & IFTYPE_I80)) { | 227 | if (!crtc->i80_mode) { |
226 | int vbp = m->crtc_vtotal - m->crtc_vsync_end; | 228 | int vbp = m->crtc_vtotal - m->crtc_vsync_end; |
227 | int vfp = m->crtc_vsync_start - m->crtc_vdisplay; | 229 | int vfp = m->crtc_vsync_start - m->crtc_vdisplay; |
228 | 230 | ||
@@ -277,16 +279,14 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win, | |||
277 | val |= WINCONx_BURSTLEN_16WORD; | 279 | val |= WINCONx_BURSTLEN_16WORD; |
278 | break; | 280 | break; |
279 | case DRM_FORMAT_ARGB8888: | 281 | case DRM_FORMAT_ARGB8888: |
282 | default: | ||
280 | val |= WINCONx_BPPMODE_32BPP_A8888; | 283 | val |= WINCONx_BPPMODE_32BPP_A8888; |
281 | val |= WINCONx_WSWP_F | WINCONx_BLD_PIX_F | WINCONx_ALPHA_SEL_F; | 284 | val |= WINCONx_WSWP_F | WINCONx_BLD_PIX_F | WINCONx_ALPHA_SEL_F; |
282 | val |= WINCONx_BURSTLEN_16WORD; | 285 | val |= WINCONx_BURSTLEN_16WORD; |
283 | break; | 286 | break; |
284 | default: | ||
285 | DRM_ERROR("Proper pixel format is not set\n"); | ||
286 | return; | ||
287 | } | 287 | } |
288 | 288 | ||
289 | DRM_DEBUG_KMS("bpp = %u\n", fb->format->cpp[0] * 8); | 289 | DRM_DEBUG_KMS("cpp = %u\n", fb->format->cpp[0]); |
290 | 290 | ||
291 | /* | 291 | /* |
292 | * In case of exynos, setting dma-burst to 16Word causes permanent | 292 | * In case of exynos, setting dma-burst to 16Word causes permanent |
@@ -329,7 +329,7 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, | |||
329 | struct decon_context *ctx = crtc->ctx; | 329 | struct decon_context *ctx = crtc->ctx; |
330 | struct drm_framebuffer *fb = state->base.fb; | 330 | struct drm_framebuffer *fb = state->base.fb; |
331 | unsigned int win = plane->index; | 331 | unsigned int win = plane->index; |
332 | unsigned int bpp = fb->format->cpp[0]; | 332 | unsigned int cpp = fb->format->cpp[0]; |
333 | unsigned int pitch = fb->pitches[0]; | 333 | unsigned int pitch = fb->pitches[0]; |
334 | dma_addr_t dma_addr = exynos_drm_fb_dma_addr(fb, 0); | 334 | dma_addr_t dma_addr = exynos_drm_fb_dma_addr(fb, 0); |
335 | u32 val; | 335 | u32 val; |
@@ -365,11 +365,11 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, | |||
365 | writel(val, ctx->addr + DECON_VIDW0xADD1B0(win)); | 365 | writel(val, ctx->addr + DECON_VIDW0xADD1B0(win)); |
366 | 366 | ||
367 | if (!(ctx->out_type & IFTYPE_HDMI)) | 367 | if (!(ctx->out_type & IFTYPE_HDMI)) |
368 | val = BIT_VAL(pitch - state->crtc.w * bpp, 27, 14) | 368 | val = BIT_VAL(pitch - state->crtc.w * cpp, 27, 14) |
369 | | BIT_VAL(state->crtc.w * bpp, 13, 0); | 369 | | BIT_VAL(state->crtc.w * cpp, 13, 0); |
370 | else | 370 | else |
371 | val = BIT_VAL(pitch - state->crtc.w * bpp, 29, 15) | 371 | val = BIT_VAL(pitch - state->crtc.w * cpp, 29, 15) |
372 | | BIT_VAL(state->crtc.w * bpp, 14, 0); | 372 | | BIT_VAL(state->crtc.w * cpp, 14, 0); |
373 | writel(val, ctx->addr + DECON_VIDW0xADD2(win)); | 373 | writel(val, ctx->addr + DECON_VIDW0xADD2(win)); |
374 | 374 | ||
375 | decon_win_set_pixfmt(ctx, win, fb); | 375 | decon_win_set_pixfmt(ctx, win, fb); |
@@ -407,24 +407,19 @@ static void decon_atomic_flush(struct exynos_drm_crtc *crtc) | |||
407 | 407 | ||
408 | static void decon_swreset(struct decon_context *ctx) | 408 | static void decon_swreset(struct decon_context *ctx) |
409 | { | 409 | { |
410 | unsigned int tries; | ||
411 | unsigned long flags; | 410 | unsigned long flags; |
411 | u32 val; | ||
412 | int ret; | ||
412 | 413 | ||
413 | writel(0, ctx->addr + DECON_VIDCON0); | 414 | writel(0, ctx->addr + DECON_VIDCON0); |
414 | for (tries = 2000; tries; --tries) { | 415 | readl_poll_timeout(ctx->addr + DECON_VIDCON0, val, |
415 | if (~readl(ctx->addr + DECON_VIDCON0) & VIDCON0_STOP_STATUS) | 416 | ~val & VIDCON0_STOP_STATUS, 12, 20000); |
416 | break; | ||
417 | udelay(10); | ||
418 | } | ||
419 | 417 | ||
420 | writel(VIDCON0_SWRESET, ctx->addr + DECON_VIDCON0); | 418 | writel(VIDCON0_SWRESET, ctx->addr + DECON_VIDCON0); |
421 | for (tries = 2000; tries; --tries) { | 419 | ret = readl_poll_timeout(ctx->addr + DECON_VIDCON0, val, |
422 | if (~readl(ctx->addr + DECON_VIDCON0) & VIDCON0_SWRESET) | 420 | ~val & VIDCON0_SWRESET, 12, 20000); |
423 | break; | ||
424 | udelay(10); | ||
425 | } | ||
426 | 421 | ||
427 | WARN(tries == 0, "failed to software reset DECON\n"); | 422 | WARN(ret < 0, "failed to software reset DECON\n"); |
428 | 423 | ||
429 | spin_lock_irqsave(&ctx->vblank_lock, flags); | 424 | spin_lock_irqsave(&ctx->vblank_lock, flags); |
430 | ctx->frame_id = 0; | 425 | ctx->frame_id = 0; |
@@ -515,6 +510,22 @@ err: | |||
515 | clk_disable_unprepare(ctx->clks[i]); | 510 | clk_disable_unprepare(ctx->clks[i]); |
516 | } | 511 | } |
517 | 512 | ||
513 | static enum drm_mode_status decon_mode_valid(struct exynos_drm_crtc *crtc, | ||
514 | const struct drm_display_mode *mode) | ||
515 | { | ||
516 | struct decon_context *ctx = crtc->ctx; | ||
517 | |||
518 | ctx->irq = crtc->i80_mode ? ctx->irq_lcd_sys : ctx->irq_vsync; | ||
519 | |||
520 | if (ctx->irq) | ||
521 | return MODE_OK; | ||
522 | |||
523 | dev_info(ctx->dev, "Sink requires %s mode, but appropriate interrupt is not provided.\n", | ||
524 | crtc->i80_mode ? "command" : "video"); | ||
525 | |||
526 | return MODE_BAD; | ||
527 | } | ||
528 | |||
518 | static const struct exynos_drm_crtc_ops decon_crtc_ops = { | 529 | static const struct exynos_drm_crtc_ops decon_crtc_ops = { |
519 | .enable = decon_enable, | 530 | .enable = decon_enable, |
520 | .disable = decon_disable, | 531 | .disable = decon_disable, |
@@ -524,6 +535,7 @@ static const struct exynos_drm_crtc_ops decon_crtc_ops = { | |||
524 | .atomic_begin = decon_atomic_begin, | 535 | .atomic_begin = decon_atomic_begin, |
525 | .update_plane = decon_update_plane, | 536 | .update_plane = decon_update_plane, |
526 | .disable_plane = decon_disable_plane, | 537 | .disable_plane = decon_disable_plane, |
538 | .mode_valid = decon_mode_valid, | ||
527 | .atomic_flush = decon_atomic_flush, | 539 | .atomic_flush = decon_atomic_flush, |
528 | }; | 540 | }; |
529 | 541 | ||
@@ -674,19 +686,22 @@ static const struct of_device_id exynos5433_decon_driver_dt_match[] = { | |||
674 | MODULE_DEVICE_TABLE(of, exynos5433_decon_driver_dt_match); | 686 | MODULE_DEVICE_TABLE(of, exynos5433_decon_driver_dt_match); |
675 | 687 | ||
676 | static int decon_conf_irq(struct decon_context *ctx, const char *name, | 688 | static int decon_conf_irq(struct decon_context *ctx, const char *name, |
677 | irq_handler_t handler, unsigned long int flags, bool required) | 689 | irq_handler_t handler, unsigned long int flags) |
678 | { | 690 | { |
679 | struct platform_device *pdev = to_platform_device(ctx->dev); | 691 | struct platform_device *pdev = to_platform_device(ctx->dev); |
680 | int ret, irq = platform_get_irq_byname(pdev, name); | 692 | int ret, irq = platform_get_irq_byname(pdev, name); |
681 | 693 | ||
682 | if (irq < 0) { | 694 | if (irq < 0) { |
683 | if (irq == -EPROBE_DEFER) | 695 | switch (irq) { |
696 | case -EPROBE_DEFER: | ||
684 | return irq; | 697 | return irq; |
685 | if (required) | 698 | case -ENODATA: |
686 | dev_err(ctx->dev, "cannot get %s IRQ\n", name); | 699 | case -ENXIO: |
687 | else | 700 | return 0; |
688 | irq = 0; | 701 | default: |
689 | return irq; | 702 | dev_err(ctx->dev, "IRQ %s get failed, %d\n", name, irq); |
703 | return irq; | ||
704 | } | ||
690 | } | 705 | } |
691 | irq_set_status_flags(irq, IRQ_NOAUTOEN); | 706 | irq_set_status_flags(irq, IRQ_NOAUTOEN); |
692 | ret = devm_request_irq(ctx->dev, irq, handler, flags, "drm_decon", ctx); | 707 | ret = devm_request_irq(ctx->dev, irq, handler, flags, "drm_decon", ctx); |
@@ -714,11 +729,8 @@ static int exynos5433_decon_probe(struct platform_device *pdev) | |||
714 | ctx->out_type = (unsigned long)of_device_get_match_data(dev); | 729 | ctx->out_type = (unsigned long)of_device_get_match_data(dev); |
715 | spin_lock_init(&ctx->vblank_lock); | 730 | spin_lock_init(&ctx->vblank_lock); |
716 | 731 | ||
717 | if (ctx->out_type & IFTYPE_HDMI) { | 732 | if (ctx->out_type & IFTYPE_HDMI) |
718 | ctx->first_win = 1; | 733 | ctx->first_win = 1; |
719 | } else if (of_get_child_by_name(dev->of_node, "i80-if-timings")) { | ||
720 | ctx->out_type |= IFTYPE_I80; | ||
721 | } | ||
722 | 734 | ||
723 | for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) { | 735 | for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) { |
724 | struct clk *clk; | 736 | struct clk *clk; |
@@ -742,25 +754,23 @@ static int exynos5433_decon_probe(struct platform_device *pdev) | |||
742 | return PTR_ERR(ctx->addr); | 754 | return PTR_ERR(ctx->addr); |
743 | } | 755 | } |
744 | 756 | ||
745 | if (ctx->out_type & IFTYPE_I80) { | 757 | ret = decon_conf_irq(ctx, "vsync", decon_irq_handler, 0); |
746 | ret = decon_conf_irq(ctx, "lcd_sys", decon_irq_handler, 0, true); | 758 | if (ret < 0) |
747 | if (ret < 0) | 759 | return ret; |
748 | return ret; | 760 | ctx->irq_vsync = ret; |
749 | ctx->irq = ret; | ||
750 | 761 | ||
751 | ret = decon_conf_irq(ctx, "te", decon_te_irq_handler, | 762 | ret = decon_conf_irq(ctx, "lcd_sys", decon_irq_handler, 0); |
752 | IRQF_TRIGGER_RISING, false); | 763 | if (ret < 0) |
753 | if (ret < 0) | 764 | return ret; |
754 | return ret; | 765 | ctx->irq_lcd_sys = ret; |
755 | if (ret) { | 766 | |
756 | ctx->te_irq = ret; | 767 | ret = decon_conf_irq(ctx, "te", decon_te_irq_handler, |
757 | ctx->out_type &= ~I80_HW_TRG; | 768 | IRQF_TRIGGER_RISING); |
758 | } | 769 | if (ret < 0) |
759 | } else { | ||
760 | ret = decon_conf_irq(ctx, "vsync", decon_irq_handler, 0, true); | ||
761 | if (ret < 0) | ||
762 | return ret; | 770 | return ret; |
763 | ctx->irq = ret; | 771 | if (ret) { |
772 | ctx->te_irq = ret; | ||
773 | ctx->out_type &= ~I80_HW_TRG; | ||
764 | } | 774 | } |
765 | 775 | ||
766 | if (ctx->out_type & I80_HW_TRG) { | 776 | if (ctx->out_type & I80_HW_TRG) { |
diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c index 3e88269fdc2e..615efcf7782a 100644 --- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c | |||
@@ -309,19 +309,14 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win, | |||
309 | val |= WINCONx_BURSTLEN_16WORD; | 309 | val |= WINCONx_BURSTLEN_16WORD; |
310 | break; | 310 | break; |
311 | case DRM_FORMAT_BGRA8888: | 311 | case DRM_FORMAT_BGRA8888: |
312 | default: | ||
312 | val |= WINCONx_BPPMODE_32BPP_BGRA | WINCONx_BLD_PIX | | 313 | val |= WINCONx_BPPMODE_32BPP_BGRA | WINCONx_BLD_PIX | |
313 | WINCONx_ALPHA_SEL; | 314 | WINCONx_ALPHA_SEL; |
314 | val |= WINCONx_BURSTLEN_16WORD; | 315 | val |= WINCONx_BURSTLEN_16WORD; |
315 | break; | 316 | break; |
316 | default: | ||
317 | DRM_DEBUG_KMS("invalid pixel size so using unpacked 24bpp.\n"); | ||
318 | |||
319 | val |= WINCONx_BPPMODE_24BPP_xRGB; | ||
320 | val |= WINCONx_BURSTLEN_16WORD; | ||
321 | break; | ||
322 | } | 317 | } |
323 | 318 | ||
324 | DRM_DEBUG_KMS("bpp = %d\n", fb->format->cpp[0] * 8); | 319 | DRM_DEBUG_KMS("cpp = %d\n", fb->format->cpp[0]); |
325 | 320 | ||
326 | /* | 321 | /* |
327 | * In case of exynos, setting dma-burst to 16Word causes permanent | 322 | * In case of exynos, setting dma-burst to 16Word causes permanent |
@@ -398,7 +393,7 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, | |||
398 | unsigned int last_x; | 393 | unsigned int last_x; |
399 | unsigned int last_y; | 394 | unsigned int last_y; |
400 | unsigned int win = plane->index; | 395 | unsigned int win = plane->index; |
401 | unsigned int bpp = fb->format->cpp[0]; | 396 | unsigned int cpp = fb->format->cpp[0]; |
402 | unsigned int pitch = fb->pitches[0]; | 397 | unsigned int pitch = fb->pitches[0]; |
403 | 398 | ||
404 | if (ctx->suspended) | 399 | if (ctx->suspended) |
@@ -418,7 +413,7 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, | |||
418 | val = (unsigned long)exynos_drm_fb_dma_addr(fb, 0); | 413 | val = (unsigned long)exynos_drm_fb_dma_addr(fb, 0); |
419 | writel(val, ctx->regs + VIDW_BUF_START(win)); | 414 | writel(val, ctx->regs + VIDW_BUF_START(win)); |
420 | 415 | ||
421 | padding = (pitch / bpp) - fb->width; | 416 | padding = (pitch / cpp) - fb->width; |
422 | 417 | ||
423 | /* buffer size */ | 418 | /* buffer size */ |
424 | writel(fb->width + padding, ctx->regs + VIDW_WHOLE_X(win)); | 419 | writel(fb->width + padding, ctx->regs + VIDW_WHOLE_X(win)); |
diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c index 385537b726a6..39629e7a80b9 100644 --- a/drivers/gpu/drm/exynos/exynos_dp.c +++ b/drivers/gpu/drm/exynos/exynos_dp.c | |||
@@ -155,7 +155,7 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data) | |||
155 | struct exynos_dp_device *dp = dev_get_drvdata(dev); | 155 | struct exynos_dp_device *dp = dev_get_drvdata(dev); |
156 | struct drm_encoder *encoder = &dp->encoder; | 156 | struct drm_encoder *encoder = &dp->encoder; |
157 | struct drm_device *drm_dev = data; | 157 | struct drm_device *drm_dev = data; |
158 | int pipe, ret; | 158 | int ret; |
159 | 159 | ||
160 | /* | 160 | /* |
161 | * Just like the probe function said, we don't need the | 161 | * Just like the probe function said, we don't need the |
@@ -179,20 +179,15 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data) | |||
179 | return ret; | 179 | return ret; |
180 | } | 180 | } |
181 | 181 | ||
182 | pipe = exynos_drm_crtc_get_pipe_from_type(drm_dev, | ||
183 | EXYNOS_DISPLAY_TYPE_LCD); | ||
184 | if (pipe < 0) | ||
185 | return pipe; | ||
186 | |||
187 | encoder->possible_crtcs = 1 << pipe; | ||
188 | |||
189 | DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs); | ||
190 | |||
191 | drm_encoder_init(drm_dev, encoder, &exynos_dp_encoder_funcs, | 182 | drm_encoder_init(drm_dev, encoder, &exynos_dp_encoder_funcs, |
192 | DRM_MODE_ENCODER_TMDS, NULL); | 183 | DRM_MODE_ENCODER_TMDS, NULL); |
193 | 184 | ||
194 | drm_encoder_helper_add(encoder, &exynos_dp_encoder_helper_funcs); | 185 | drm_encoder_helper_add(encoder, &exynos_dp_encoder_helper_funcs); |
195 | 186 | ||
187 | ret = exynos_drm_set_possible_crtcs(encoder, EXYNOS_DISPLAY_TYPE_LCD); | ||
188 | if (ret < 0) | ||
189 | return ret; | ||
190 | |||
196 | dp->plat_data.encoder = encoder; | 191 | dp->plat_data.encoder = encoder; |
197 | 192 | ||
198 | return analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data); | 193 | return analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data); |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c index edbd98ff293e..b0c0621fcdf7 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_core.c +++ b/drivers/gpu/drm/exynos/exynos_drm_core.c | |||
@@ -13,6 +13,7 @@ | |||
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <drm/drmP.h> | 15 | #include <drm/drmP.h> |
16 | |||
16 | #include "exynos_drm_drv.h" | 17 | #include "exynos_drm_drv.h" |
17 | #include "exynos_drm_crtc.h" | 18 | #include "exynos_drm_crtc.h" |
18 | 19 | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index c37078fbe0ea..6ce0821590df 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <drm/drm_crtc_helper.h> | 16 | #include <drm/drm_crtc_helper.h> |
17 | #include <drm/drm_atomic.h> | 17 | #include <drm/drm_atomic.h> |
18 | #include <drm/drm_atomic_helper.h> | 18 | #include <drm/drm_atomic_helper.h> |
19 | #include <drm/drm_encoder.h> | ||
19 | 20 | ||
20 | #include "exynos_drm_crtc.h" | 21 | #include "exynos_drm_crtc.h" |
21 | #include "exynos_drm_drv.h" | 22 | #include "exynos_drm_drv.h" |
@@ -83,7 +84,19 @@ static void exynos_crtc_atomic_flush(struct drm_crtc *crtc, | |||
83 | exynos_crtc->ops->atomic_flush(exynos_crtc); | 84 | exynos_crtc->ops->atomic_flush(exynos_crtc); |
84 | } | 85 | } |
85 | 86 | ||
87 | static enum drm_mode_status exynos_crtc_mode_valid(struct drm_crtc *crtc, | ||
88 | const struct drm_display_mode *mode) | ||
89 | { | ||
90 | struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); | ||
91 | |||
92 | if (exynos_crtc->ops->mode_valid) | ||
93 | return exynos_crtc->ops->mode_valid(exynos_crtc, mode); | ||
94 | |||
95 | return MODE_OK; | ||
96 | } | ||
97 | |||
86 | static const struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = { | 98 | static const struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = { |
99 | .mode_valid = exynos_crtc_mode_valid, | ||
87 | .atomic_check = exynos_crtc_atomic_check, | 100 | .atomic_check = exynos_crtc_atomic_check, |
88 | .atomic_begin = exynos_crtc_atomic_begin, | 101 | .atomic_begin = exynos_crtc_atomic_begin, |
89 | .atomic_flush = exynos_crtc_atomic_flush, | 102 | .atomic_flush = exynos_crtc_atomic_flush, |
@@ -191,16 +204,30 @@ err_crtc: | |||
191 | return ERR_PTR(ret); | 204 | return ERR_PTR(ret); |
192 | } | 205 | } |
193 | 206 | ||
194 | int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev, | 207 | struct exynos_drm_crtc *exynos_drm_crtc_get_by_type(struct drm_device *drm_dev, |
195 | enum exynos_drm_output_type out_type) | 208 | enum exynos_drm_output_type out_type) |
196 | { | 209 | { |
197 | struct drm_crtc *crtc; | 210 | struct drm_crtc *crtc; |
198 | 211 | ||
199 | drm_for_each_crtc(crtc, drm_dev) | 212 | drm_for_each_crtc(crtc, drm_dev) |
200 | if (to_exynos_crtc(crtc)->type == out_type) | 213 | if (to_exynos_crtc(crtc)->type == out_type) |
201 | return drm_crtc_index(crtc); | 214 | return to_exynos_crtc(crtc); |
202 | 215 | ||
203 | return -EPERM; | 216 | return ERR_PTR(-EPERM); |
217 | } | ||
218 | |||
219 | int exynos_drm_set_possible_crtcs(struct drm_encoder *encoder, | ||
220 | enum exynos_drm_output_type out_type) | ||
221 | { | ||
222 | struct exynos_drm_crtc *crtc = exynos_drm_crtc_get_by_type(encoder->dev, | ||
223 | out_type); | ||
224 | |||
225 | if (IS_ERR(crtc)) | ||
226 | return PTR_ERR(crtc); | ||
227 | |||
228 | encoder->possible_crtcs = drm_crtc_mask(&crtc->base); | ||
229 | |||
230 | return 0; | ||
204 | } | 231 | } |
205 | 232 | ||
206 | void exynos_drm_crtc_te_handler(struct drm_crtc *crtc) | 233 | void exynos_drm_crtc_te_handler(struct drm_crtc *crtc) |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.h b/drivers/gpu/drm/exynos/exynos_drm_crtc.h index ef58b64e3d2d..dec446109e6c 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.h +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.h | |||
@@ -15,21 +15,25 @@ | |||
15 | #ifndef _EXYNOS_DRM_CRTC_H_ | 15 | #ifndef _EXYNOS_DRM_CRTC_H_ |
16 | #define _EXYNOS_DRM_CRTC_H_ | 16 | #define _EXYNOS_DRM_CRTC_H_ |
17 | 17 | ||
18 | |||
18 | #include "exynos_drm_drv.h" | 19 | #include "exynos_drm_drv.h" |
19 | 20 | ||
20 | struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, | 21 | struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, |
21 | struct drm_plane *plane, | 22 | struct drm_plane *plane, |
22 | enum exynos_drm_output_type type, | 23 | enum exynos_drm_output_type out_type, |
23 | const struct exynos_drm_crtc_ops *ops, | 24 | const struct exynos_drm_crtc_ops *ops, |
24 | void *context); | 25 | void *context); |
25 | void exynos_drm_crtc_wait_pending_update(struct exynos_drm_crtc *exynos_crtc); | 26 | void exynos_drm_crtc_wait_pending_update(struct exynos_drm_crtc *exynos_crtc); |
26 | void exynos_drm_crtc_finish_update(struct exynos_drm_crtc *exynos_crtc, | 27 | void exynos_drm_crtc_finish_update(struct exynos_drm_crtc *exynos_crtc, |
27 | struct exynos_drm_plane *exynos_plane); | 28 | struct exynos_drm_plane *exynos_plane); |
28 | 29 | ||
29 | /* This function gets pipe value to crtc device matched with out_type. */ | 30 | /* This function gets crtc device matched with out_type. */ |
30 | int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev, | 31 | struct exynos_drm_crtc *exynos_drm_crtc_get_by_type(struct drm_device *drm_dev, |
31 | enum exynos_drm_output_type out_type); | 32 | enum exynos_drm_output_type out_type); |
32 | 33 | ||
34 | int exynos_drm_set_possible_crtcs(struct drm_encoder *encoder, | ||
35 | enum exynos_drm_output_type out_type); | ||
36 | |||
33 | /* | 37 | /* |
34 | * This function calls the crtc device(manager)'s te_handler() callback | 38 | * This function calls the crtc device(manager)'s te_handler() callback |
35 | * to trigger to transfer video image at the tearing effect synchronization | 39 | * to trigger to transfer video image at the tearing effect synchronization |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c index 76d80e5de521..66945e0dc57f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c | |||
@@ -202,19 +202,15 @@ int exynos_dpi_bind(struct drm_device *dev, struct drm_encoder *encoder) | |||
202 | { | 202 | { |
203 | int ret; | 203 | int ret; |
204 | 204 | ||
205 | ret = exynos_drm_crtc_get_pipe_from_type(dev, EXYNOS_DISPLAY_TYPE_LCD); | ||
206 | if (ret < 0) | ||
207 | return ret; | ||
208 | |||
209 | encoder->possible_crtcs = 1 << ret; | ||
210 | |||
211 | DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs); | ||
212 | |||
213 | drm_encoder_init(dev, encoder, &exynos_dpi_encoder_funcs, | 205 | drm_encoder_init(dev, encoder, &exynos_dpi_encoder_funcs, |
214 | DRM_MODE_ENCODER_TMDS, NULL); | 206 | DRM_MODE_ENCODER_TMDS, NULL); |
215 | 207 | ||
216 | drm_encoder_helper_add(encoder, &exynos_dpi_encoder_helper_funcs); | 208 | drm_encoder_helper_add(encoder, &exynos_dpi_encoder_helper_funcs); |
217 | 209 | ||
210 | ret = exynos_drm_set_possible_crtcs(encoder, EXYNOS_DISPLAY_TYPE_LCD); | ||
211 | if (ret < 0) | ||
212 | return ret; | ||
213 | |||
218 | ret = exynos_dpi_create_connector(encoder); | 214 | ret = exynos_dpi_create_connector(encoder); |
219 | if (ret) { | 215 | if (ret) { |
220 | DRM_ERROR("failed to create connector ret = %d\n", ret); | 216 | DRM_ERROR("failed to create connector ret = %d\n", ret); |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index a93de321706b..cf131c2aa23e 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h | |||
@@ -91,6 +91,7 @@ struct exynos_drm_plane { | |||
91 | #define EXYNOS_DRM_PLANE_CAP_DOUBLE (1 << 0) | 91 | #define EXYNOS_DRM_PLANE_CAP_DOUBLE (1 << 0) |
92 | #define EXYNOS_DRM_PLANE_CAP_SCALE (1 << 1) | 92 | #define EXYNOS_DRM_PLANE_CAP_SCALE (1 << 1) |
93 | #define EXYNOS_DRM_PLANE_CAP_ZPOS (1 << 2) | 93 | #define EXYNOS_DRM_PLANE_CAP_ZPOS (1 << 2) |
94 | #define EXYNOS_DRM_PLANE_CAP_TILE (1 << 3) | ||
94 | 95 | ||
95 | /* | 96 | /* |
96 | * Exynos DRM plane configuration structure. | 97 | * Exynos DRM plane configuration structure. |
@@ -117,6 +118,7 @@ struct exynos_drm_plane_config { | |||
117 | * @disable: disable the device | 118 | * @disable: disable the device |
118 | * @enable_vblank: specific driver callback for enabling vblank interrupt. | 119 | * @enable_vblank: specific driver callback for enabling vblank interrupt. |
119 | * @disable_vblank: specific driver callback for disabling vblank interrupt. | 120 | * @disable_vblank: specific driver callback for disabling vblank interrupt. |
121 | * @mode_valid: specific driver callback for mode validation | ||
120 | * @atomic_check: validate state | 122 | * @atomic_check: validate state |
121 | * @atomic_begin: prepare device to receive an update | 123 | * @atomic_begin: prepare device to receive an update |
122 | * @atomic_flush: mark the end of device update | 124 | * @atomic_flush: mark the end of device update |
@@ -132,6 +134,8 @@ struct exynos_drm_crtc_ops { | |||
132 | int (*enable_vblank)(struct exynos_drm_crtc *crtc); | 134 | int (*enable_vblank)(struct exynos_drm_crtc *crtc); |
133 | void (*disable_vblank)(struct exynos_drm_crtc *crtc); | 135 | void (*disable_vblank)(struct exynos_drm_crtc *crtc); |
134 | u32 (*get_vblank_counter)(struct exynos_drm_crtc *crtc); | 136 | u32 (*get_vblank_counter)(struct exynos_drm_crtc *crtc); |
137 | enum drm_mode_status (*mode_valid)(struct exynos_drm_crtc *crtc, | ||
138 | const struct drm_display_mode *mode); | ||
135 | int (*atomic_check)(struct exynos_drm_crtc *crtc, | 139 | int (*atomic_check)(struct exynos_drm_crtc *crtc, |
136 | struct drm_crtc_state *state); | 140 | struct drm_crtc_state *state); |
137 | void (*atomic_begin)(struct exynos_drm_crtc *crtc); | 141 | void (*atomic_begin)(struct exynos_drm_crtc *crtc); |
@@ -162,6 +166,7 @@ struct exynos_drm_crtc { | |||
162 | const struct exynos_drm_crtc_ops *ops; | 166 | const struct exynos_drm_crtc_ops *ops; |
163 | void *ctx; | 167 | void *ctx; |
164 | struct exynos_drm_clk *pipe_clk; | 168 | struct exynos_drm_clk *pipe_clk; |
169 | bool i80_mode : 1; | ||
165 | }; | 170 | }; |
166 | 171 | ||
167 | static inline void exynos_drm_pipe_clk_enable(struct exynos_drm_crtc *crtc, | 172 | static inline void exynos_drm_pipe_clk_enable(struct exynos_drm_crtc *crtc, |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index c399dc9b325f..7904ffa9abfb 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c | |||
@@ -254,7 +254,6 @@ struct exynos_dsi { | |||
254 | struct drm_encoder encoder; | 254 | struct drm_encoder encoder; |
255 | struct mipi_dsi_host dsi_host; | 255 | struct mipi_dsi_host dsi_host; |
256 | struct drm_connector connector; | 256 | struct drm_connector connector; |
257 | struct device_node *panel_node; | ||
258 | struct drm_panel *panel; | 257 | struct drm_panel *panel; |
259 | struct device *dev; | 258 | struct device *dev; |
260 | 259 | ||
@@ -1329,12 +1328,13 @@ static int exynos_dsi_init(struct exynos_dsi *dsi) | |||
1329 | return 0; | 1328 | return 0; |
1330 | } | 1329 | } |
1331 | 1330 | ||
1332 | static int exynos_dsi_register_te_irq(struct exynos_dsi *dsi) | 1331 | static int exynos_dsi_register_te_irq(struct exynos_dsi *dsi, |
1332 | struct device *panel) | ||
1333 | { | 1333 | { |
1334 | int ret; | 1334 | int ret; |
1335 | int te_gpio_irq; | 1335 | int te_gpio_irq; |
1336 | 1336 | ||
1337 | dsi->te_gpio = of_get_named_gpio(dsi->panel_node, "te-gpios", 0); | 1337 | dsi->te_gpio = of_get_named_gpio(panel->of_node, "te-gpios", 0); |
1338 | if (dsi->te_gpio == -ENOENT) | 1338 | if (dsi->te_gpio == -ENOENT) |
1339 | return 0; | 1339 | return 0; |
1340 | 1340 | ||
@@ -1374,85 +1374,6 @@ static void exynos_dsi_unregister_te_irq(struct exynos_dsi *dsi) | |||
1374 | } | 1374 | } |
1375 | } | 1375 | } |
1376 | 1376 | ||
1377 | static int exynos_dsi_host_attach(struct mipi_dsi_host *host, | ||
1378 | struct mipi_dsi_device *device) | ||
1379 | { | ||
1380 | struct exynos_dsi *dsi = host_to_dsi(host); | ||
1381 | |||
1382 | dsi->lanes = device->lanes; | ||
1383 | dsi->format = device->format; | ||
1384 | dsi->mode_flags = device->mode_flags; | ||
1385 | dsi->panel_node = device->dev.of_node; | ||
1386 | |||
1387 | /* | ||
1388 | * This is a temporary solution and should be made by more generic way. | ||
1389 | * | ||
1390 | * If attached panel device is for command mode one, dsi should register | ||
1391 | * TE interrupt handler. | ||
1392 | */ | ||
1393 | if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO)) { | ||
1394 | int ret = exynos_dsi_register_te_irq(dsi); | ||
1395 | |||
1396 | if (ret) | ||
1397 | return ret; | ||
1398 | } | ||
1399 | |||
1400 | if (dsi->connector.dev) | ||
1401 | drm_helper_hpd_irq_event(dsi->connector.dev); | ||
1402 | |||
1403 | return 0; | ||
1404 | } | ||
1405 | |||
1406 | static int exynos_dsi_host_detach(struct mipi_dsi_host *host, | ||
1407 | struct mipi_dsi_device *device) | ||
1408 | { | ||
1409 | struct exynos_dsi *dsi = host_to_dsi(host); | ||
1410 | |||
1411 | exynos_dsi_unregister_te_irq(dsi); | ||
1412 | |||
1413 | dsi->panel_node = NULL; | ||
1414 | |||
1415 | if (dsi->connector.dev) | ||
1416 | drm_helper_hpd_irq_event(dsi->connector.dev); | ||
1417 | |||
1418 | return 0; | ||
1419 | } | ||
1420 | |||
1421 | static ssize_t exynos_dsi_host_transfer(struct mipi_dsi_host *host, | ||
1422 | const struct mipi_dsi_msg *msg) | ||
1423 | { | ||
1424 | struct exynos_dsi *dsi = host_to_dsi(host); | ||
1425 | struct exynos_dsi_transfer xfer; | ||
1426 | int ret; | ||
1427 | |||
1428 | if (!(dsi->state & DSIM_STATE_ENABLED)) | ||
1429 | return -EINVAL; | ||
1430 | |||
1431 | if (!(dsi->state & DSIM_STATE_INITIALIZED)) { | ||
1432 | ret = exynos_dsi_init(dsi); | ||
1433 | if (ret) | ||
1434 | return ret; | ||
1435 | dsi->state |= DSIM_STATE_INITIALIZED; | ||
1436 | } | ||
1437 | |||
1438 | ret = mipi_dsi_create_packet(&xfer.packet, msg); | ||
1439 | if (ret < 0) | ||
1440 | return ret; | ||
1441 | |||
1442 | xfer.rx_len = msg->rx_len; | ||
1443 | xfer.rx_payload = msg->rx_buf; | ||
1444 | xfer.flags = msg->flags; | ||
1445 | |||
1446 | ret = exynos_dsi_transfer(dsi, &xfer); | ||
1447 | return (ret < 0) ? ret : xfer.rx_done; | ||
1448 | } | ||
1449 | |||
1450 | static const struct mipi_dsi_host_ops exynos_dsi_ops = { | ||
1451 | .attach = exynos_dsi_host_attach, | ||
1452 | .detach = exynos_dsi_host_detach, | ||
1453 | .transfer = exynos_dsi_host_transfer, | ||
1454 | }; | ||
1455 | |||
1456 | static void exynos_dsi_enable(struct drm_encoder *encoder) | 1377 | static void exynos_dsi_enable(struct drm_encoder *encoder) |
1457 | { | 1378 | { |
1458 | struct exynos_dsi *dsi = encoder_to_dsi(encoder); | 1379 | struct exynos_dsi *dsi = encoder_to_dsi(encoder); |
@@ -1508,25 +1429,7 @@ static void exynos_dsi_disable(struct drm_encoder *encoder) | |||
1508 | static enum drm_connector_status | 1429 | static enum drm_connector_status |
1509 | exynos_dsi_detect(struct drm_connector *connector, bool force) | 1430 | exynos_dsi_detect(struct drm_connector *connector, bool force) |
1510 | { | 1431 | { |
1511 | struct exynos_dsi *dsi = connector_to_dsi(connector); | 1432 | return connector->status; |
1512 | |||
1513 | if (!dsi->panel) { | ||
1514 | dsi->panel = of_drm_find_panel(dsi->panel_node); | ||
1515 | if (dsi->panel) | ||
1516 | drm_panel_attach(dsi->panel, &dsi->connector); | ||
1517 | } else if (!dsi->panel_node) { | ||
1518 | struct drm_encoder *encoder; | ||
1519 | |||
1520 | encoder = platform_get_drvdata(to_platform_device(dsi->dev)); | ||
1521 | exynos_dsi_disable(encoder); | ||
1522 | drm_panel_detach(dsi->panel); | ||
1523 | dsi->panel = NULL; | ||
1524 | } | ||
1525 | |||
1526 | if (dsi->panel) | ||
1527 | return connector_status_connected; | ||
1528 | |||
1529 | return connector_status_disconnected; | ||
1530 | } | 1433 | } |
1531 | 1434 | ||
1532 | static void exynos_dsi_connector_destroy(struct drm_connector *connector) | 1435 | static void exynos_dsi_connector_destroy(struct drm_connector *connector) |
@@ -1575,6 +1478,7 @@ static int exynos_dsi_create_connector(struct drm_encoder *encoder) | |||
1575 | return ret; | 1478 | return ret; |
1576 | } | 1479 | } |
1577 | 1480 | ||
1481 | connector->status = connector_status_disconnected; | ||
1578 | drm_connector_helper_add(connector, &exynos_dsi_connector_helper_funcs); | 1482 | drm_connector_helper_add(connector, &exynos_dsi_connector_helper_funcs); |
1579 | drm_mode_connector_attach_encoder(connector, encoder); | 1483 | drm_mode_connector_attach_encoder(connector, encoder); |
1580 | 1484 | ||
@@ -1611,6 +1515,105 @@ static const struct drm_encoder_funcs exynos_dsi_encoder_funcs = { | |||
1611 | 1515 | ||
1612 | MODULE_DEVICE_TABLE(of, exynos_dsi_of_match); | 1516 | MODULE_DEVICE_TABLE(of, exynos_dsi_of_match); |
1613 | 1517 | ||
1518 | static int exynos_dsi_host_attach(struct mipi_dsi_host *host, | ||
1519 | struct mipi_dsi_device *device) | ||
1520 | { | ||
1521 | struct exynos_dsi *dsi = host_to_dsi(host); | ||
1522 | struct drm_device *drm = dsi->connector.dev; | ||
1523 | |||
1524 | /* | ||
1525 | * This is a temporary solution and should be made by more generic way. | ||
1526 | * | ||
1527 | * If attached panel device is for command mode one, dsi should register | ||
1528 | * TE interrupt handler. | ||
1529 | */ | ||
1530 | if (!(device->mode_flags & MIPI_DSI_MODE_VIDEO)) { | ||
1531 | int ret = exynos_dsi_register_te_irq(dsi, &device->dev); | ||
1532 | if (ret) | ||
1533 | return ret; | ||
1534 | } | ||
1535 | |||
1536 | mutex_lock(&drm->mode_config.mutex); | ||
1537 | |||
1538 | dsi->lanes = device->lanes; | ||
1539 | dsi->format = device->format; | ||
1540 | dsi->mode_flags = device->mode_flags; | ||
1541 | dsi->panel = of_drm_find_panel(device->dev.of_node); | ||
1542 | if (dsi->panel) { | ||
1543 | drm_panel_attach(dsi->panel, &dsi->connector); | ||
1544 | dsi->connector.status = connector_status_connected; | ||
1545 | } | ||
1546 | exynos_drm_crtc_get_by_type(drm, EXYNOS_DISPLAY_TYPE_LCD)->i80_mode = | ||
1547 | !(dsi->mode_flags & MIPI_DSI_MODE_VIDEO); | ||
1548 | |||
1549 | mutex_unlock(&drm->mode_config.mutex); | ||
1550 | |||
1551 | if (drm->mode_config.poll_enabled) | ||
1552 | drm_kms_helper_hotplug_event(drm); | ||
1553 | |||
1554 | return 0; | ||
1555 | } | ||
1556 | |||
1557 | static int exynos_dsi_host_detach(struct mipi_dsi_host *host, | ||
1558 | struct mipi_dsi_device *device) | ||
1559 | { | ||
1560 | struct exynos_dsi *dsi = host_to_dsi(host); | ||
1561 | struct drm_device *drm = dsi->connector.dev; | ||
1562 | |||
1563 | mutex_lock(&drm->mode_config.mutex); | ||
1564 | |||
1565 | if (dsi->panel) { | ||
1566 | exynos_dsi_disable(&dsi->encoder); | ||
1567 | drm_panel_detach(dsi->panel); | ||
1568 | dsi->panel = NULL; | ||
1569 | dsi->connector.status = connector_status_disconnected; | ||
1570 | } | ||
1571 | |||
1572 | mutex_unlock(&drm->mode_config.mutex); | ||
1573 | |||
1574 | if (drm->mode_config.poll_enabled) | ||
1575 | drm_kms_helper_hotplug_event(drm); | ||
1576 | |||
1577 | exynos_dsi_unregister_te_irq(dsi); | ||
1578 | |||
1579 | return 0; | ||
1580 | } | ||
1581 | |||
1582 | static ssize_t exynos_dsi_host_transfer(struct mipi_dsi_host *host, | ||
1583 | const struct mipi_dsi_msg *msg) | ||
1584 | { | ||
1585 | struct exynos_dsi *dsi = host_to_dsi(host); | ||
1586 | struct exynos_dsi_transfer xfer; | ||
1587 | int ret; | ||
1588 | |||
1589 | if (!(dsi->state & DSIM_STATE_ENABLED)) | ||
1590 | return -EINVAL; | ||
1591 | |||
1592 | if (!(dsi->state & DSIM_STATE_INITIALIZED)) { | ||
1593 | ret = exynos_dsi_init(dsi); | ||
1594 | if (ret) | ||
1595 | return ret; | ||
1596 | dsi->state |= DSIM_STATE_INITIALIZED; | ||
1597 | } | ||
1598 | |||
1599 | ret = mipi_dsi_create_packet(&xfer.packet, msg); | ||
1600 | if (ret < 0) | ||
1601 | return ret; | ||
1602 | |||
1603 | xfer.rx_len = msg->rx_len; | ||
1604 | xfer.rx_payload = msg->rx_buf; | ||
1605 | xfer.flags = msg->flags; | ||
1606 | |||
1607 | ret = exynos_dsi_transfer(dsi, &xfer); | ||
1608 | return (ret < 0) ? ret : xfer.rx_done; | ||
1609 | } | ||
1610 | |||
1611 | static const struct mipi_dsi_host_ops exynos_dsi_ops = { | ||
1612 | .attach = exynos_dsi_host_attach, | ||
1613 | .detach = exynos_dsi_host_detach, | ||
1614 | .transfer = exynos_dsi_host_transfer, | ||
1615 | }; | ||
1616 | |||
1614 | static int exynos_dsi_of_read_u32(const struct device_node *np, | 1617 | static int exynos_dsi_of_read_u32(const struct device_node *np, |
1615 | const char *propname, u32 *out_value) | 1618 | const char *propname, u32 *out_value) |
1616 | { | 1619 | { |
@@ -1662,20 +1665,15 @@ static int exynos_dsi_bind(struct device *dev, struct device *master, | |||
1662 | struct drm_bridge *bridge; | 1665 | struct drm_bridge *bridge; |
1663 | int ret; | 1666 | int ret; |
1664 | 1667 | ||
1665 | ret = exynos_drm_crtc_get_pipe_from_type(drm_dev, | ||
1666 | EXYNOS_DISPLAY_TYPE_LCD); | ||
1667 | if (ret < 0) | ||
1668 | return ret; | ||
1669 | |||
1670 | encoder->possible_crtcs = 1 << ret; | ||
1671 | |||
1672 | DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs); | ||
1673 | |||
1674 | drm_encoder_init(drm_dev, encoder, &exynos_dsi_encoder_funcs, | 1668 | drm_encoder_init(drm_dev, encoder, &exynos_dsi_encoder_funcs, |
1675 | DRM_MODE_ENCODER_TMDS, NULL); | 1669 | DRM_MODE_ENCODER_TMDS, NULL); |
1676 | 1670 | ||
1677 | drm_encoder_helper_add(encoder, &exynos_dsi_encoder_helper_funcs); | 1671 | drm_encoder_helper_add(encoder, &exynos_dsi_encoder_helper_funcs); |
1678 | 1672 | ||
1673 | ret = exynos_drm_set_possible_crtcs(encoder, EXYNOS_DISPLAY_TYPE_LCD); | ||
1674 | if (ret < 0) | ||
1675 | return ret; | ||
1676 | |||
1679 | ret = exynos_dsi_create_connector(encoder); | 1677 | ret = exynos_dsi_create_connector(encoder); |
1680 | if (ret) { | 1678 | if (ret) { |
1681 | DRM_ERROR("failed to create connector ret = %d\n", ret); | 1679 | DRM_ERROR("failed to create connector ret = %d\n", ret); |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index 6592f50d460a..8208df56a88f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c | |||
@@ -225,4 +225,6 @@ void exynos_drm_mode_config_init(struct drm_device *dev) | |||
225 | 225 | ||
226 | dev->mode_config.funcs = &exynos_drm_mode_config_funcs; | 226 | dev->mode_config.funcs = &exynos_drm_mode_config_funcs; |
227 | dev->mode_config.helper_private = &exynos_drm_mode_config_helpers; | 227 | dev->mode_config.helper_private = &exynos_drm_mode_config_helpers; |
228 | |||
229 | dev->mode_config.allow_fb_modifiers = true; | ||
228 | } | 230 | } |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 60f93cad6643..d42ae2bc3e56 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c | |||
@@ -583,18 +583,12 @@ static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win, | |||
583 | val |= WINCONx_BURSTLEN_16WORD; | 583 | val |= WINCONx_BURSTLEN_16WORD; |
584 | break; | 584 | break; |
585 | case DRM_FORMAT_ARGB8888: | 585 | case DRM_FORMAT_ARGB8888: |
586 | default: | ||
586 | val |= WINCON1_BPPMODE_25BPP_A1888 | 587 | val |= WINCON1_BPPMODE_25BPP_A1888 |
587 | | WINCON1_BLD_PIX | WINCON1_ALPHA_SEL; | 588 | | WINCON1_BLD_PIX | WINCON1_ALPHA_SEL; |
588 | val |= WINCONx_WSWP; | 589 | val |= WINCONx_WSWP; |
589 | val |= WINCONx_BURSTLEN_16WORD; | 590 | val |= WINCONx_BURSTLEN_16WORD; |
590 | break; | 591 | break; |
591 | default: | ||
592 | DRM_DEBUG_KMS("invalid pixel size so using unpacked 24bpp.\n"); | ||
593 | |||
594 | val |= WINCON0_BPPMODE_24BPP_888; | ||
595 | val |= WINCONx_WSWP; | ||
596 | val |= WINCONx_BURSTLEN_16WORD; | ||
597 | break; | ||
598 | } | 592 | } |
599 | 593 | ||
600 | /* | 594 | /* |
@@ -718,13 +712,13 @@ static void fimd_update_plane(struct exynos_drm_crtc *crtc, | |||
718 | unsigned long val, size, offset; | 712 | unsigned long val, size, offset; |
719 | unsigned int last_x, last_y, buf_offsize, line_size; | 713 | unsigned int last_x, last_y, buf_offsize, line_size; |
720 | unsigned int win = plane->index; | 714 | unsigned int win = plane->index; |
721 | unsigned int bpp = fb->format->cpp[0]; | 715 | unsigned int cpp = fb->format->cpp[0]; |
722 | unsigned int pitch = fb->pitches[0]; | 716 | unsigned int pitch = fb->pitches[0]; |
723 | 717 | ||
724 | if (ctx->suspended) | 718 | if (ctx->suspended) |
725 | return; | 719 | return; |
726 | 720 | ||
727 | offset = state->src.x * bpp; | 721 | offset = state->src.x * cpp; |
728 | offset += state->src.y * pitch; | 722 | offset += state->src.y * pitch; |
729 | 723 | ||
730 | /* buffer start address */ | 724 | /* buffer start address */ |
@@ -743,8 +737,8 @@ static void fimd_update_plane(struct exynos_drm_crtc *crtc, | |||
743 | state->crtc.w, state->crtc.h); | 737 | state->crtc.w, state->crtc.h); |
744 | 738 | ||
745 | /* buffer size */ | 739 | /* buffer size */ |
746 | buf_offsize = pitch - (state->crtc.w * bpp); | 740 | buf_offsize = pitch - (state->crtc.w * cpp); |
747 | line_size = state->crtc.w * bpp; | 741 | line_size = state->crtc.w * cpp; |
748 | val = VIDW_BUF_SIZE_OFFSET(buf_offsize) | | 742 | val = VIDW_BUF_SIZE_OFFSET(buf_offsize) | |
749 | VIDW_BUF_SIZE_PAGEWIDTH(line_size) | | 743 | VIDW_BUF_SIZE_PAGEWIDTH(line_size) | |
750 | VIDW_BUF_SIZE_OFFSET_E(buf_offsize) | | 744 | VIDW_BUF_SIZE_OFFSET_E(buf_offsize) | |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_mic.c b/drivers/gpu/drm/exynos/exynos_drm_mic.c index 16bbee897e0d..ba4a32b132ba 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_mic.c +++ b/drivers/gpu/drm/exynos/exynos_drm_mic.c | |||
@@ -21,9 +21,12 @@ | |||
21 | #include <linux/component.h> | 21 | #include <linux/component.h> |
22 | #include <linux/pm_runtime.h> | 22 | #include <linux/pm_runtime.h> |
23 | #include <drm/drmP.h> | 23 | #include <drm/drmP.h> |
24 | #include <drm/drm_encoder.h> | ||
24 | #include <linux/mfd/syscon.h> | 25 | #include <linux/mfd/syscon.h> |
25 | #include <linux/regmap.h> | 26 | #include <linux/regmap.h> |
26 | 27 | ||
28 | #include "exynos_drm_drv.h" | ||
29 | |||
27 | /* Sysreg registers for MIC */ | 30 | /* Sysreg registers for MIC */ |
28 | #define DSD_CFG_MUX 0x1004 | 31 | #define DSD_CFG_MUX 0x1004 |
29 | #define MIC0_RGB_MUX (1 << 0) | 32 | #define MIC0_RGB_MUX (1 << 0) |
@@ -85,12 +88,6 @@ | |||
85 | 88 | ||
86 | #define MIC_BS_SIZE_2D(x) ((x) & 0x3fff) | 89 | #define MIC_BS_SIZE_2D(x) ((x) & 0x3fff) |
87 | 90 | ||
88 | enum { | ||
89 | ENDPOINT_DECON_NODE, | ||
90 | ENDPOINT_DSI_NODE, | ||
91 | NUM_ENDPOINTS | ||
92 | }; | ||
93 | |||
94 | static char *clk_names[] = { "pclk_mic0", "sclk_rgb_vclk_to_mic0" }; | 91 | static char *clk_names[] = { "pclk_mic0", "sclk_rgb_vclk_to_mic0" }; |
95 | #define NUM_CLKS ARRAY_SIZE(clk_names) | 92 | #define NUM_CLKS ARRAY_SIZE(clk_names) |
96 | static DEFINE_MUTEX(mic_mutex); | 93 | static DEFINE_MUTEX(mic_mutex); |
@@ -229,36 +226,6 @@ static void mic_set_reg_on(struct exynos_mic *mic, bool enable) | |||
229 | writel(reg, mic->reg + MIC_OP); | 226 | writel(reg, mic->reg + MIC_OP); |
230 | } | 227 | } |
231 | 228 | ||
232 | static int parse_dt(struct exynos_mic *mic) | ||
233 | { | ||
234 | int ret = 0, i, j; | ||
235 | struct device_node *remote_node; | ||
236 | struct device_node *nodes[3]; | ||
237 | |||
238 | /* | ||
239 | * The order of endpoints does matter. | ||
240 | * The first node must be for decon and the second one must be for dsi. | ||
241 | */ | ||
242 | for (i = 0, j = 0; i < NUM_ENDPOINTS; i++) { | ||
243 | remote_node = of_graph_get_remote_node(mic->dev->of_node, i, 0); | ||
244 | if (!remote_node) { | ||
245 | ret = -EPIPE; | ||
246 | goto exit; | ||
247 | } | ||
248 | nodes[j++] = remote_node; | ||
249 | |||
250 | if (i == ENDPOINT_DECON_NODE && | ||
251 | of_get_child_by_name(remote_node, "i80-if-timings")) | ||
252 | mic->i80_mode = 1; | ||
253 | } | ||
254 | |||
255 | exit: | ||
256 | while (--j > -1) | ||
257 | of_node_put(nodes[j]); | ||
258 | |||
259 | return ret; | ||
260 | } | ||
261 | |||
262 | static void mic_disable(struct drm_bridge *bridge) { } | 229 | static void mic_disable(struct drm_bridge *bridge) { } |
263 | 230 | ||
264 | static void mic_post_disable(struct drm_bridge *bridge) | 231 | static void mic_post_disable(struct drm_bridge *bridge) |
@@ -286,6 +253,7 @@ static void mic_mode_set(struct drm_bridge *bridge, | |||
286 | 253 | ||
287 | mutex_lock(&mic_mutex); | 254 | mutex_lock(&mic_mutex); |
288 | drm_display_mode_to_videomode(mode, &mic->vm); | 255 | drm_display_mode_to_videomode(mode, &mic->vm); |
256 | mic->i80_mode = to_exynos_crtc(bridge->encoder->crtc)->i80_mode; | ||
289 | mutex_unlock(&mic_mutex); | 257 | mutex_unlock(&mic_mutex); |
290 | } | 258 | } |
291 | 259 | ||
@@ -417,10 +385,6 @@ static int exynos_mic_probe(struct platform_device *pdev) | |||
417 | 385 | ||
418 | mic->dev = dev; | 386 | mic->dev = dev; |
419 | 387 | ||
420 | ret = parse_dt(mic); | ||
421 | if (ret) | ||
422 | goto err; | ||
423 | |||
424 | ret = of_address_to_resource(dev->of_node, 0, &res); | 388 | ret = of_address_to_resource(dev->of_node, 0, &res); |
425 | if (ret) { | 389 | if (ret) { |
426 | DRM_ERROR("mic: Failed to get mem region for MIC\n"); | 390 | DRM_ERROR("mic: Failed to get mem region for MIC\n"); |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index 8de74009dee4..d2a90dae5c71 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c | |||
@@ -179,6 +179,29 @@ static struct drm_plane_funcs exynos_plane_funcs = { | |||
179 | }; | 179 | }; |
180 | 180 | ||
181 | static int | 181 | static int |
182 | exynos_drm_plane_check_format(const struct exynos_drm_plane_config *config, | ||
183 | struct exynos_drm_plane_state *state) | ||
184 | { | ||
185 | struct drm_framebuffer *fb = state->base.fb; | ||
186 | |||
187 | switch (fb->modifier) { | ||
188 | case DRM_FORMAT_MOD_SAMSUNG_64_32_TILE: | ||
189 | if (!(config->capabilities & EXYNOS_DRM_PLANE_CAP_TILE)) | ||
190 | return -ENOTSUPP; | ||
191 | break; | ||
192 | |||
193 | case DRM_FORMAT_MOD_LINEAR: | ||
194 | break; | ||
195 | |||
196 | default: | ||
197 | DRM_ERROR("unsupported pixel format modifier"); | ||
198 | return -ENOTSUPP; | ||
199 | } | ||
200 | |||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | static int | ||
182 | exynos_drm_plane_check_size(const struct exynos_drm_plane_config *config, | 205 | exynos_drm_plane_check_size(const struct exynos_drm_plane_config *config, |
183 | struct exynos_drm_plane_state *state) | 206 | struct exynos_drm_plane_state *state) |
184 | { | 207 | { |
@@ -222,6 +245,10 @@ static int exynos_plane_atomic_check(struct drm_plane *plane, | |||
222 | /* translate state into exynos_state */ | 245 | /* translate state into exynos_state */ |
223 | exynos_plane_mode_set(exynos_state); | 246 | exynos_plane_mode_set(exynos_state); |
224 | 247 | ||
248 | ret = exynos_drm_plane_check_format(exynos_plane->config, exynos_state); | ||
249 | if (ret) | ||
250 | return ret; | ||
251 | |||
225 | ret = exynos_drm_plane_check_size(exynos_plane->config, exynos_state); | 252 | ret = exynos_drm_plane_check_size(exynos_plane->config, exynos_state); |
226 | return ret; | 253 | return ret; |
227 | } | 254 | } |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index 9186a654c3b5..53e03f8af3d5 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c | |||
@@ -381,7 +381,7 @@ static int vidi_bind(struct device *dev, struct device *master, void *data) | |||
381 | struct exynos_drm_plane *exynos_plane; | 381 | struct exynos_drm_plane *exynos_plane; |
382 | struct exynos_drm_plane_config plane_config = { 0 }; | 382 | struct exynos_drm_plane_config plane_config = { 0 }; |
383 | unsigned int i; | 383 | unsigned int i; |
384 | int pipe, ret; | 384 | int ret; |
385 | 385 | ||
386 | ctx->drm_dev = drm_dev; | 386 | ctx->drm_dev = drm_dev; |
387 | 387 | ||
@@ -406,20 +406,15 @@ static int vidi_bind(struct device *dev, struct device *master, void *data) | |||
406 | return PTR_ERR(ctx->crtc); | 406 | return PTR_ERR(ctx->crtc); |
407 | } | 407 | } |
408 | 408 | ||
409 | pipe = exynos_drm_crtc_get_pipe_from_type(drm_dev, | ||
410 | EXYNOS_DISPLAY_TYPE_VIDI); | ||
411 | if (pipe < 0) | ||
412 | return pipe; | ||
413 | |||
414 | encoder->possible_crtcs = 1 << pipe; | ||
415 | |||
416 | DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs); | ||
417 | |||
418 | drm_encoder_init(drm_dev, encoder, &exynos_vidi_encoder_funcs, | 409 | drm_encoder_init(drm_dev, encoder, &exynos_vidi_encoder_funcs, |
419 | DRM_MODE_ENCODER_TMDS, NULL); | 410 | DRM_MODE_ENCODER_TMDS, NULL); |
420 | 411 | ||
421 | drm_encoder_helper_add(encoder, &exynos_vidi_encoder_helper_funcs); | 412 | drm_encoder_helper_add(encoder, &exynos_vidi_encoder_helper_funcs); |
422 | 413 | ||
414 | ret = exynos_drm_set_possible_crtcs(encoder, EXYNOS_DISPLAY_TYPE_VIDI); | ||
415 | if (ret < 0) | ||
416 | return ret; | ||
417 | |||
423 | ret = vidi_create_connector(encoder); | 418 | ret = vidi_create_connector(encoder); |
424 | if (ret) { | 419 | if (ret) { |
425 | DRM_ERROR("failed to create connector ret = %d\n", ret); | 420 | DRM_ERROR("failed to create connector ret = %d\n", ret); |
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index d70eeb8c5f75..214fa5e51963 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c | |||
@@ -1697,32 +1697,25 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data) | |||
1697 | struct drm_device *drm_dev = data; | 1697 | struct drm_device *drm_dev = data; |
1698 | struct hdmi_context *hdata = dev_get_drvdata(dev); | 1698 | struct hdmi_context *hdata = dev_get_drvdata(dev); |
1699 | struct drm_encoder *encoder = &hdata->encoder; | 1699 | struct drm_encoder *encoder = &hdata->encoder; |
1700 | struct exynos_drm_crtc *exynos_crtc; | 1700 | struct exynos_drm_crtc *crtc; |
1701 | struct drm_crtc *crtc; | 1701 | int ret; |
1702 | int ret, pipe; | ||
1703 | 1702 | ||
1704 | hdata->drm_dev = drm_dev; | 1703 | hdata->drm_dev = drm_dev; |
1705 | 1704 | ||
1706 | pipe = exynos_drm_crtc_get_pipe_from_type(drm_dev, | ||
1707 | EXYNOS_DISPLAY_TYPE_HDMI); | ||
1708 | if (pipe < 0) | ||
1709 | return pipe; | ||
1710 | |||
1711 | hdata->phy_clk.enable = hdmiphy_clk_enable; | 1705 | hdata->phy_clk.enable = hdmiphy_clk_enable; |
1712 | 1706 | ||
1713 | crtc = drm_crtc_from_index(drm_dev, pipe); | ||
1714 | exynos_crtc = to_exynos_crtc(crtc); | ||
1715 | exynos_crtc->pipe_clk = &hdata->phy_clk; | ||
1716 | |||
1717 | encoder->possible_crtcs = 1 << pipe; | ||
1718 | |||
1719 | DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs); | ||
1720 | |||
1721 | drm_encoder_init(drm_dev, encoder, &exynos_hdmi_encoder_funcs, | 1707 | drm_encoder_init(drm_dev, encoder, &exynos_hdmi_encoder_funcs, |
1722 | DRM_MODE_ENCODER_TMDS, NULL); | 1708 | DRM_MODE_ENCODER_TMDS, NULL); |
1723 | 1709 | ||
1724 | drm_encoder_helper_add(encoder, &exynos_hdmi_encoder_helper_funcs); | 1710 | drm_encoder_helper_add(encoder, &exynos_hdmi_encoder_helper_funcs); |
1725 | 1711 | ||
1712 | ret = exynos_drm_set_possible_crtcs(encoder, EXYNOS_DISPLAY_TYPE_HDMI); | ||
1713 | if (ret < 0) | ||
1714 | return ret; | ||
1715 | |||
1716 | crtc = exynos_drm_crtc_get_by_type(drm_dev, EXYNOS_DISPLAY_TYPE_HDMI); | ||
1717 | crtc->pipe_clk = &hdata->phy_clk; | ||
1718 | |||
1726 | ret = hdmi_create_connector(encoder); | 1719 | ret = hdmi_create_connector(encoder); |
1727 | if (ret) { | 1720 | if (ret) { |
1728 | DRM_ERROR("failed to create connector ret = %d\n", ret); | 1721 | DRM_ERROR("failed to create connector ret = %d\n", ret); |
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index a998a8dd783c..002755415e00 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c | |||
@@ -148,7 +148,8 @@ static const struct exynos_drm_plane_config plane_configs[MIXER_WIN_NR] = { | |||
148 | .pixel_formats = vp_formats, | 148 | .pixel_formats = vp_formats, |
149 | .num_pixel_formats = ARRAY_SIZE(vp_formats), | 149 | .num_pixel_formats = ARRAY_SIZE(vp_formats), |
150 | .capabilities = EXYNOS_DRM_PLANE_CAP_SCALE | | 150 | .capabilities = EXYNOS_DRM_PLANE_CAP_SCALE | |
151 | EXYNOS_DRM_PLANE_CAP_ZPOS, | 151 | EXYNOS_DRM_PLANE_CAP_ZPOS | |
152 | EXYNOS_DRM_PLANE_CAP_TILE, | ||
152 | }, | 153 | }, |
153 | }; | 154 | }; |
154 | 155 | ||
@@ -483,29 +484,18 @@ static void vp_video_buffer(struct mixer_context *ctx, | |||
483 | unsigned int priority = state->base.normalized_zpos + 1; | 484 | unsigned int priority = state->base.normalized_zpos + 1; |
484 | unsigned long flags; | 485 | unsigned long flags; |
485 | dma_addr_t luma_addr[2], chroma_addr[2]; | 486 | dma_addr_t luma_addr[2], chroma_addr[2]; |
486 | bool tiled_mode = false; | 487 | bool is_tiled, is_nv21; |
487 | bool crcb_mode = false; | ||
488 | u32 val; | 488 | u32 val; |
489 | 489 | ||
490 | switch (fb->format->format) { | 490 | is_nv21 = (fb->format->format == DRM_FORMAT_NV21); |
491 | case DRM_FORMAT_NV12: | 491 | is_tiled = (fb->modifier == DRM_FORMAT_MOD_SAMSUNG_64_32_TILE); |
492 | crcb_mode = false; | ||
493 | break; | ||
494 | case DRM_FORMAT_NV21: | ||
495 | crcb_mode = true; | ||
496 | break; | ||
497 | default: | ||
498 | DRM_ERROR("pixel format for vp is wrong [%d].\n", | ||
499 | fb->format->format); | ||
500 | return; | ||
501 | } | ||
502 | 492 | ||
503 | luma_addr[0] = exynos_drm_fb_dma_addr(fb, 0); | 493 | luma_addr[0] = exynos_drm_fb_dma_addr(fb, 0); |
504 | chroma_addr[0] = exynos_drm_fb_dma_addr(fb, 1); | 494 | chroma_addr[0] = exynos_drm_fb_dma_addr(fb, 1); |
505 | 495 | ||
506 | if (mode->flags & DRM_MODE_FLAG_INTERLACE) { | 496 | if (mode->flags & DRM_MODE_FLAG_INTERLACE) { |
507 | __set_bit(MXR_BIT_INTERLACE, &ctx->flags); | 497 | __set_bit(MXR_BIT_INTERLACE, &ctx->flags); |
508 | if (tiled_mode) { | 498 | if (is_tiled) { |
509 | luma_addr[1] = luma_addr[0] + 0x40; | 499 | luma_addr[1] = luma_addr[0] + 0x40; |
510 | chroma_addr[1] = chroma_addr[0] + 0x40; | 500 | chroma_addr[1] = chroma_addr[0] + 0x40; |
511 | } else { | 501 | } else { |
@@ -525,14 +515,14 @@ static void vp_video_buffer(struct mixer_context *ctx, | |||
525 | vp_reg_writemask(res, VP_MODE, val, VP_MODE_LINE_SKIP); | 515 | vp_reg_writemask(res, VP_MODE, val, VP_MODE_LINE_SKIP); |
526 | 516 | ||
527 | /* setup format */ | 517 | /* setup format */ |
528 | val = (crcb_mode ? VP_MODE_NV21 : VP_MODE_NV12); | 518 | val = (is_nv21 ? VP_MODE_NV21 : VP_MODE_NV12); |
529 | val |= (tiled_mode ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR); | 519 | val |= (is_tiled ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR); |
530 | vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK); | 520 | vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK); |
531 | 521 | ||
532 | /* setting size of input image */ | 522 | /* setting size of input image */ |
533 | vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(fb->pitches[0]) | | 523 | vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(fb->pitches[0]) | |
534 | VP_IMG_VSIZE(fb->height)); | 524 | VP_IMG_VSIZE(fb->height)); |
535 | /* chroma height has to reduced by 2 to avoid chroma distorions */ | 525 | /* chroma plane for NV12/NV21 is half the height of the luma plane */ |
536 | vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(fb->pitches[0]) | | 526 | vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(fb->pitches[0]) | |
537 | VP_IMG_VSIZE(fb->height / 2)); | 527 | VP_IMG_VSIZE(fb->height / 2)); |
538 | 528 | ||
@@ -594,7 +584,7 @@ static void mixer_graph_buffer(struct mixer_context *ctx, | |||
594 | unsigned long flags; | 584 | unsigned long flags; |
595 | unsigned int win = plane->index; | 585 | unsigned int win = plane->index; |
596 | unsigned int x_ratio = 0, y_ratio = 0; | 586 | unsigned int x_ratio = 0, y_ratio = 0; |
597 | unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset; | 587 | unsigned int dst_x_offset, dst_y_offset; |
598 | dma_addr_t dma_addr; | 588 | dma_addr_t dma_addr; |
599 | unsigned int fmt; | 589 | unsigned int fmt; |
600 | u32 val; | 590 | u32 val; |
@@ -616,12 +606,9 @@ static void mixer_graph_buffer(struct mixer_context *ctx, | |||
616 | 606 | ||
617 | case DRM_FORMAT_XRGB8888: | 607 | case DRM_FORMAT_XRGB8888: |
618 | case DRM_FORMAT_ARGB8888: | 608 | case DRM_FORMAT_ARGB8888: |
609 | default: | ||
619 | fmt = MXR_FORMAT_ARGB8888; | 610 | fmt = MXR_FORMAT_ARGB8888; |
620 | break; | 611 | break; |
621 | |||
622 | default: | ||
623 | DRM_DEBUG_KMS("pixelformat unsupported by mixer\n"); | ||
624 | return; | ||
625 | } | 612 | } |
626 | 613 | ||
627 | /* ratio is already checked by common plane code */ | 614 | /* ratio is already checked by common plane code */ |
@@ -631,12 +618,10 @@ static void mixer_graph_buffer(struct mixer_context *ctx, | |||
631 | dst_x_offset = state->crtc.x; | 618 | dst_x_offset = state->crtc.x; |
632 | dst_y_offset = state->crtc.y; | 619 | dst_y_offset = state->crtc.y; |
633 | 620 | ||
634 | /* converting dma address base and source offset */ | 621 | /* translate dma address base s.t. the source image offset is zero */ |
635 | dma_addr = exynos_drm_fb_dma_addr(fb, 0) | 622 | dma_addr = exynos_drm_fb_dma_addr(fb, 0) |
636 | + (state->src.x * fb->format->cpp[0]) | 623 | + (state->src.x * fb->format->cpp[0]) |
637 | + (state->src.y * fb->pitches[0]); | 624 | + (state->src.y * fb->pitches[0]); |
638 | src_x_offset = 0; | ||
639 | src_y_offset = 0; | ||
640 | 625 | ||
641 | if (mode->flags & DRM_MODE_FLAG_INTERLACE) | 626 | if (mode->flags & DRM_MODE_FLAG_INTERLACE) |
642 | __set_bit(MXR_BIT_INTERLACE, &ctx->flags); | 627 | __set_bit(MXR_BIT_INTERLACE, &ctx->flags); |
@@ -667,11 +652,6 @@ static void mixer_graph_buffer(struct mixer_context *ctx, | |||
667 | val |= MXR_GRP_WH_V_SCALE(y_ratio); | 652 | val |= MXR_GRP_WH_V_SCALE(y_ratio); |
668 | mixer_reg_write(res, MXR_GRAPHIC_WH(win), val); | 653 | mixer_reg_write(res, MXR_GRAPHIC_WH(win), val); |
669 | 654 | ||
670 | /* setup offsets in source image */ | ||
671 | val = MXR_GRP_SXY_SX(src_x_offset); | ||
672 | val |= MXR_GRP_SXY_SY(src_y_offset); | ||
673 | mixer_reg_write(res, MXR_GRAPHIC_SXY(win), val); | ||
674 | |||
675 | /* setup offsets in display image */ | 655 | /* setup offsets in display image */ |
676 | val = MXR_GRP_DXY_DX(dst_x_offset); | 656 | val = MXR_GRP_DXY_DX(dst_x_offset); |
677 | val |= MXR_GRP_DXY_DY(dst_y_offset); | 657 | val |= MXR_GRP_DXY_DY(dst_y_offset); |
@@ -748,6 +728,10 @@ static void mixer_win_reset(struct mixer_context *ctx) | |||
748 | if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) | 728 | if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) |
749 | mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE); | 729 | mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE); |
750 | 730 | ||
731 | /* set all source image offsets to zero */ | ||
732 | mixer_reg_write(res, MXR_GRAPHIC_SXY(0), 0); | ||
733 | mixer_reg_write(res, MXR_GRAPHIC_SXY(1), 0); | ||
734 | |||
751 | spin_unlock_irqrestore(&res->reg_slock, flags); | 735 | spin_unlock_irqrestore(&res->reg_slock, flags); |
752 | } | 736 | } |
753 | 737 | ||