diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-12-13 20:35:09 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-12-13 20:35:09 +0300 |
commit | 9439b3710df688d853eb6cb4851256f2c92b1797 (patch) | |
tree | a0e5de21bbe65ac73fb69cfacaa700fb8e934483 /drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c | |
parent | 7079efc9d3e7f1f7cdd34082ec58209026315057 (diff) | |
parent | 2cf026ae85c42f253feb9f420d1b4bc99bd5503d (diff) | |
download | linux-9439b3710df688d853eb6cb4851256f2c92b1797.tar.xz |
Merge tag 'drm-for-v4.10' of git://people.freedesktop.org/~airlied/linux
Pull drm updates from Dave Airlie:
"This is the main pull request for drm for 4.10 kernel.
New drivers:
- ZTE VOU display driver (zxdrm)
- Amlogic Meson Graphic Controller GXBB/GXL/GXM SoCs (meson)
- MXSFB support (mxsfb)
Core:
- Format handling has been reworked
- Better atomic state debugging
- drm_mm leak debugging
- Atomic explicit fencing support
- fbdev helper ops
- Documentation updates
- MST fbcon fixes
Bridge:
- Silicon Image SiI8620 driver
Panel:
- Add support for new simple panels
i915:
- GVT Device model
- Better HDMI2.0 support on skylake
- More watermark fixes
- GPU idling rework for suspend/resume
- DP Audio workarounds
- Scheduler prep-work
- Opregion CADL handling
- GPU scheduler and priority boosting
amdgfx/radeon:
- Support for virtual devices
- New VM manager for non-contig VRAM buffers
- UVD powergating
- SI register header cleanup
- Cursor fixes
- Powermanagement fixes
nouveau:
- Powermangement reworks for better voltage/clock changes
- Atomic modesetting support
- Displayport Multistream (MST) support.
- GP102/104 hang and cursor fixes
- GP106 support
hisilicon:
- hibmc support (BMC chip for aarch64 servers)
armada:
- add tracing support for overlay change
- refactor plane support
- de-midlayer the driver
omapdrm:
- Timing code cleanups
rcar-du:
- R8A7792/R8A7796 support
- Misc fixes.
sunxi:
- A31 SoC display engine support
imx-drm:
- YUV format support
- Cleanup plane atomic update
mali-dp:
- Misc fixes
dw-hdmi:
- Add support for HDMI i2c master controller
tegra:
- IOMMU support fixes
- Error handling fixes
tda998x:
- Fix connector registration
- Improved robustness
- Fix infoframe/audio compliance
virtio:
- fix busid issues
- allocate more vbufs
qxl:
- misc fixes and cleanups.
vc4:
- Fragment shader threading
- ETC1 support
- VEC (tv-out) support
msm:
- A5XX GPU support
- Lots of atomic changes
tilcdc:
- Misc fixes and cleanups.
etnaviv:
- Fix dma-buf export path
- DRAW_INSTANCED support
- fix driver on i.MX6SX
exynos:
- HDMI refactoring
fsl-dcu:
- fbdev changes"
* tag 'drm-for-v4.10' of git://people.freedesktop.org/~airlied/linux: (1343 commits)
drm/nouveau/kms/nv50: fix atomic regression on original G80
drm/nouveau/bl: Do not register interface if Apple GMUX detected
drm/nouveau/bl: Assign different names to interfaces
drm/nouveau/bios/dp: fix handling of LevelEntryTableIndex on DP table 4.2
drm/nouveau/ltc: protect clearing of comptags with mutex
drm/nouveau/gr/gf100-: handle GPC/TPC/MPC trap
drm/nouveau/core: recognise GP106 chipset
drm/nouveau/ttm: wait for bo fence to signal before unmapping vmas
drm/nouveau/gr/gf100-: FECS intr handling is not relevant on proprietary ucode
drm/nouveau/gr/gf100-: properly ack all FECS error interrupts
drm/nouveau/fifo/gf100-: recover from host mmu faults
drm: Add fake controlD* symlinks for backwards compat
drm/vc4: Don't use drm_put_dev
drm/vc4: Document VEC DT binding
drm/vc4: Add support for the VEC (Video Encoder) IP
drm: Add TV connector states to drm_connector_state
drm: Turn DRM_MODE_SUBCONNECTOR_xx definitions into an enum
drm/vc4: Fix ->clock_select setting for the VEC encoder
drm/amdgpu/dce6: Set MASTER_UPDATE_MODE to 0 in resume_mc_access as well
drm/amdgpu: use pin rather than pin_restricted in a few cases
...
Diffstat (limited to 'drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c')
-rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c | 267 |
1 files changed, 204 insertions, 63 deletions
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c index ed7143d35b25..5f6cd8745dbc 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c @@ -19,6 +19,7 @@ #include <linux/of_irq.h> #include "msm_drv.h" +#include "msm_gem.h" #include "msm_mmu.h" #include "mdp5_kms.h" @@ -71,10 +72,49 @@ static int mdp5_hw_init(struct msm_kms *kms) return 0; } +struct mdp5_state *mdp5_get_state(struct drm_atomic_state *s) +{ + struct msm_drm_private *priv = s->dev->dev_private; + struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms)); + struct msm_kms_state *state = to_kms_state(s); + struct mdp5_state *new_state; + int ret; + + if (state->state) + return state->state; + + ret = drm_modeset_lock(&mdp5_kms->state_lock, s->acquire_ctx); + if (ret) + return ERR_PTR(ret); + + new_state = kmalloc(sizeof(*mdp5_kms->state), GFP_KERNEL); + if (!new_state) + return ERR_PTR(-ENOMEM); + + /* Copy state: */ + new_state->hwpipe = mdp5_kms->state->hwpipe; + if (mdp5_kms->smp) + new_state->smp = mdp5_kms->state->smp; + + state->state = new_state; + + return new_state; +} + +static void mdp5_swap_state(struct msm_kms *kms, struct drm_atomic_state *state) +{ + struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); + swap(to_kms_state(state)->state, mdp5_kms->state); +} + static void mdp5_prepare_commit(struct msm_kms *kms, struct drm_atomic_state *state) { struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); + mdp5_enable(mdp5_kms); + + if (mdp5_kms->smp) + mdp5_smp_prepare_commit(mdp5_kms->smp, &mdp5_kms->state->smp); } static void mdp5_complete_commit(struct msm_kms *kms, struct drm_atomic_state *state) @@ -87,6 +127,9 @@ static void mdp5_complete_commit(struct msm_kms *kms, struct drm_atomic_state *s for_each_plane_in_state(state, plane, plane_state, i) mdp5_plane_complete_commit(plane, plane_state); + if (mdp5_kms->smp) + mdp5_smp_complete_commit(mdp5_kms->smp, &mdp5_kms->state->smp); + mdp5_disable(mdp5_kms); } @@ -117,14 +160,66 @@ static int mdp5_set_split_display(struct msm_kms *kms, static void mdp5_kms_destroy(struct msm_kms *kms) { struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); - struct msm_mmu *mmu = mdp5_kms->mmu; + struct msm_gem_address_space *aspace = mdp5_kms->aspace; + int i; + + for (i = 0; i < mdp5_kms->num_hwpipes; i++) + mdp5_pipe_destroy(mdp5_kms->hwpipes[i]); - if (mmu) { - mmu->funcs->detach(mmu, iommu_ports, ARRAY_SIZE(iommu_ports)); - mmu->funcs->destroy(mmu); + if (aspace) { + aspace->mmu->funcs->detach(aspace->mmu, + iommu_ports, ARRAY_SIZE(iommu_ports)); + msm_gem_address_space_destroy(aspace); } } +#ifdef CONFIG_DEBUG_FS +static int smp_show(struct seq_file *m, void *arg) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + struct msm_drm_private *priv = dev->dev_private; + struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms)); + struct drm_printer p = drm_seq_file_printer(m); + + if (!mdp5_kms->smp) { + drm_printf(&p, "no SMP pool\n"); + return 0; + } + + mdp5_smp_dump(mdp5_kms->smp, &p); + + return 0; +} + +static struct drm_info_list mdp5_debugfs_list[] = { + {"smp", smp_show }, +}; + +static int mdp5_kms_debugfs_init(struct msm_kms *kms, struct drm_minor *minor) +{ + struct drm_device *dev = minor->dev; + int ret; + + ret = drm_debugfs_create_files(mdp5_debugfs_list, + ARRAY_SIZE(mdp5_debugfs_list), + minor->debugfs_root, minor); + + if (ret) { + dev_err(dev->dev, "could not install mdp5_debugfs_list\n"); + return ret; + } + + return 0; +} + +static void mdp5_kms_debugfs_cleanup(struct msm_kms *kms, struct drm_minor *minor) +{ + drm_debugfs_remove_files(mdp5_debugfs_list, + ARRAY_SIZE(mdp5_debugfs_list), minor); +} +#endif + static const struct mdp_kms_funcs kms_funcs = { .base = { .hw_init = mdp5_hw_init, @@ -134,6 +229,7 @@ static const struct mdp_kms_funcs kms_funcs = { .irq = mdp5_irq, .enable_vblank = mdp5_enable_vblank, .disable_vblank = mdp5_disable_vblank, + .swap_state = mdp5_swap_state, .prepare_commit = mdp5_prepare_commit, .complete_commit = mdp5_complete_commit, .wait_for_crtc_commit_done = mdp5_wait_for_crtc_commit_done, @@ -141,6 +237,10 @@ static const struct mdp_kms_funcs kms_funcs = { .round_pixclk = mdp5_round_pixclk, .set_split_display = mdp5_set_split_display, .destroy = mdp5_kms_destroy, +#ifdef CONFIG_DEBUG_FS + .debugfs_init = mdp5_kms_debugfs_init, + .debugfs_cleanup = mdp5_kms_debugfs_cleanup, +#endif }, .set_irqmask = mdp5_set_irqmask, }; @@ -321,15 +421,6 @@ static int modeset_init_intf(struct mdp5_kms *mdp5_kms, int intf_num) static int modeset_init(struct mdp5_kms *mdp5_kms) { - static const enum mdp5_pipe crtcs[] = { - SSPP_RGB0, SSPP_RGB1, SSPP_RGB2, SSPP_RGB3, - }; - static const enum mdp5_pipe vig_planes[] = { - SSPP_VIG0, SSPP_VIG1, SSPP_VIG2, SSPP_VIG3, - }; - static const enum mdp5_pipe dma_planes[] = { - SSPP_DMA0, SSPP_DMA1, - }; struct drm_device *dev = mdp5_kms->dev; struct msm_drm_private *priv = dev->dev_private; const struct mdp5_cfg_hw *hw_cfg; @@ -337,58 +428,35 @@ static int modeset_init(struct mdp5_kms *mdp5_kms) hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg); - /* construct CRTCs and their private planes: */ - for (i = 0; i < hw_cfg->pipe_rgb.count; i++) { + /* Construct planes equaling the number of hw pipes, and CRTCs + * for the N layer-mixers (LM). The first N planes become primary + * planes for the CRTCs, with the remainder as overlay planes: + */ + for (i = 0; i < mdp5_kms->num_hwpipes; i++) { + bool primary = i < mdp5_cfg->lm.count; struct drm_plane *plane; struct drm_crtc *crtc; - plane = mdp5_plane_init(dev, crtcs[i], true, - hw_cfg->pipe_rgb.base[i], hw_cfg->pipe_rgb.caps); + plane = mdp5_plane_init(dev, primary); if (IS_ERR(plane)) { ret = PTR_ERR(plane); - dev_err(dev->dev, "failed to construct plane for %s (%d)\n", - pipe2name(crtcs[i]), ret); + dev_err(dev->dev, "failed to construct plane %d (%d)\n", i, ret); goto fail; } + priv->planes[priv->num_planes++] = plane; + + if (!primary) + continue; crtc = mdp5_crtc_init(dev, plane, i); if (IS_ERR(crtc)) { ret = PTR_ERR(crtc); - dev_err(dev->dev, "failed to construct crtc for %s (%d)\n", - pipe2name(crtcs[i]), ret); + dev_err(dev->dev, "failed to construct crtc %d (%d)\n", i, ret); goto fail; } priv->crtcs[priv->num_crtcs++] = crtc; } - /* Construct video planes: */ - for (i = 0; i < hw_cfg->pipe_vig.count; i++) { - struct drm_plane *plane; - - plane = mdp5_plane_init(dev, vig_planes[i], false, - hw_cfg->pipe_vig.base[i], hw_cfg->pipe_vig.caps); - if (IS_ERR(plane)) { - ret = PTR_ERR(plane); - dev_err(dev->dev, "failed to construct %s plane: %d\n", - pipe2name(vig_planes[i]), ret); - goto fail; - } - } - - /* DMA planes */ - for (i = 0; i < hw_cfg->pipe_dma.count; i++) { - struct drm_plane *plane; - - plane = mdp5_plane_init(dev, dma_planes[i], false, - hw_cfg->pipe_dma.base[i], hw_cfg->pipe_dma.caps); - if (IS_ERR(plane)) { - ret = PTR_ERR(plane); - dev_err(dev->dev, "failed to construct %s plane: %d\n", - pipe2name(dma_planes[i]), ret); - goto fail; - } - } - /* Construct encoders and modeset initialize connector devices * for each external display interface. */ @@ -564,7 +632,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) struct mdp5_kms *mdp5_kms; struct mdp5_cfg *config; struct msm_kms *kms; - struct msm_mmu *mmu; + struct msm_gem_address_space *aspace; int irq, i, ret; /* priv->kms would have been populated by the MDP5 driver */ @@ -606,30 +674,29 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) mdelay(16); if (config->platform.iommu) { - mmu = msm_iommu_new(&pdev->dev, config->platform.iommu); - if (IS_ERR(mmu)) { - ret = PTR_ERR(mmu); - dev_err(&pdev->dev, "failed to init iommu: %d\n", ret); - iommu_domain_free(config->platform.iommu); + aspace = msm_gem_address_space_create(&pdev->dev, + config->platform.iommu, "mdp5"); + if (IS_ERR(aspace)) { + ret = PTR_ERR(aspace); goto fail; } - ret = mmu->funcs->attach(mmu, iommu_ports, + mdp5_kms->aspace = aspace; + + ret = aspace->mmu->funcs->attach(aspace->mmu, iommu_ports, ARRAY_SIZE(iommu_ports)); if (ret) { dev_err(&pdev->dev, "failed to attach iommu: %d\n", ret); - mmu->funcs->destroy(mmu); goto fail; } } else { dev_info(&pdev->dev, "no iommu, fallback to phys contig buffers for scanout\n"); - mmu = NULL; + aspace = NULL;; } - mdp5_kms->mmu = mmu; - mdp5_kms->id = msm_register_mmu(dev, mmu); + mdp5_kms->id = msm_register_address_space(dev, aspace); if (mdp5_kms->id < 0) { ret = mdp5_kms->id; dev_err(&pdev->dev, "failed to register mdp5 iommu: %d\n", ret); @@ -644,8 +711,8 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) dev->mode_config.min_width = 0; dev->mode_config.min_height = 0; - dev->mode_config.max_width = config->hw->lm.max_width; - dev->mode_config.max_height = config->hw->lm.max_height; + dev->mode_config.max_width = 0xffff; + dev->mode_config.max_height = 0xffff; dev->driver->get_vblank_timestamp = mdp5_get_vblank_timestamp; dev->driver->get_scanout_position = mdp5_get_scanoutpos; @@ -673,6 +740,69 @@ static void mdp5_destroy(struct platform_device *pdev) if (mdp5_kms->rpm_enabled) pm_runtime_disable(&pdev->dev); + + kfree(mdp5_kms->state); +} + +static int construct_pipes(struct mdp5_kms *mdp5_kms, int cnt, + const enum mdp5_pipe *pipes, const uint32_t *offsets, + uint32_t caps) +{ + struct drm_device *dev = mdp5_kms->dev; + int i, ret; + + for (i = 0; i < cnt; i++) { + struct mdp5_hw_pipe *hwpipe; + + hwpipe = mdp5_pipe_init(pipes[i], offsets[i], caps); + if (IS_ERR(hwpipe)) { + ret = PTR_ERR(hwpipe); + dev_err(dev->dev, "failed to construct pipe for %s (%d)\n", + pipe2name(pipes[i]), ret); + return ret; + } + hwpipe->idx = mdp5_kms->num_hwpipes; + mdp5_kms->hwpipes[mdp5_kms->num_hwpipes++] = hwpipe; + } + + return 0; +} + +static int hwpipe_init(struct mdp5_kms *mdp5_kms) +{ + static const enum mdp5_pipe rgb_planes[] = { + SSPP_RGB0, SSPP_RGB1, SSPP_RGB2, SSPP_RGB3, + }; + static const enum mdp5_pipe vig_planes[] = { + SSPP_VIG0, SSPP_VIG1, SSPP_VIG2, SSPP_VIG3, + }; + static const enum mdp5_pipe dma_planes[] = { + SSPP_DMA0, SSPP_DMA1, + }; + const struct mdp5_cfg_hw *hw_cfg; + int ret; + + hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg); + + /* Construct RGB pipes: */ + ret = construct_pipes(mdp5_kms, hw_cfg->pipe_rgb.count, rgb_planes, + hw_cfg->pipe_rgb.base, hw_cfg->pipe_rgb.caps); + if (ret) + return ret; + + /* Construct video (VIG) pipes: */ + ret = construct_pipes(mdp5_kms, hw_cfg->pipe_vig.count, vig_planes, + hw_cfg->pipe_vig.base, hw_cfg->pipe_vig.caps); + if (ret) + return ret; + + /* Construct DMA pipes: */ + ret = construct_pipes(mdp5_kms, hw_cfg->pipe_dma.count, dma_planes, + hw_cfg->pipe_dma.base, hw_cfg->pipe_dma.caps); + if (ret) + return ret; + + return 0; } static int mdp5_init(struct platform_device *pdev, struct drm_device *dev) @@ -696,6 +826,13 @@ static int mdp5_init(struct platform_device *pdev, struct drm_device *dev) mdp5_kms->dev = dev; mdp5_kms->pdev = pdev; + drm_modeset_lock_init(&mdp5_kms->state_lock); + mdp5_kms->state = kzalloc(sizeof(*mdp5_kms->state), GFP_KERNEL); + if (!mdp5_kms->state) { + ret = -ENOMEM; + goto fail; + } + mdp5_kms->mmio = msm_ioremap(pdev, "mdp_phys", "MDP5"); if (IS_ERR(mdp5_kms->mmio)) { ret = PTR_ERR(mdp5_kms->mmio); @@ -749,7 +886,7 @@ static int mdp5_init(struct platform_device *pdev, struct drm_device *dev) * this section initializes the SMP: */ if (mdp5_kms->caps & MDP_CAP_SMP) { - mdp5_kms->smp = mdp5_smp_init(mdp5_kms->dev, &config->hw->smp); + mdp5_kms->smp = mdp5_smp_init(mdp5_kms, &config->hw->smp); if (IS_ERR(mdp5_kms->smp)) { ret = PTR_ERR(mdp5_kms->smp); mdp5_kms->smp = NULL; @@ -764,6 +901,10 @@ static int mdp5_init(struct platform_device *pdev, struct drm_device *dev) goto fail; } + ret = hwpipe_init(mdp5_kms); + if (ret) + goto fail; + /* set uninit-ed kms */ priv->kms = &mdp5_kms->base.base; |