| .. | .. |
|---|
| 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; |
|---|