diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-10 04:48:37 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-10 04:48:37 +0300 |
commit | af3c8d98508d37541d4bf57f13a984a7f73a328c (patch) | |
tree | e8dd974d6ebccd38b1e373be8a5e4a2f8bf3c6ce /drivers/gpu/drm/exynos | |
parent | d3e3b7eac886fb1383db2f22b81550fa6d87f62f (diff) | |
parent | 00fc2c26bc46a64545cdf95a1511461ea9acecb4 (diff) | |
download | linux-af3c8d98508d37541d4bf57f13a984a7f73a328c.tar.xz |
Merge tag 'drm-for-v4.13' of git://people.freedesktop.org/~airlied/linux
Pull drm updates from Dave Airlie:
"This is the main pull request for the drm, I think I've got one later
driver pull for mediatek SoC driver, I'm undecided on if it needs to
go to you yet.
Otherwise summary below:
Core drm:
- Atomic add driver private objects
- Deprecate preclose hook in modern drivers
- MST bandwidth tracking
- Use kvmalloc in more places
- Add mode_valid hook for crtc/encoder/bridge
- Reduce sync_file construction time
- Documentation updates
- New DRM synchronisation object support
New drivers:
- pl111 - pl111 CLCD display controller
Panel:
- Innolux P079ZCA panel driver
- Add NL12880B20-05, NL192108AC18-02D, P320HVN03 panels
- panel-samsung-s6e3ha2: Add s6e3hf2 panel support
i915:
- SKL+ watermark fixes
- G4x/G33 reset improvements
- DP AUX backlight improvements
- Buffer based GuC/host communication
- New getparam for (sub)slice infomation
- Cannonlake and Coffeelake initial patches
- Execbuf optimisations
radeon/amdgpu:
- Lots of Vega10 bug fixes
- Preliminary raven support
- KIQ support for compute rings
- MEC queue management rework
- DCE6 Audio support
- SR-IOV improvements
- Better radeon/amdgpu selection support
nouveau:
- HDMI stereoscopic support
- Display code rework for >= GM20x GPUs
msm:
- GEM rework for fine-grained locking
- Per-process pagetable work
- HDMI fixes for Snapdragon 820.
vc4:
- Remove 256MB CMA limit from vc4
- Add out-fence support
- Add support for cygnus
- Get/set tiling ioctls support
- Add T-format tiling support for scanout
zte:
- add VGA support.
etnaviv:
- Thermal throttle support for newer GPUs
- Restore userspace buffer cache performance
- dma-buf sync fix
stm:
- add stm32f429 display support
exynos:
- Rework vblank handling
- Fixup sw-trigger code
sun4i:
- V3s display engine support
- HDMI support for older SoCs
- Preliminary work on dual-pipeline SoCs.
rcar-du:
- VSP work
imx-drm:
- Remove counter load enable from PRE
- Double read/write reduction flag support
tegra:
- Documentation for the host1x and drm driver.
- Lots of staging ioctl fixes due to grate project work.
omapdrm:
- dma-buf fence support
- TILER rotation fixes"
* tag 'drm-for-v4.13' of git://people.freedesktop.org/~airlied/linux: (1270 commits)
drm: Remove unused drm_file parameter to drm_syncobj_replace_fence()
drm/amd/powerplay: fix bug fail to remove sysfs when rmmod amdgpu.
amdgpu: Set cik/si_support to 1 by default if radeon isn't built
drm/amdgpu/gfx9: fix driver reload with KIQ
drm/amdgpu/gfx8: fix driver reload with KIQ
drm/amdgpu: Don't call amd_powerplay_destroy() if we don't have powerplay
drm/ttm: Fix use-after-free in ttm_bo_clean_mm
drm/amd/amdgpu: move get memory type function from early init to sw init
drm/amdgpu/cgs: always set reference clock in mode_info
drm/amdgpu: fix vblank_time when displays are off
drm/amd/powerplay: power value format change for Vega10
drm/amdgpu/gfx9: support the amdgpu.disable_cu option
drm/amd/powerplay: change PPSMC_MSG_GetCurrPkgPwr for Vega10
drm/amdgpu: Make amdgpu_cs_parser_init static (v2)
drm/amdgpu/cs: fix a typo in a comment
drm/amdgpu: Fix the exported always on CU bitmap
drm/amdgpu/gfx9: gfx_v9_0_enable_gfx_static_mg_power_gating() can be static
drm/amdgpu/psp: upper_32_bits/lower_32_bits for address setup
drm/amd/powerplay/cz: print message if smc message fails
drm/amdgpu: fix typo in amdgpu_debugfs_test_ib_init
...
Diffstat (limited to 'drivers/gpu/drm/exynos')
-rw-r--r-- | drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 218 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos7_drm_decon.c | 19 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_crtc.c | 50 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_crtc.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_drv.c | 18 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_drv.h | 14 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_dsi.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_fimd.c | 24 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_gem.c | 11 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_plane.c | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_plane.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_vidi.c | 22 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_hdmi.c | 13 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_mixer.c | 76 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/regs-mixer.h | 7 |
15 files changed, 192 insertions, 289 deletions
diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index c0e8d3302292..5792ca88ab7a 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -47,14 +47,6 @@ static const char * const decon_clks_name[] = { "sclk_decon_eclk", }; -enum decon_flag_bits { - BIT_CLKS_ENABLED, - BIT_IRQS_ENABLED, - BIT_WIN_UPDATED, - BIT_SUSPENDED, - BIT_REQUEST_UPDATE -}; - struct decon_context { struct device *dev; struct drm_device *drm_dev; @@ -64,8 +56,8 @@ struct decon_context { void __iomem *addr; struct regmap *sysreg; struct clk *clks[ARRAY_SIZE(decon_clks_name)]; - int pipe; - unsigned long flags; + unsigned int irq; + unsigned int te_irq; unsigned long out_type; int first_win; spinlock_t vblank_lock; @@ -97,18 +89,17 @@ static int decon_enable_vblank(struct exynos_drm_crtc *crtc) struct decon_context *ctx = crtc->ctx; u32 val; - if (test_bit(BIT_SUSPENDED, &ctx->flags)) - return -EPERM; + val = VIDINTCON0_INTEN; + if (ctx->out_type & IFTYPE_I80) + val |= VIDINTCON0_FRAMEDONE; + else + val |= VIDINTCON0_INTFRMEN | VIDINTCON0_FRAMESEL_FP; - if (!test_and_set_bit(BIT_IRQS_ENABLED, &ctx->flags)) { - val = VIDINTCON0_INTEN; - if (ctx->out_type & IFTYPE_I80) - val |= VIDINTCON0_FRAMEDONE; - else - val |= VIDINTCON0_INTFRMEN | VIDINTCON0_FRAMESEL_FP; + writel(val, ctx->addr + DECON_VIDINTCON0); - writel(val, ctx->addr + DECON_VIDINTCON0); - } + enable_irq(ctx->irq); + if (!(ctx->out_type & I80_HW_TRG)) + enable_irq(ctx->te_irq); return 0; } @@ -117,11 +108,11 @@ static void decon_disable_vblank(struct exynos_drm_crtc *crtc) { struct decon_context *ctx = crtc->ctx; - if (test_bit(BIT_SUSPENDED, &ctx->flags)) - return; + if (!(ctx->out_type & I80_HW_TRG)) + disable_irq_nosync(ctx->te_irq); + disable_irq_nosync(ctx->irq); - if (test_and_clear_bit(BIT_IRQS_ENABLED, &ctx->flags)) - writel(0, ctx->addr + DECON_VIDINTCON0); + writel(0, ctx->addr + DECON_VIDINTCON0); } /* return number of starts/ends of frame transmissions since reset */ @@ -166,6 +157,13 @@ static u32 decon_get_frame_count(struct decon_context *ctx, bool end) return frm; } +static u32 decon_get_vblank_counter(struct exynos_drm_crtc *crtc) +{ + struct decon_context *ctx = crtc->ctx; + + return decon_get_frame_count(ctx, false); +} + static void decon_setup_trigger(struct decon_context *ctx) { if (!(ctx->out_type & (IFTYPE_I80 | I80_HW_TRG))) @@ -193,9 +191,6 @@ static void decon_commit(struct exynos_drm_crtc *crtc) bool interlaced = false; u32 val; - if (test_bit(BIT_SUSPENDED, &ctx->flags)) - return; - if (ctx->out_type & IFTYPE_HDMI) { m->crtc_hsync_start = m->crtc_hdisplay + 10; m->crtc_hsync_end = m->crtc_htotal - 92; @@ -309,23 +304,17 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win, writel(val, ctx->addr + DECON_WINCONx(win)); } -static void decon_shadow_protect_win(struct decon_context *ctx, int win, - bool protect) +static void decon_shadow_protect(struct decon_context *ctx, bool protect) { - decon_set_bits(ctx, DECON_SHADOWCON, SHADOWCON_Wx_PROTECT(win), + decon_set_bits(ctx, DECON_SHADOWCON, SHADOWCON_PROTECT_MASK, protect ? ~0 : 0); } static void decon_atomic_begin(struct exynos_drm_crtc *crtc) { struct decon_context *ctx = crtc->ctx; - int i; - - if (test_bit(BIT_SUSPENDED, &ctx->flags)) - return; - for (i = ctx->first_win; i < WINDOWS_NR; i++) - decon_shadow_protect_win(ctx, i, true); + decon_shadow_protect(ctx, true); } #define BIT_VAL(x, e, s) (((x) & ((1 << ((e) - (s) + 1)) - 1)) << (s)) @@ -345,9 +334,6 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, dma_addr_t dma_addr = exynos_drm_fb_dma_addr(fb, 0); u32 val; - if (test_bit(BIT_SUSPENDED, &ctx->flags)) - return; - if (crtc->base.mode.flags & DRM_MODE_FLAG_INTERLACE) { val = COORDINATE_X(state->crtc.x) | COORDINATE_Y(state->crtc.y / 2); @@ -390,7 +376,6 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, /* window enable */ decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, ~0); - set_bit(BIT_REQUEST_UPDATE, &ctx->flags); } static void decon_disable_plane(struct exynos_drm_crtc *crtc, @@ -399,32 +384,19 @@ static void decon_disable_plane(struct exynos_drm_crtc *crtc, struct decon_context *ctx = crtc->ctx; unsigned int win = plane->index; - if (test_bit(BIT_SUSPENDED, &ctx->flags)) - return; - decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, 0); - set_bit(BIT_REQUEST_UPDATE, &ctx->flags); } static void decon_atomic_flush(struct exynos_drm_crtc *crtc) { struct decon_context *ctx = crtc->ctx; unsigned long flags; - int i; - - if (test_bit(BIT_SUSPENDED, &ctx->flags)) - return; spin_lock_irqsave(&ctx->vblank_lock, flags); - for (i = ctx->first_win; i < WINDOWS_NR; i++) - decon_shadow_protect_win(ctx, i, false); - - if (test_and_clear_bit(BIT_REQUEST_UPDATE, &ctx->flags)) - decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0); + decon_shadow_protect(ctx, false); - if (ctx->out_type & IFTYPE_I80) - set_bit(BIT_WIN_UPDATED, &ctx->flags); + decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0); ctx->frame_id = decon_get_frame_count(ctx, true); @@ -473,21 +445,12 @@ static void decon_enable(struct exynos_drm_crtc *crtc) { struct decon_context *ctx = crtc->ctx; - if (!test_and_clear_bit(BIT_SUSPENDED, &ctx->flags)) - return; - pm_runtime_get_sync(ctx->dev); exynos_drm_pipe_clk_enable(crtc, true); - set_bit(BIT_CLKS_ENABLED, &ctx->flags); - decon_swreset(ctx); - /* if vblank was enabled status, enable it again. */ - if (test_and_clear_bit(BIT_IRQS_ENABLED, &ctx->flags)) - decon_enable_vblank(ctx->crtc); - decon_commit(ctx->crtc); } @@ -496,8 +459,9 @@ static void decon_disable(struct exynos_drm_crtc *crtc) struct decon_context *ctx = crtc->ctx; int i; - if (test_bit(BIT_SUSPENDED, &ctx->flags)) - return; + if (!(ctx->out_type & I80_HW_TRG)) + synchronize_irq(ctx->te_irq); + synchronize_irq(ctx->irq); /* * We need to make sure that all windows are disabled before we @@ -509,25 +473,18 @@ static void decon_disable(struct exynos_drm_crtc *crtc) decon_swreset(ctx); - clear_bit(BIT_CLKS_ENABLED, &ctx->flags); - exynos_drm_pipe_clk_enable(crtc, false); pm_runtime_put_sync(ctx->dev); - - set_bit(BIT_SUSPENDED, &ctx->flags); } -static void decon_te_irq_handler(struct exynos_drm_crtc *crtc) +static irqreturn_t decon_te_irq_handler(int irq, void *dev_id) { - struct decon_context *ctx = crtc->ctx; + struct decon_context *ctx = dev_id; - if (!test_bit(BIT_CLKS_ENABLED, &ctx->flags) || - (ctx->out_type & I80_HW_TRG)) - return; + decon_set_bits(ctx, DECON_TRIGCON, TRIGCON_SWTRIGCMD, ~0); - if (test_and_clear_bit(BIT_WIN_UPDATED, &ctx->flags)) - decon_set_bits(ctx, DECON_TRIGCON, TRIGCON_SWTRIGCMD, ~0); + return IRQ_HANDLED; } static void decon_clear_channels(struct exynos_drm_crtc *crtc) @@ -543,11 +500,10 @@ static void decon_clear_channels(struct exynos_drm_crtc *crtc) goto err; } - for (win = 0; win < WINDOWS_NR; win++) { - decon_shadow_protect_win(ctx, win, true); + decon_shadow_protect(ctx, true); + for (win = 0; win < WINDOWS_NR; win++) decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, 0); - decon_shadow_protect_win(ctx, win, false); - } + decon_shadow_protect(ctx, false); decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0); @@ -564,25 +520,24 @@ static const struct exynos_drm_crtc_ops decon_crtc_ops = { .disable = decon_disable, .enable_vblank = decon_enable_vblank, .disable_vblank = decon_disable_vblank, + .get_vblank_counter = decon_get_vblank_counter, .atomic_begin = decon_atomic_begin, .update_plane = decon_update_plane, .disable_plane = decon_disable_plane, .atomic_flush = decon_atomic_flush, - .te_handler = decon_te_irq_handler, }; static int decon_bind(struct device *dev, struct device *master, void *data) { struct decon_context *ctx = dev_get_drvdata(dev); struct drm_device *drm_dev = data; - struct exynos_drm_private *priv = drm_dev->dev_private; struct exynos_drm_plane *exynos_plane; enum exynos_drm_output_type out_type; unsigned int win; int ret; ctx->drm_dev = drm_dev; - ctx->pipe = priv->pipe++; + drm_dev->max_vblank_count = 0xffffffff; for (win = ctx->first_win; win < WINDOWS_NR; win++) { int tmp = (win == ctx->first_win) ? 0 : win; @@ -593,7 +548,7 @@ static int decon_bind(struct device *dev, struct device *master, void *data) ctx->configs[win].type = decon_win_types[tmp]; ret = exynos_plane_init(drm_dev, &ctx->planes[win], win, - 1 << ctx->pipe, &ctx->configs[win]); + &ctx->configs[win]); if (ret) return ret; } @@ -602,23 +557,13 @@ static int decon_bind(struct device *dev, struct device *master, void *data) out_type = (ctx->out_type & IFTYPE_HDMI) ? EXYNOS_DISPLAY_TYPE_HDMI : EXYNOS_DISPLAY_TYPE_LCD; ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base, - ctx->pipe, out_type, - &decon_crtc_ops, ctx); - if (IS_ERR(ctx->crtc)) { - ret = PTR_ERR(ctx->crtc); - goto err; - } + out_type, &decon_crtc_ops, ctx); + if (IS_ERR(ctx->crtc)) + return PTR_ERR(ctx->crtc); decon_clear_channels(ctx->crtc); - ret = drm_iommu_attach_device(drm_dev, dev); - if (ret) - goto err; - - return ret; -err: - priv->pipe--; - return ret; + return drm_iommu_attach_device(drm_dev, dev); } static void decon_unbind(struct device *dev, struct device *master, void *data) @@ -659,9 +604,6 @@ static irqreturn_t decon_irq_handler(int irq, void *dev_id) struct decon_context *ctx = dev_id; u32 val; - if (!test_bit(BIT_CLKS_ENABLED, &ctx->flags)) - goto out; - val = readl(ctx->addr + DECON_VIDINTCON1); val &= VIDINTCON1_INTFRMDONEPEND | VIDINTCON1_INTFRMPEND; @@ -677,7 +619,6 @@ static irqreturn_t decon_irq_handler(int irq, void *dev_id) decon_handle_vblank(ctx); } -out: return IRQ_HANDLED; } @@ -732,6 +673,31 @@ static const struct of_device_id exynos5433_decon_driver_dt_match[] = { }; MODULE_DEVICE_TABLE(of, exynos5433_decon_driver_dt_match); +static int decon_conf_irq(struct decon_context *ctx, const char *name, + irq_handler_t handler, unsigned long int flags, bool required) +{ + struct platform_device *pdev = to_platform_device(ctx->dev); + int ret, irq = platform_get_irq_byname(pdev, name); + + if (irq < 0) { + if (irq == -EPROBE_DEFER) + return irq; + if (required) + dev_err(ctx->dev, "cannot get %s IRQ\n", name); + else + irq = 0; + return irq; + } + irq_set_status_flags(irq, IRQ_NOAUTOEN); + ret = devm_request_irq(ctx->dev, irq, handler, flags, "drm_decon", ctx); + if (ret < 0) { + dev_err(ctx->dev, "IRQ %s request failed\n", name); + return ret; + } + + return irq; +} + static int exynos5433_decon_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -744,7 +710,6 @@ static int exynos5433_decon_probe(struct platform_device *pdev) if (!ctx) return -ENOMEM; - __set_bit(BIT_SUSPENDED, &ctx->flags); ctx->dev = dev; ctx->out_type = (unsigned long)of_device_get_match_data(dev); spin_lock_init(&ctx->vblank_lock); @@ -755,15 +720,6 @@ static int exynos5433_decon_probe(struct platform_device *pdev) ctx->out_type |= IFTYPE_I80; } - if (ctx->out_type & I80_HW_TRG) { - ctx->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node, - "samsung,disp-sysreg"); - if (IS_ERR(ctx->sysreg)) { - dev_err(dev, "failed to get system register\n"); - return PTR_ERR(ctx->sysreg); - } - } - for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) { struct clk *clk; @@ -786,18 +742,34 @@ static int exynos5433_decon_probe(struct platform_device *pdev) return PTR_ERR(ctx->addr); } - res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, - (ctx->out_type & IFTYPE_I80) ? "lcd_sys" : "vsync"); - if (!res) { - dev_err(dev, "cannot find IRQ resource\n"); - return -ENXIO; + if (ctx->out_type & IFTYPE_I80) { + ret = decon_conf_irq(ctx, "lcd_sys", decon_irq_handler, 0, true); + if (ret < 0) + return ret; + ctx->irq = ret; + + ret = decon_conf_irq(ctx, "te", decon_te_irq_handler, + IRQF_TRIGGER_RISING, false); + if (ret < 0) + return ret; + if (ret) { + ctx->te_irq = ret; + ctx->out_type &= ~I80_HW_TRG; + } + } else { + ret = decon_conf_irq(ctx, "vsync", decon_irq_handler, 0, true); + if (ret < 0) + return ret; + ctx->irq = ret; } - ret = devm_request_irq(dev, res->start, decon_irq_handler, 0, - "drm_decon", ctx); - if (ret < 0) { - dev_err(dev, "lcd_sys irq request failed\n"); - return ret; + if (ctx->out_type & I80_HW_TRG) { + ctx->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node, + "samsung,disp-sysreg"); + if (IS_ERR(ctx->sysreg)) { + dev_err(dev, "failed to get system register\n"); + return PTR_ERR(ctx->sysreg); + } } platform_set_drvdata(pdev, ctx); diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c index 48811806fa27..3e88269fdc2e 100644 --- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c @@ -55,7 +55,6 @@ struct decon_context { unsigned long irq_flags; bool i80_if; bool suspended; - int pipe; wait_queue_head_t wait_vsync_queue; atomic_t wait_vsync_event; @@ -130,19 +129,11 @@ static void decon_clear_channels(struct exynos_drm_crtc *crtc) static int decon_ctx_initialize(struct decon_context *ctx, struct drm_device *drm_dev) { - struct exynos_drm_private *priv = drm_dev->dev_private; - int ret; - ctx->drm_dev = drm_dev; - ctx->pipe = priv->pipe++; decon_clear_channels(ctx->crtc); - ret = drm_iommu_attach_device(drm_dev, ctx->dev); - if (ret) - priv->pipe--; - - return ret; + return drm_iommu_attach_device(drm_dev, ctx->dev); } static void decon_ctx_remove(struct decon_context *ctx) @@ -590,7 +581,6 @@ static void decon_disable(struct exynos_drm_crtc *crtc) static const struct exynos_drm_crtc_ops decon_crtc_ops = { .enable = decon_enable, .disable = decon_disable, - .commit = decon_commit, .enable_vblank = decon_enable_vblank, .disable_vblank = decon_disable_vblank, .atomic_begin = decon_atomic_begin, @@ -612,7 +602,7 @@ static irqreturn_t decon_irq_handler(int irq, void *dev_id) writel(clear_bit, ctx->regs + VIDINTCON1); /* check the crtc is detached already from encoder */ - if (ctx->pipe < 0 || !ctx->drm_dev) + if (!ctx->drm_dev) goto out; if (!ctx->i80_if) { @@ -649,15 +639,14 @@ static int decon_bind(struct device *dev, struct device *master, void *data) ctx->configs[i].type = decon_win_types[i]; ret = exynos_plane_init(drm_dev, &ctx->planes[i], i, - 1 << ctx->pipe, &ctx->configs[i]); + &ctx->configs[i]); if (ret) return ret; } exynos_plane = &ctx->planes[DEFAULT_WIN]; ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base, - ctx->pipe, EXYNOS_DISPLAY_TYPE_LCD, - &decon_crtc_ops, ctx); + EXYNOS_DISPLAY_TYPE_LCD, &decon_crtc_ops, ctx); if (IS_ERR(ctx->crtc)) { decon_ctx_remove(ctx); return PTR_ERR(ctx->crtc); diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 0620d3ca2d06..d72777f6411a 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -49,15 +49,6 @@ static void exynos_drm_crtc_disable(struct drm_crtc *crtc) } } -static void -exynos_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) -{ - struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); - - if (exynos_crtc->ops->commit) - exynos_crtc->ops->commit(exynos_crtc); -} - static int exynos_crtc_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state) { @@ -93,7 +84,6 @@ static void exynos_crtc_atomic_flush(struct drm_crtc *crtc, static const struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = { .enable = exynos_drm_crtc_enable, .disable = exynos_drm_crtc_disable, - .mode_set_nofb = exynos_drm_crtc_mode_set_nofb, .atomic_check = exynos_crtc_atomic_check, .atomic_begin = exynos_crtc_atomic_begin, .atomic_flush = exynos_crtc_atomic_flush, @@ -105,16 +95,15 @@ void exynos_crtc_handle_event(struct exynos_drm_crtc *exynos_crtc) struct drm_pending_vblank_event *event = crtc->state->event; unsigned long flags; - if (event) { - crtc->state->event = NULL; - spin_lock_irqsave(&crtc->dev->event_lock, flags); - if (drm_crtc_vblank_get(crtc) == 0) - drm_crtc_arm_vblank_event(crtc, event); - else - drm_crtc_send_vblank_event(crtc, event); - spin_unlock_irqrestore(&crtc->dev->event_lock, flags); - } + if (!event) + return; + crtc->state->event = NULL; + WARN_ON(drm_crtc_vblank_get(crtc) != 0); + + spin_lock_irqsave(&crtc->dev->event_lock, flags); + drm_crtc_arm_vblank_event(crtc, event); + spin_unlock_irqrestore(&crtc->dev->event_lock, flags); } static void exynos_drm_crtc_destroy(struct drm_crtc *crtc) @@ -143,6 +132,16 @@ static void exynos_drm_crtc_disable_vblank(struct drm_crtc *crtc) exynos_crtc->ops->disable_vblank(exynos_crtc); } +static u32 exynos_drm_crtc_get_vblank_counter(struct drm_crtc *crtc) +{ + struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); + + if (exynos_crtc->ops->get_vblank_counter) + return exynos_crtc->ops->get_vblank_counter(exynos_crtc); + + return 0; +} + static const struct drm_crtc_funcs exynos_crtc_funcs = { .set_config = drm_atomic_helper_set_config, .page_flip = drm_atomic_helper_page_flip, @@ -152,11 +151,11 @@ static const struct drm_crtc_funcs exynos_crtc_funcs = { .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, .enable_vblank = exynos_drm_crtc_enable_vblank, .disable_vblank = exynos_drm_crtc_disable_vblank, + .get_vblank_counter = exynos_drm_crtc_get_vblank_counter, }; struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, struct drm_plane *plane, - int pipe, enum exynos_drm_output_type type, const struct exynos_drm_crtc_ops *ops, void *ctx) @@ -169,7 +168,6 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, if (!exynos_crtc) return ERR_PTR(-ENOMEM); - exynos_crtc->pipe = pipe; exynos_crtc->type = type; exynos_crtc->ops = ops; exynos_crtc->ctx = ctx; @@ -196,13 +194,9 @@ int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev, { struct drm_crtc *crtc; - list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head) { - struct exynos_drm_crtc *exynos_crtc; - - exynos_crtc = to_exynos_crtc(crtc); - if (exynos_crtc->type == out_type) - return exynos_crtc->pipe; - } + drm_for_each_crtc(crtc, drm_dev) + if (to_exynos_crtc(crtc)->type == out_type) + return drm_crtc_index(crtc); return -EPERM; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.h b/drivers/gpu/drm/exynos/exynos_drm_crtc.h index 9634fe5ad5fe..ef58b64e3d2d 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.h +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.h @@ -19,7 +19,6 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, struct drm_plane *plane, - int pipe, enum exynos_drm_output_type type, const struct exynos_drm_crtc_ops *ops, void *context); diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 50294a7bd29d..35a8dfc93836 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -171,12 +171,13 @@ static int exynos_drm_suspend(struct device *dev) { struct drm_device *drm_dev = dev_get_drvdata(dev); struct drm_connector *connector; + struct drm_connector_list_iter conn_iter; if (pm_runtime_suspended(dev) || !drm_dev) return 0; - drm_modeset_lock_all(drm_dev); - drm_for_each_connector(connector, drm_dev) { + drm_connector_list_iter_begin(drm_dev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { int old_dpms = connector->dpms; if (connector->funcs->dpms) @@ -185,7 +186,7 @@ static int exynos_drm_suspend(struct device *dev) /* Set the old mode back to the connector for resume */ connector->dpms = old_dpms; } - drm_modeset_unlock_all(drm_dev); + drm_connector_list_iter_end(&conn_iter); return 0; } @@ -194,12 +195,13 @@ static int exynos_drm_resume(struct device *dev) { struct drm_device *drm_dev = dev_get_drvdata(dev); struct drm_connector *connector; + struct drm_connector_list_iter conn_iter; if (pm_runtime_suspended(dev) || !drm_dev) return 0; - drm_modeset_lock_all(drm_dev); - drm_for_each_connector(connector, drm_dev) { + drm_connector_list_iter_begin(drm_dev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { if (connector->funcs->dpms) { int dpms = connector->dpms; @@ -207,7 +209,7 @@ static int exynos_drm_resume(struct device *dev) connector->funcs->dpms(connector, dpms); } } - drm_modeset_unlock_all(drm_dev); + drm_connector_list_iter_end(&conn_iter); return 0; } @@ -376,7 +378,7 @@ static int exynos_drm_bind(struct device *dev) /* Probe non kms sub drivers and virtual display driver. */ ret = exynos_drm_device_subdrv_probe(drm); if (ret) - goto err_cleanup_vblank; + goto err_unbind_all; drm_mode_config_reset(drm); @@ -407,8 +409,6 @@ err_cleanup_fbdev: exynos_drm_fbdev_fini(drm); drm_kms_helper_poll_fini(drm); exynos_drm_device_subdrv_remove(drm); -err_cleanup_vblank: - drm_vblank_cleanup(drm); err_unbind_all: component_unbind_all(drm->dev, drm); err_mode_config_cleanup: diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 39c740572034..a93de321706b 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -115,7 +115,6 @@ struct exynos_drm_plane_config { * * @enable: enable the device * @disable: disable the device - * @commit: set current hw specific display mode to hw. * @enable_vblank: specific driver callback for enabling vblank interrupt. * @disable_vblank: specific driver callback for disabling vblank interrupt. * @atomic_check: validate state @@ -130,9 +129,9 @@ struct exynos_drm_crtc; struct exynos_drm_crtc_ops { void (*enable)(struct exynos_drm_crtc *crtc); void (*disable)(struct exynos_drm_crtc *crtc); - void (*commit)(struct exynos_drm_crtc *crtc); int (*enable_vblank)(struct exynos_drm_crtc *crtc); void (*disable_vblank)(struct exynos_drm_crtc *crtc); + u32 (*get_vblank_counter)(struct exynos_drm_crtc *crtc); int (*atomic_check)(struct exynos_drm_crtc *crtc, struct drm_crtc_state *state); void (*atomic_begin)(struct exynos_drm_crtc *crtc); @@ -153,13 +152,6 @@ struct exynos_drm_clk { * * @base: crtc object. * @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI. - * @pipe: a crtc index created at load() with a new crtc object creation - * and the crtc object would be set to private->crtc array - * to get a crtc object corresponding to this pipe from private->crtc - * array when irq interrupt occurred. the reason of using this pipe is that - * drm framework doesn't support multiple irq yet. - * we can refer to the crtc to current hardware interrupt occurred through - * this pipe value. * @ops: pointer to callbacks for exynos drm specific functionality * @ctx: A pointer to the crtc's implementation specific context * @pipe_clk: A pointer to the crtc's pipeline clock. @@ -167,7 +159,6 @@ struct exynos_drm_clk { struct exynos_drm_crtc { struct drm_crtc base; enum exynos_drm_output_type type; - unsigned int pipe; const struct exynos_drm_crtc_ops *ops; void *ctx; struct exynos_drm_clk *pipe_clk; @@ -200,7 +191,6 @@ struct drm_exynos_file_private { * otherwise default one. * @da_space_size: size of device address space. * if 0 then default value is used for it. - * @pipe: the pipe number for this crtc/manager. * @pending: the crtcs that have pending updates to finish * @lock: protect access to @pending * @wait: wait an atomic commit to finish @@ -211,8 +201,6 @@ struct exynos_drm_private { struct device *dma_dev; void *mapping; - unsigned int pipe; - /* for atomic commit */ u32 pending; spinlock_t lock; diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index d404de86d5f9..a11b79596e2f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -1650,7 +1650,7 @@ static int exynos_dsi_parse_dt(struct exynos_dsi *dsi) if (ret < 0) return ret; - dsi->bridge_node = of_graph_get_remote_node(node, DSI_PORT_OUT, 0); + dsi->bridge_node = of_graph_get_remote_node(node, DSI_PORT_IN, 0); if (!dsi->bridge_node) return -EINVAL; diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 3f04d72c448d..60f93cad6643 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -179,7 +179,6 @@ struct fimd_context { u32 i80ifcon; bool i80_if; bool suspended; - int pipe; wait_queue_head_t wait_vsync_queue; atomic_t wait_vsync_event; atomic_t win_updated; @@ -354,18 +353,13 @@ static void fimd_clear_channels(struct exynos_drm_crtc *crtc) /* Wait for vsync, as disable channel takes effect at next vsync */ if (ch_enabled) { - int pipe = ctx->pipe; - - /* ensure that vblank interrupt won't be reported to core */ ctx->suspended = false; - ctx->pipe = -1; fimd_enable_vblank(ctx->crtc); fimd_wait_for_vblank(ctx->crtc); fimd_disable_vblank(ctx->crtc); ctx->suspended = true; - ctx->pipe = pipe; } clk_disable_unprepare(ctx->lcd_clk); @@ -899,7 +893,7 @@ static void fimd_te_handler(struct exynos_drm_crtc *crtc) u32 trg_type = ctx->driver_data->trg_type; /* Checks the crtc is detached already from encoder */ - if (ctx->pipe < 0 || !ctx->drm_dev) + if (!ctx->drm_dev) return; if (trg_type == I80_HW_TRG) @@ -934,7 +928,6 @@ static void fimd_dp_clock_enable(struct exynos_drm_clk *clk, bool enable) static const struct exynos_drm_crtc_ops fimd_crtc_ops = { .enable = fimd_enable, .disable = fimd_disable, - .commit = fimd_commit, .enable_vblank = fimd_enable_vblank, .disable_vblank = fimd_disable_vblank, .atomic_begin = fimd_atomic_begin, @@ -957,7 +950,7 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id) writel(clear_bit, ctx->regs + VIDINTCON1); /* check the crtc is detached already from encoder */ - if (ctx->pipe < 0 || !ctx->drm_dev) + if (!ctx->drm_dev) goto out; if (!ctx->i80_if) @@ -982,13 +975,11 @@ static int fimd_bind(struct device *dev, struct device *master, void *data) { struct fimd_context *ctx = dev_get_drvdata(dev); struct drm_device *drm_dev = data; - struct exynos_drm_private *priv = drm_dev->dev_private; struct exynos_drm_plane *exynos_plane; unsigned int i; int ret; ctx->drm_dev = drm_dev; - ctx->pipe = priv->pipe++; for (i = 0; i < WINDOWS_NR; i++) { ctx->configs[i].pixel_formats = fimd_formats; @@ -996,15 +987,14 @@ static int fimd_bind(struct device *dev, struct device *master, void *data) ctx->configs[i].zpos = i; ctx->configs[i].type = fimd_win_types[i]; ret = exynos_plane_init(drm_dev, &ctx->planes[i], i, - 1 << ctx->pipe, &ctx->configs[i]); + &ctx->configs[i]); if (ret) return ret; } exynos_plane = &ctx->planes[DEFAULT_WIN]; ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base, - ctx->pipe, EXYNOS_DISPLAY_TYPE_LCD, - &fimd_crtc_ops, ctx); + EXYNOS_DISPLAY_TYPE_LCD, &fimd_crtc_ops, ctx); if (IS_ERR(ctx->crtc)) return PTR_ERR(ctx->crtc); @@ -1019,11 +1009,7 @@ static int fimd_bind(struct device *dev, struct device *master, void *data) if (is_drm_iommu_supported(drm_dev)) fimd_clear_channels(ctx->crtc); - ret = drm_iommu_attach_device(drm_dev, dev); - if (ret) - priv->pipe--; - - return ret; + return drm_iommu_attach_device(drm_dev, dev); } static void fimd_unbind(struct device *dev, struct device *master, diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c index 55a1579d11b3..c23479be4850 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c @@ -59,7 +59,8 @@ static int exynos_drm_alloc_buf(struct exynos_drm_gem *exynos_gem) nr_pages = exynos_gem->size >> PAGE_SHIFT; - exynos_gem->pages = drm_calloc_large(nr_pages, sizeof(struct page *)); + exynos_gem->pages = kvmalloc_array(nr_pages, sizeof(struct page *), + GFP_KERNEL | __GFP_ZERO); if (!exynos_gem->pages) { DRM_ERROR("failed to allocate pages.\n"); return -ENOMEM; @@ -101,7 +102,7 @@ err_dma_free: dma_free_attrs(to_dma_dev(dev), exynos_gem->size, exynos_gem->cookie, exynos_gem->dma_addr, exynos_gem->dma_attrs); err_free: - drm_free_large(exynos_gem->pages); + kvfree(exynos_gem->pages); return ret; } @@ -122,7 +123,7 @@ static void exynos_drm_free_buf(struct exynos_drm_gem *exynos_gem) (dma_addr_t)exynos_gem->dma_addr, exynos_gem->dma_attrs); - drm_free_large(exynos_gem->pages); + kvfree(exynos_gem->pages); } static int exynos_drm_gem_handle_create(struct drm_gem_object *obj, @@ -559,7 +560,7 @@ exynos_drm_gem_prime_import_sg_table(struct drm_device *dev, exynos_gem->dma_addr = sg_dma_address(sgt->sgl); npages = exynos_gem->size >> PAGE_SHIFT; - exynos_gem->pages = drm_malloc_ab(npages, sizeof(struct page *)); + exynos_gem->pages = kvmalloc_array(npages, sizeof(struct page *), GFP_KERNEL); if (!exynos_gem->pages) { ret = -ENOMEM; goto err; @@ -588,7 +589,7 @@ exynos_drm_gem_prime_import_sg_table(struct drm_device *dev, return &exynos_gem->base; err_free_large: - drm_free_large(exynos_gem->pages); + kvfree(exynos_gem->pages); err: drm_gem_object_release(&exynos_gem->base); kfree(exynos_gem); diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index c2f17f30afab..611b6fd65433 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c @@ -273,14 +273,13 @@ static void exynos_plane_attach_zpos_property(struct drm_plane *plane, } int exynos_plane_init(struct drm_device *dev, - struct exynos_drm_plane *exynos_plane, - unsigned int index, unsigned long possible_crtcs, + struct exynos_drm_plane *exynos_plane, unsigned int index, const struct exynos_drm_plane_config *config) { int err; err = drm_universal_plane_init(dev, &exynos_plane->base, - possible_crtcs, + 1 << dev->mode_config.num_crtc, &exynos_plane_funcs, config->pixel_formats, config->num_pixel_formats, diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.h b/drivers/gpu/drm/exynos/exynos_drm_plane.h index 9aafad164cdf..497047b19614 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.h +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.h @@ -11,5 +11,4 @@ int exynos_plane_init(struct drm_device *dev, struct exynos_drm_plane *exynos_plane, unsigned int index, - unsigned long possible_crtcs, const struct exynos_drm_plane_config *config); diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index ef86dbf1cc29..cb8a72842537 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -51,7 +51,6 @@ struct vidi_context { bool suspended; struct timer_list timer; struct mutex lock; - int pipe; }; static inline struct vidi_context *encoder_to_vidi(struct drm_encoder *e) @@ -153,17 +152,6 @@ static void vidi_disable(struct exynos_drm_crtc *crtc) mutex_unlock(&ctx->lock); } -static int vidi_ctx_initialize(struct vidi_context *ctx, - struct drm_device *drm_dev) -{ - struct exynos_drm_private *priv = drm_dev->dev_private; - - ctx->drm_dev = drm_dev; - ctx->pipe = priv->pipe++; - - return 0; -} - static const struct exynos_drm_crtc_ops vidi_crtc_ops = { .enable = vidi_enable, .disable = vidi_disable, @@ -177,9 +165,6 @@ static void vidi_fake_vblank_timer(unsigned long arg) { struct vidi_context *ctx = (void *)arg; - if (ctx->pipe < 0) - return; - if (drm_crtc_handle_vblank(&ctx->crtc->base)) mod_timer(&ctx->timer, jiffies + msecs_to_jiffies(VIDI_REFRESH_TIME) - 1); @@ -399,7 +384,7 @@ static int vidi_bind(struct device *dev, struct device *master, void *data) unsigned int i; int pipe, ret; - vidi_ctx_initialize(ctx, drm_dev); + ctx->drm_dev = drm_dev; plane_config.pixel_formats = formats; plane_config.num_pixel_formats = ARRAY_SIZE(formats); @@ -409,15 +394,14 @@ static int vidi_bind(struct device *dev, struct device *master, void *data) plane_config.type = vidi_win_types[i]; ret = exynos_plane_init(drm_dev, &ctx->planes[i], i, - 1 << ctx->pipe, &plane_config); + &plane_config); if (ret) return ret; } exynos_plane = &ctx->planes[DEFAULT_WIN]; ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base, - ctx->pipe, EXYNOS_DISPLAY_TYPE_VIDI, - &vidi_crtc_ops, ctx); + EXYNOS_DISPLAY_TYPE_VIDI, &vidi_crtc_ops, ctx); if (IS_ERR(ctx->crtc)) { DRM_ERROR("failed to create crtc.\n"); return PTR_ERR(ctx->crtc); diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 1ff6ab6371e8..06bfbe400cf1 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -1486,8 +1486,6 @@ static void hdmi_enable(struct drm_encoder *encoder) static void hdmi_disable(struct drm_encoder *encoder) { struct hdmi_context *hdata = encoder_to_hdmi(encoder); - struct drm_crtc *crtc = encoder->crtc; - const struct drm_crtc_helper_funcs *funcs = NULL; if (!hdata->powered) return; @@ -1498,16 +1496,11 @@ static void hdmi_disable(struct drm_encoder *encoder) * to disable TV Subsystem should be as following, * VP -> Mixer -> HDMI * - * Below codes will try to disable Mixer and VP(if used) - * prior to disabling HDMI. + * To achieve such sequence HDMI is disabled together with HDMI PHY, via + * pipe clock callback. */ - if (crtc) - funcs = crtc->helper_private; - if (funcs && funcs->disable) - (*funcs->disable)(crtc); - - cec_notifier_set_phys_addr(hdata->notifier, CEC_PHYS_ADDR_INVALID); cancel_delayed_work(&hdata->hotplug_work); + cec_notifier_set_phys_addr(hdata->notifier, CEC_PHYS_ADDR_INVALID); hdmiphy_disable(hdata); } diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 25edb635a197..6bed4f3ffcd6 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -45,6 +45,22 @@ #define MIXER_WIN_NR 3 #define VP_DEFAULT_WIN 2 +/* + * Mixer color space conversion coefficient triplet. + * Used for CSC from RGB to YCbCr. + * Each coefficient is a 10-bit fixed point number with + * sign and no integer part, i.e. + * [0:8] = fractional part (representing a value y = x / 2^9) + * [9] = sign + * Negative values are encoded with two's complement. + */ +#define MXR_CSC_C(x) ((int)((x) * 512.0) & 0x3ff) +#define MXR_CSC_CT(a0, a1, a2) \ + ((MXR_CSC_C(a0) << 20) | (MXR_CSC_C(a1) << 10) | (MXR_CSC_C(a2) << 0)) + +/* YCbCr value, used for mixer background color configuration. */ +#define MXR_YCBCR_VAL(y, cb, cr) (((y) << 16) | ((cb) << 8) | ((cr) << 0)) + /* The pixelformats that are natively supported by the mixer. */ #define MXR_FORMAT_RGB565 4 #define MXR_FORMAT_ARGB1555 5 @@ -99,7 +115,6 @@ struct mixer_context { struct drm_device *drm_dev; struct exynos_drm_crtc *crtc; struct exynos_drm_plane planes[MIXER_WIN_NR]; - int pipe; unsigned long flags; struct mixer_resources mixer_res; @@ -382,37 +397,24 @@ static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height) struct mixer_resources *res = &ctx->mixer_res; u32 val; - if (height == 480) { - val = MXR_CFG_RGB601_0_255; - } else if (height == 576) { + switch (height) { + case 480: + case 576: val = MXR_CFG_RGB601_0_255; - } else if (height == 720) { - val = MXR_CFG_RGB709_16_235; - mixer_reg_write(res, MXR_CM_COEFF_Y, - (1 << 30) | (94 << 20) | (314 << 10) | - (32 << 0)); - mixer_reg_write(res, MXR_CM_COEFF_CB, - (972 << 20) | (851 << 10) | (225 << 0)); - mixer_reg_write(res, MXR_CM_COEFF_CR, - (225 << 20) | (820 << 10) | (1004 << 0)); - } else if (height == 1080) { - val = MXR_CFG_RGB709_16_235; - mixer_reg_write(res, MXR_CM_COEFF_Y, - (1 << 30) | (94 << 20) | (314 << 10) | - (32 << 0)); - mixer_reg_write(res, MXR_CM_COEFF_CB, - (972 << 20) | (851 << 10) | (225 << 0)); - mixer_reg_write(res, MXR_CM_COEFF_CR, - (225 << 20) | (820 << 10) | (1004 << 0)); - } else { + break; + case 720: + case 1080: + default: val = MXR_CFG_RGB709_16_235; + /* Configure the BT.709 CSC matrix for full range RGB. */ mixer_reg_write(res, MXR_CM_COEFF_Y, - (1 << 30) | (94 << 20) | (314 << 10) | - (32 << 0)); + MXR_CSC_CT( 0.184, 0.614, 0.063) | + MXR_CM_COEFF_RGB_FULL); mixer_reg_write(res, MXR_CM_COEFF_CB, - (972 << 20) | (851 << 10) | (225 << 0)); + MXR_CSC_CT(-0.102, -0.338, 0.440)); mixer_reg_write(res, MXR_CM_COEFF_CR, - (225 << 20) | (820 << 10) | (1004 << 0)); + MXR_CSC_CT( 0.440, -0.399, -0.040)); + break; } mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK); @@ -729,10 +731,10 @@ static void mixer_win_reset(struct mixer_context *ctx) /* reset default layer priority */ mixer_reg_write(res, MXR_LAYER_CFG, 0); - /* setting background color */ - mixer_reg_write(res, MXR_BG_COLOR0, 0x008080); - mixer_reg_write(res, MXR_BG_COLOR1, 0x008080); - mixer_reg_write(res, MXR_BG_COLOR2, 0x008080); + /* set all background colors to RGB (0,0,0) */ + mixer_reg_write(res, MXR_BG_COLOR0, MXR_YCBCR_VAL(0, 128, 128)); + mixer_reg_write(res, MXR_BG_COLOR1, MXR_YCBCR_VAL(0, 128, 128)); + mixer_reg_write(res, MXR_BG_COLOR2, MXR_YCBCR_VAL(0, 128, 128)); if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) { /* configuration of Video Processor Registers */ @@ -900,7 +902,6 @@ static int mixer_initialize(struct mixer_context *mixer_ctx, priv = drm_dev->dev_private; mixer_ctx->drm_dev = drm_dev; - mixer_ctx->pipe = priv->pipe++; /* acquire resources: regs, irqs, clocks */ ret = mixer_resources_init(mixer_ctx); @@ -918,11 +919,7 @@ static int mixer_initialize(struct mixer_context *mixer_ctx, } } - ret = drm_iommu_attach_device(drm_dev, mixer_ctx->dev); - if (ret) - priv->pipe--; - - return ret; + return drm_iommu_attach_device(drm_dev, mixer_ctx->dev); } static void mixer_ctx_remove(struct mixer_context *mixer_ctx) @@ -1158,15 +1155,14 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data) continue; ret = exynos_plane_init(drm_dev, &ctx->planes[i], i, - 1 << ctx->pipe, &plane_configs[i]); + &plane_configs[i]); if (ret) return ret; } exynos_plane = &ctx->planes[DEFAULT_WIN]; ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base, - ctx->pipe, EXYNOS_DISPLAY_TYPE_HDMI, - &mixer_crtc_ops, ctx); + EXYNOS_DISPLAY_TYPE_HDMI, &mixer_crtc_ops, ctx); if (IS_ERR(ctx->crtc)) { mixer_ctx_remove(ctx); ret = PTR_ERR(ctx->crtc); diff --git a/drivers/gpu/drm/exynos/regs-mixer.h b/drivers/gpu/drm/exynos/regs-mixer.h index 7f22df5bf707..c311f571bdf9 100644 --- a/drivers/gpu/drm/exynos/regs-mixer.h +++ b/drivers/gpu/drm/exynos/regs-mixer.h @@ -140,11 +140,11 @@ #define MXR_INT_EN_VSYNC (1 << 11) #define MXR_INT_EN_ALL (0x0f << 8) -/* bit for MXR_INT_STATUS */ +/* bits for MXR_INT_STATUS */ #define MXR_INT_CLEAR_VSYNC (1 << 11) #define MXR_INT_STATUS_VSYNC (1 << 0) -/* bit for MXR_LAYER_CFG */ +/* bits for MXR_LAYER_CFG */ #define MXR_LAYER_CFG_GRP1_VAL(x) MXR_MASK_VAL(x, 11, 8) #define MXR_LAYER_CFG_GRP1_MASK MXR_LAYER_CFG_GRP1_VAL(~0) #define MXR_LAYER_CFG_GRP0_VAL(x) MXR_MASK_VAL(x, 7, 4) @@ -152,5 +152,8 @@ #define MXR_LAYER_CFG_VP_VAL(x) MXR_MASK_VAL(x, 3, 0) #define MXR_LAYER_CFG_VP_MASK MXR_LAYER_CFG_VP_VAL(~0) +/* bits for MXR_CM_COEFF_Y */ +#define MXR_CM_COEFF_RGB_FULL (1 << 30) + #endif /* SAMSUNG_REGS_MIXER_H */ |