.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* drivers/gpu/drm/exynos5433_drm_decon.c |
---|
2 | 3 | * |
---|
3 | 4 | * Copyright (C) 2015 Samsung Electronics Co.Ltd |
---|
4 | 5 | * Authors: |
---|
5 | 6 | * Joonyoung Shim <jy0922.shim@samsung.com> |
---|
6 | 7 | * Hyungwon Hwang <human.hwang@samsung.com> |
---|
7 | | - * |
---|
8 | | - * This program is free software; you can redistribute it and/or modify |
---|
9 | | - * it under the terms of the GNU General Public License version 2 as |
---|
10 | | - * published by the Free Software Foundationr |
---|
11 | 8 | */ |
---|
12 | 9 | |
---|
13 | | -#include <linux/platform_device.h> |
---|
14 | 10 | #include <linux/clk.h> |
---|
15 | 11 | #include <linux/component.h> |
---|
16 | 12 | #include <linux/iopoll.h> |
---|
.. | .. |
---|
18 | 14 | #include <linux/mfd/syscon.h> |
---|
19 | 15 | #include <linux/of_device.h> |
---|
20 | 16 | #include <linux/of_gpio.h> |
---|
| 17 | +#include <linux/platform_device.h> |
---|
21 | 18 | #include <linux/pm_runtime.h> |
---|
22 | 19 | #include <linux/regmap.h> |
---|
23 | 20 | |
---|
24 | | -#include "exynos_drm_drv.h" |
---|
| 21 | +#include <drm/drm_fourcc.h> |
---|
| 22 | +#include <drm/drm_vblank.h> |
---|
| 23 | + |
---|
25 | 24 | #include "exynos_drm_crtc.h" |
---|
| 25 | +#include "exynos_drm_drv.h" |
---|
26 | 26 | #include "exynos_drm_fb.h" |
---|
27 | 27 | #include "exynos_drm_plane.h" |
---|
28 | | -#include "exynos_drm_iommu.h" |
---|
29 | 28 | #include "regs-decon5433.h" |
---|
30 | 29 | |
---|
31 | 30 | #define DSD_CFG_MUX 0x1004 |
---|
.. | .. |
---|
56 | 55 | struct decon_context { |
---|
57 | 56 | struct device *dev; |
---|
58 | 57 | struct drm_device *drm_dev; |
---|
| 58 | + void *dma_priv; |
---|
59 | 59 | struct exynos_drm_crtc *crtc; |
---|
60 | 60 | struct exynos_drm_plane planes[WINDOWS_NR]; |
---|
61 | 61 | struct exynos_drm_plane_config configs[WINDOWS_NR]; |
---|
.. | .. |
---|
82 | 82 | static const enum drm_plane_type decon_win_types[WINDOWS_NR] = { |
---|
83 | 83 | [PRIMARY_WIN] = DRM_PLANE_TYPE_PRIMARY, |
---|
84 | 84 | [CURSON_WIN] = DRM_PLANE_TYPE_CURSOR, |
---|
| 85 | +}; |
---|
| 86 | + |
---|
| 87 | +static const unsigned int capabilities[WINDOWS_NR] = { |
---|
| 88 | + 0, |
---|
| 89 | + EXYNOS_DRM_PLANE_CAP_WIN_BLEND | EXYNOS_DRM_PLANE_CAP_PIX_BLEND, |
---|
| 90 | + EXYNOS_DRM_PLANE_CAP_WIN_BLEND | EXYNOS_DRM_PLANE_CAP_PIX_BLEND, |
---|
| 91 | + EXYNOS_DRM_PLANE_CAP_WIN_BLEND | EXYNOS_DRM_PLANE_CAP_PIX_BLEND, |
---|
| 92 | + EXYNOS_DRM_PLANE_CAP_WIN_BLEND | EXYNOS_DRM_PLANE_CAP_PIX_BLEND, |
---|
85 | 93 | }; |
---|
86 | 94 | |
---|
87 | 95 | static inline void decon_set_bits(struct decon_context *ctx, u32 reg, u32 mask, |
---|
.. | .. |
---|
181 | 189 | |
---|
182 | 190 | if (regmap_update_bits(ctx->sysreg, DSD_CFG_MUX, |
---|
183 | 191 | DSD_CFG_MUX_TE_UNMASK_GLOBAL, ~0)) |
---|
184 | | - DRM_ERROR("Cannot update sysreg.\n"); |
---|
| 192 | + DRM_DEV_ERROR(ctx->dev, "Cannot update sysreg.\n"); |
---|
185 | 193 | } |
---|
186 | 194 | |
---|
187 | 195 | static void decon_commit(struct exynos_drm_crtc *crtc) |
---|
.. | .. |
---|
252 | 260 | decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0); |
---|
253 | 261 | } |
---|
254 | 262 | |
---|
| 263 | +static void decon_win_set_bldeq(struct decon_context *ctx, unsigned int win, |
---|
| 264 | + unsigned int alpha, unsigned int pixel_alpha) |
---|
| 265 | +{ |
---|
| 266 | + u32 mask = BLENDERQ_A_FUNC_F(0xf) | BLENDERQ_B_FUNC_F(0xf); |
---|
| 267 | + u32 val = 0; |
---|
| 268 | + |
---|
| 269 | + switch (pixel_alpha) { |
---|
| 270 | + case DRM_MODE_BLEND_PIXEL_NONE: |
---|
| 271 | + case DRM_MODE_BLEND_COVERAGE: |
---|
| 272 | + val |= BLENDERQ_A_FUNC_F(BLENDERQ_ALPHA_A); |
---|
| 273 | + val |= BLENDERQ_B_FUNC_F(BLENDERQ_ONE_MINUS_ALPHA_A); |
---|
| 274 | + break; |
---|
| 275 | + case DRM_MODE_BLEND_PREMULTI: |
---|
| 276 | + default: |
---|
| 277 | + if (alpha != DRM_BLEND_ALPHA_OPAQUE) { |
---|
| 278 | + val |= BLENDERQ_A_FUNC_F(BLENDERQ_ALPHA0); |
---|
| 279 | + val |= BLENDERQ_B_FUNC_F(BLENDERQ_ONE_MINUS_ALPHA_A); |
---|
| 280 | + } else { |
---|
| 281 | + val |= BLENDERQ_A_FUNC_F(BLENDERQ_ONE); |
---|
| 282 | + val |= BLENDERQ_B_FUNC_F(BLENDERQ_ONE_MINUS_ALPHA_A); |
---|
| 283 | + } |
---|
| 284 | + break; |
---|
| 285 | + } |
---|
| 286 | + decon_set_bits(ctx, DECON_BLENDERQx(win), mask, val); |
---|
| 287 | +} |
---|
| 288 | + |
---|
| 289 | +static void decon_win_set_bldmod(struct decon_context *ctx, unsigned int win, |
---|
| 290 | + unsigned int alpha, unsigned int pixel_alpha) |
---|
| 291 | +{ |
---|
| 292 | + u32 win_alpha = alpha >> 8; |
---|
| 293 | + u32 val = 0; |
---|
| 294 | + |
---|
| 295 | + switch (pixel_alpha) { |
---|
| 296 | + case DRM_MODE_BLEND_PIXEL_NONE: |
---|
| 297 | + break; |
---|
| 298 | + case DRM_MODE_BLEND_COVERAGE: |
---|
| 299 | + case DRM_MODE_BLEND_PREMULTI: |
---|
| 300 | + default: |
---|
| 301 | + val |= WINCONx_ALPHA_SEL_F; |
---|
| 302 | + val |= WINCONx_BLD_PIX_F; |
---|
| 303 | + val |= WINCONx_ALPHA_MUL_F; |
---|
| 304 | + break; |
---|
| 305 | + } |
---|
| 306 | + decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_BLEND_MODE_MASK, val); |
---|
| 307 | + |
---|
| 308 | + if (alpha != DRM_BLEND_ALPHA_OPAQUE) { |
---|
| 309 | + val = VIDOSD_Wx_ALPHA_R_F(win_alpha) | |
---|
| 310 | + VIDOSD_Wx_ALPHA_G_F(win_alpha) | |
---|
| 311 | + VIDOSD_Wx_ALPHA_B_F(win_alpha); |
---|
| 312 | + decon_set_bits(ctx, DECON_VIDOSDxC(win), |
---|
| 313 | + VIDOSDxC_ALPHA0_RGB_MASK, val); |
---|
| 314 | + decon_set_bits(ctx, DECON_BLENDCON, BLEND_NEW, BLEND_NEW); |
---|
| 315 | + } |
---|
| 316 | +} |
---|
| 317 | + |
---|
255 | 318 | static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win, |
---|
256 | 319 | struct drm_framebuffer *fb) |
---|
257 | 320 | { |
---|
| 321 | + struct exynos_drm_plane plane = ctx->planes[win]; |
---|
| 322 | + struct exynos_drm_plane_state *state = |
---|
| 323 | + to_exynos_plane_state(plane.base.state); |
---|
| 324 | + unsigned int alpha = state->base.alpha; |
---|
| 325 | + unsigned int pixel_alpha; |
---|
258 | 326 | unsigned long val; |
---|
| 327 | + |
---|
| 328 | + if (fb->format->has_alpha) |
---|
| 329 | + pixel_alpha = state->base.pixel_blend_mode; |
---|
| 330 | + else |
---|
| 331 | + pixel_alpha = DRM_MODE_BLEND_PIXEL_NONE; |
---|
259 | 332 | |
---|
260 | 333 | val = readl(ctx->addr + DECON_WINCONx(win)); |
---|
261 | 334 | val &= WINCONx_ENWIN_F; |
---|
.. | .. |
---|
279 | 352 | case DRM_FORMAT_ARGB8888: |
---|
280 | 353 | default: |
---|
281 | 354 | val |= WINCONx_BPPMODE_32BPP_A8888; |
---|
282 | | - val |= WINCONx_WSWP_F | WINCONx_BLD_PIX_F | WINCONx_ALPHA_SEL_F; |
---|
| 355 | + val |= WINCONx_WSWP_F; |
---|
283 | 356 | val |= WINCONx_BURSTLEN_16WORD; |
---|
284 | 357 | break; |
---|
285 | 358 | } |
---|
286 | 359 | |
---|
287 | | - DRM_DEBUG_KMS("cpp = %u\n", fb->format->cpp[0]); |
---|
| 360 | + DRM_DEV_DEBUG_KMS(ctx->dev, "cpp = %u\n", fb->format->cpp[0]); |
---|
288 | 361 | |
---|
289 | 362 | /* |
---|
290 | 363 | * In case of exynos, setting dma-burst to 16Word causes permanent |
---|
.. | .. |
---|
298 | 371 | val &= ~WINCONx_BURSTLEN_MASK; |
---|
299 | 372 | val |= WINCONx_BURSTLEN_8WORD; |
---|
300 | 373 | } |
---|
| 374 | + decon_set_bits(ctx, DECON_WINCONx(win), ~WINCONx_BLEND_MODE_MASK, val); |
---|
301 | 375 | |
---|
302 | | - writel(val, ctx->addr + DECON_WINCONx(win)); |
---|
| 376 | + if (win > 0) { |
---|
| 377 | + decon_win_set_bldmod(ctx, win, alpha, pixel_alpha); |
---|
| 378 | + decon_win_set_bldeq(ctx, win, alpha, pixel_alpha); |
---|
| 379 | + } |
---|
303 | 380 | } |
---|
304 | 381 | |
---|
305 | 382 | static void decon_shadow_protect(struct decon_context *ctx, bool protect) |
---|
.. | .. |
---|
434 | 511 | ctx->addr + DECON_CRCCTRL); |
---|
435 | 512 | } |
---|
436 | 513 | |
---|
437 | | -static void decon_enable(struct exynos_drm_crtc *crtc) |
---|
| 514 | +static void decon_atomic_enable(struct exynos_drm_crtc *crtc) |
---|
438 | 515 | { |
---|
439 | 516 | struct decon_context *ctx = crtc->ctx; |
---|
440 | 517 | |
---|
.. | .. |
---|
447 | 524 | decon_commit(ctx->crtc); |
---|
448 | 525 | } |
---|
449 | 526 | |
---|
450 | | -static void decon_disable(struct exynos_drm_crtc *crtc) |
---|
| 527 | +static void decon_atomic_disable(struct exynos_drm_crtc *crtc) |
---|
451 | 528 | { |
---|
452 | 529 | struct decon_context *ctx = crtc->ctx; |
---|
453 | 530 | int i; |
---|
.. | .. |
---|
484 | 561 | { |
---|
485 | 562 | struct decon_context *ctx = crtc->ctx; |
---|
486 | 563 | int win, i, ret; |
---|
487 | | - |
---|
488 | | - DRM_DEBUG_KMS("%s\n", __FILE__); |
---|
489 | 564 | |
---|
490 | 565 | for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) { |
---|
491 | 566 | ret = clk_prepare_enable(ctx->clks[i]); |
---|
.. | .. |
---|
525 | 600 | } |
---|
526 | 601 | |
---|
527 | 602 | static const struct exynos_drm_crtc_ops decon_crtc_ops = { |
---|
528 | | - .enable = decon_enable, |
---|
529 | | - .disable = decon_disable, |
---|
| 603 | + .atomic_enable = decon_atomic_enable, |
---|
| 604 | + .atomic_disable = decon_atomic_disable, |
---|
530 | 605 | .enable_vblank = decon_enable_vblank, |
---|
531 | 606 | .disable_vblank = decon_disable_vblank, |
---|
532 | 607 | .atomic_begin = decon_atomic_begin, |
---|
.. | .. |
---|
552 | 627 | ctx->configs[win].num_pixel_formats = ARRAY_SIZE(decon_formats); |
---|
553 | 628 | ctx->configs[win].zpos = win - ctx->first_win; |
---|
554 | 629 | ctx->configs[win].type = decon_win_types[win]; |
---|
| 630 | + ctx->configs[win].capabilities = capabilities[win]; |
---|
555 | 631 | |
---|
556 | 632 | ret = exynos_plane_init(drm_dev, &ctx->planes[win], win, |
---|
557 | 633 | &ctx->configs[win]); |
---|
.. | .. |
---|
569 | 645 | |
---|
570 | 646 | decon_clear_channels(ctx->crtc); |
---|
571 | 647 | |
---|
572 | | - return drm_iommu_attach_device(drm_dev, dev); |
---|
| 648 | + return exynos_drm_register_dma(drm_dev, dev, &ctx->dma_priv); |
---|
573 | 649 | } |
---|
574 | 650 | |
---|
575 | 651 | static void decon_unbind(struct device *dev, struct device *master, void *data) |
---|
576 | 652 | { |
---|
577 | 653 | struct decon_context *ctx = dev_get_drvdata(dev); |
---|
578 | 654 | |
---|
579 | | - decon_disable(ctx->crtc); |
---|
| 655 | + decon_atomic_disable(ctx->crtc); |
---|
580 | 656 | |
---|
581 | 657 | /* detach this sub driver from iommu mapping if supported. */ |
---|
582 | | - drm_iommu_detach_device(ctx->drm_dev, ctx->dev); |
---|
| 658 | + exynos_drm_unregister_dma(ctx->drm_dev, ctx->dev, &ctx->dma_priv); |
---|
583 | 659 | } |
---|
584 | 660 | |
---|
585 | 661 | static const struct component_ops decon_component_ops = { |
---|
.. | .. |
---|
699 | 775 | return irq; |
---|
700 | 776 | } |
---|
701 | 777 | } |
---|
702 | | - irq_set_status_flags(irq, IRQ_NOAUTOEN); |
---|
703 | | - ret = devm_request_irq(ctx->dev, irq, handler, flags, "drm_decon", ctx); |
---|
| 778 | + ret = devm_request_irq(ctx->dev, irq, handler, |
---|
| 779 | + flags | IRQF_NO_AUTOEN, "drm_decon", ctx); |
---|
704 | 780 | if (ret < 0) { |
---|
705 | 781 | dev_err(ctx->dev, "IRQ %s request failed\n", name); |
---|
706 | 782 | return ret; |
---|