diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-12-25 11:48:26 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-12-25 11:48:26 -0800 |
commit | 4971f090aa7f6ce5daa094ce4334f6618f93a7eb (patch) | |
tree | 45d75782b7dedbec76a3ab82d2769f7707668071 /drivers/gpu/drm/msm/msm_drv.c | |
parent | c76cd634eb5bfd497617ea224a54a03b545c8c4d (diff) | |
parent | 2a3c83f5fe0770d13bbb71b23674886ff4111f44 (diff) | |
download | lwn-4971f090aa7f6ce5daa094ce4334f6618f93a7eb.tar.gz lwn-4971f090aa7f6ce5daa094ce4334f6618f93a7eb.zip |
Merge tag 'drm-next-2018-12-14' of git://anongit.freedesktop.org/drm/drm
Pull drm updates from Dave Airlie:
"Core:
- shared fencing staging removal
- drop transactional atomic helpers and move helpers to new location
- DP/MST atomic cleanup
- Leasing cleanups and drop EXPORT_SYMBOL
- Convert drivers to atomic helpers and generic fbdev.
- removed deprecated obj_ref/unref in favour of get/put
- Improve dumb callback documentation
- MODESET_LOCK_BEGIN/END helpers
panels:
- CDTech panels, Banana Pi Panel, DLC1010GIG,
- Olimex LCD-O-LinuXino, Samsung S6D16D0, Truly NT35597 WQXGA,
- Himax HX8357D, simulated RTSM AEMv8.
- GPD Win2 panel
- AUO G101EVN010
vgem:
- render node support
ttm:
- move global init out of drivers
- fix LRU handling for ghost objects
- Support for simultaneous submissions to multiple engines
scheduler:
- timeout/fault handling changes to help GPU recovery
- helpers for hw with preemption support
i915:
- Scaler/Watermark fixes
- DP MST + powerwell fixes
- PSR fixes
- Break long get/put shmemfs pages
- Icelake fixes
- Icelake DSI video mode enablement
- Engine workaround improvements
amdgpu:
- freesync support
- GPU reset enabled on CI, VI, SOC15 dGPUs
- ABM support in DC
- KFD support for vega12/polaris12
- SDMA paging queue on vega
- More amdkfd code sharing
- DCC scanout on GFX9
- DC kerneldoc
- Updated SMU firmware for GFX8 chips
- XGMI PSP + hive reset support
- GPU reset
- DC trace support
- Powerplay updates for newer Polaris
- Cursor plane update fast path
- kfd dma-buf support
virtio-gpu:
- add EDID support
vmwgfx:
- pageflip with damage support
nouveau:
- Initial Turing TU104/TU106 modesetting support
msm:
- a2xx gpu support for apq8060 and imx5
- a2xx gpummu support
- mdp4 display support for apq8060
- DPU fixes and cleanups
- enhanced profiling support
- debug object naming interface
- get_iova/page pinning decoupling
tegra:
- Tegra194 host1x, VIC and display support enabled
- Audio over HDMI for Tegra186 and Tegra194
exynos:
- DMA/IOMMU refactoring
- plane alpha + blend mode support
- Color format fixes for mixer driver
rcar-du:
- R8A7744 and R8A77470 support
- R8A77965 LVDS support
imx:
- fbdev emulation fix
- multi-tiled scalling fixes
- SPDX identifiers
rockchip
- dw_hdmi support
- dw-mipi-dsi + dual dsi support
- mailbox read size fix
qxl:
- fix cursor pinning
vc4:
- YUV support (scaling + cursor)
v3d:
- enable TFU (Texture Formatting Unit)
mali-dp:
- add support for linear tiled formats
sun4i:
- Display Engine 3 support
- H6 DE3 mixer 0 support
- H6 display engine support
- dw-hdmi support
- H6 HDMI phy support
- implicit fence waiting
- BGRX8888 support
meson:
- Overlay plane support
- implicit fence waiting
- HDMI 1.4 4k modes
bridge:
- i2c fixes for sii902x"
* tag 'drm-next-2018-12-14' of git://anongit.freedesktop.org/drm/drm: (1403 commits)
drm/amd/display: Add fast path for cursor plane updates
drm/amdgpu: Enable GPU recovery by default for CI
drm/amd/display: Fix duplicating scaling/underscan connector state
drm/amd/display: Fix unintialized max_bpc state values
Revert "drm/amd/display: Set RMX_ASPECT as default"
drm/amdgpu: Fix stub function name
drm/msm/dpu: Fix clock issue after bind failure
drm/msm/dpu: Clean up dpu_media_info.h static inline functions
drm/msm/dpu: Further cleanups for static inline functions
drm/msm/dpu: Cleanup the debugfs functions
drm/msm/dpu: Remove dpu_irq and unused functions
drm/msm: Make irq_postinstall optional
drm/msm/dpu: Cleanup callers of dpu_hw_blk_init
drm/msm/dpu: Remove unused functions
drm/msm/dpu: Remove dpu_crtc_is_enabled()
drm/msm/dpu: Remove dpu_crtc_get_mixer_height
drm/msm/dpu: Remove dpu_dbg
drm/msm: dpu: Remove crtc_lock
drm/msm: dpu: Remove vblank_requested flag from dpu_crtc
drm/msm: dpu: Separate crtc assignment from vblank enable
...
Diffstat (limited to 'drivers/gpu/drm/msm/msm_drv.c')
-rw-r--r-- | drivers/gpu/drm/msm/msm_drv.c | 173 |
1 files changed, 118 insertions, 55 deletions
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index dcff812c63d0..d2cdc7b553fe 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -23,8 +23,10 @@ #include "msm_drv.h" #include "msm_debugfs.h" #include "msm_fence.h" +#include "msm_gem.h" #include "msm_gpu.h" #include "msm_kms.h" +#include "adreno/adreno_gpu.h" /* @@ -35,9 +37,11 @@ * - 1.3.0 - adds GMEM_BASE + NR_RINGS params, SUBMITQUEUE_NEW + * SUBMITQUEUE_CLOSE ioctls, and MSM_INFO_IOVA flag for * MSM_GEM_INFO ioctl. + * - 1.4.0 - softpin, MSM_RELOC_BO_DUMP, and GEM_INFO support to set/get + * GEM object's debug name */ #define MSM_VERSION_MAJOR 1 -#define MSM_VERSION_MINOR 3 +#define MSM_VERSION_MINOR 4 #define MSM_VERSION_PATCHLEVEL 0 static const struct drm_mode_config_funcs mode_config_funcs = { @@ -170,7 +174,7 @@ void __iomem *msm_ioremap(struct platform_device *pdev, const char *name, res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { - dev_err(&pdev->dev, "failed to get memory resource: %s\n", name); + DRM_DEV_ERROR(&pdev->dev, "failed to get memory resource: %s\n", name); return ERR_PTR(-EINVAL); } @@ -178,7 +182,7 @@ void __iomem *msm_ioremap(struct platform_device *pdev, const char *name, ptr = devm_ioremap_nocache(&pdev->dev, res->start, size); if (!ptr) { - dev_err(&pdev->dev, "failed to ioremap: %s\n", name); + DRM_DEV_ERROR(&pdev->dev, "failed to ioremap: %s\n", name); return ERR_PTR(-ENOMEM); } @@ -312,6 +316,7 @@ static int msm_drm_uninit(struct device *dev) if (fbdev && priv->fbdev) msm_fbdev_free(ddev); #endif + drm_atomic_helper_shutdown(ddev); drm_mode_config_cleanup(ddev); pm_runtime_get_sync(dev); @@ -357,6 +362,14 @@ static int get_mdp_ver(struct platform_device *pdev) #include <linux/of_address.h> +bool msm_use_mmu(struct drm_device *dev) +{ + struct msm_drm_private *priv = dev->dev_private; + + /* a2xx comes with its own MMU */ + return priv->is_a2xx || iommu_present(&platform_bus_type); +} + static int msm_init_vram(struct drm_device *dev) { struct msm_drm_private *priv = dev->dev_private; @@ -395,7 +408,7 @@ static int msm_init_vram(struct drm_device *dev) * Grab the entire CMA chunk carved out in early startup in * mach-msm: */ - } else if (!iommu_present(&platform_bus_type)) { + } else if (!msm_use_mmu(dev)) { DRM_INFO("using %s VRAM carveout\n", vram); size = memparse(vram, NULL); } @@ -418,12 +431,12 @@ static int msm_init_vram(struct drm_device *dev) p = dma_alloc_attrs(dev->dev, size, &priv->vram.paddr, GFP_KERNEL, attrs); if (!p) { - dev_err(dev->dev, "failed to allocate VRAM\n"); + DRM_DEV_ERROR(dev->dev, "failed to allocate VRAM\n"); priv->vram.paddr = 0; return -ENOMEM; } - dev_info(dev->dev, "VRAM: %08x->%08x\n", + DRM_DEV_INFO(dev->dev, "VRAM: %08x->%08x\n", (uint32_t)priv->vram.paddr, (uint32_t)(priv->vram.paddr + size)); } @@ -443,7 +456,7 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) ddev = drm_dev_alloc(drv, dev); if (IS_ERR(ddev)) { - dev_err(dev, "failed to allocate drm_device\n"); + DRM_DEV_ERROR(dev, "failed to allocate drm_device\n"); return PTR_ERR(ddev); } @@ -507,19 +520,16 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) priv->kms = kms; break; default: - kms = ERR_PTR(-ENODEV); + /* valid only for the dummy headless case, where of_node=NULL */ + WARN_ON(dev->of_node); + kms = NULL; break; } if (IS_ERR(kms)) { - /* - * NOTE: once we have GPU support, having no kms should not - * be considered fatal.. ideally we would still support gpu - * and (for example) use dmabuf/prime to share buffers with - * imx drm driver on iMX5 - */ - dev_err(dev, "failed to load kms\n"); + DRM_DEV_ERROR(dev, "failed to load kms\n"); ret = PTR_ERR(kms); + priv->kms = NULL; goto err_msm_uninit; } @@ -529,7 +539,7 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) if (kms) { ret = kms->funcs->hw_init(kms); if (ret) { - dev_err(dev, "kms hw init failed: %d\n", ret); + DRM_DEV_ERROR(dev, "kms hw init failed: %d\n", ret); goto err_msm_uninit; } } @@ -554,7 +564,7 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) &priv->disp_thread[i].worker, "crtc_commit:%d", priv->disp_thread[i].crtc_id); if (IS_ERR(priv->disp_thread[i].thread)) { - dev_err(dev, "failed to create crtc_commit kthread\n"); + DRM_DEV_ERROR(dev, "failed to create crtc_commit kthread\n"); priv->disp_thread[i].thread = NULL; goto err_msm_uninit; } @@ -574,7 +584,7 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) &priv->event_thread[i].worker, "crtc_event:%d", priv->event_thread[i].crtc_id); if (IS_ERR(priv->event_thread[i].thread)) { - dev_err(dev, "failed to create crtc_event kthread\n"); + DRM_DEV_ERROR(dev, "failed to create crtc_event kthread\n"); priv->event_thread[i].thread = NULL; goto err_msm_uninit; } @@ -595,7 +605,7 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) ret = drm_vblank_init(ddev, priv->num_crtcs); if (ret < 0) { - dev_err(dev, "failed to initialize vblank\n"); + DRM_DEV_ERROR(dev, "failed to initialize vblank\n"); goto err_msm_uninit; } @@ -604,7 +614,7 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) ret = drm_irq_install(ddev, kms->irq); pm_runtime_put_sync(dev); if (ret < 0) { - dev_err(dev, "failed to install IRQ handler\n"); + DRM_DEV_ERROR(dev, "failed to install IRQ handler\n"); goto err_msm_uninit; } } @@ -616,7 +626,7 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) drm_mode_config_reset(ddev); #ifdef CONFIG_DRM_FBDEV_EMULATION - if (fbdev) + if (kms && fbdev) priv->fbdev = msm_fbdev_init(ddev); #endif @@ -724,7 +734,11 @@ static int msm_irq_postinstall(struct drm_device *dev) struct msm_drm_private *priv = dev->dev_private; struct msm_kms *kms = priv->kms; BUG_ON(!kms); - return kms->funcs->irq_postinstall(kms); + + if (kms->funcs->irq_postinstall) + return kms->funcs->irq_postinstall(kms); + + return 0; } static void msm_irq_uninstall(struct drm_device *dev) @@ -791,7 +805,7 @@ static int msm_ioctl_gem_new(struct drm_device *dev, void *data, } return msm_gem_new_handle(dev, file, args->size, - args->flags, &args->handle); + args->flags, &args->handle, NULL); } static inline ktime_t to_ktime(struct drm_msm_timespec timeout) @@ -849,6 +863,10 @@ static int msm_ioctl_gem_info_iova(struct drm_device *dev, if (!priv->gpu) return -EINVAL; + /* + * Don't pin the memory here - just get an address so that userspace can + * be productive + */ return msm_gem_get_iova(obj, priv->gpu->aspace, iova); } @@ -857,23 +875,66 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void *data, { struct drm_msm_gem_info *args = data; struct drm_gem_object *obj; - int ret = 0; + struct msm_gem_object *msm_obj; + int i, ret = 0; - if (args->flags & ~MSM_INFO_FLAGS) + if (args->pad) + return -EINVAL; + + switch (args->info) { + case MSM_INFO_GET_OFFSET: + case MSM_INFO_GET_IOVA: + /* value returned as immediate, not pointer, so len==0: */ + if (args->len) + return -EINVAL; + break; + case MSM_INFO_SET_NAME: + case MSM_INFO_GET_NAME: + break; + default: return -EINVAL; + } obj = drm_gem_object_lookup(file, args->handle); if (!obj) return -ENOENT; - if (args->flags & MSM_INFO_IOVA) { - uint64_t iova; + msm_obj = to_msm_bo(obj); - ret = msm_ioctl_gem_info_iova(dev, obj, &iova); - if (!ret) - args->offset = iova; - } else { - args->offset = msm_gem_mmap_offset(obj); + switch (args->info) { + case MSM_INFO_GET_OFFSET: + args->value = msm_gem_mmap_offset(obj); + break; + case MSM_INFO_GET_IOVA: + ret = msm_ioctl_gem_info_iova(dev, obj, &args->value); + break; + case MSM_INFO_SET_NAME: + /* length check should leave room for terminating null: */ + if (args->len >= sizeof(msm_obj->name)) { + ret = -EINVAL; + break; + } + ret = copy_from_user(msm_obj->name, + u64_to_user_ptr(args->value), args->len); + msm_obj->name[args->len] = '\0'; + for (i = 0; i < args->len; i++) { + if (!isprint(msm_obj->name[i])) { + msm_obj->name[i] = '\0'; + break; + } + } + break; + case MSM_INFO_GET_NAME: + if (args->value && (args->len < strlen(msm_obj->name))) { + ret = -EINVAL; + break; + } + args->len = strlen(msm_obj->name); + if (args->value) { + ret = copy_to_user(u64_to_user_ptr(args->value), + msm_obj->name, args->len); + } + break; } drm_gem_object_put_unlocked(obj); @@ -1052,18 +1113,15 @@ static int msm_pm_suspend(struct device *dev) { struct drm_device *ddev = dev_get_drvdata(dev); struct msm_drm_private *priv = ddev->dev_private; - struct msm_kms *kms = priv->kms; - - /* TODO: Use atomic helper suspend/resume */ - if (kms && kms->funcs && kms->funcs->pm_suspend) - return kms->funcs->pm_suspend(dev); - drm_kms_helper_poll_disable(ddev); + if (WARN_ON(priv->pm_state)) + drm_atomic_state_put(priv->pm_state); priv->pm_state = drm_atomic_helper_suspend(ddev); if (IS_ERR(priv->pm_state)) { - drm_kms_helper_poll_enable(ddev); - return PTR_ERR(priv->pm_state); + int ret = PTR_ERR(priv->pm_state); + DRM_ERROR("Failed to suspend dpu, %d\n", ret); + return ret; } return 0; @@ -1073,16 +1131,16 @@ static int msm_pm_resume(struct device *dev) { struct drm_device *ddev = dev_get_drvdata(dev); struct msm_drm_private *priv = ddev->dev_private; - struct msm_kms *kms = priv->kms; + int ret; - /* TODO: Use atomic helper suspend/resume */ - if (kms && kms->funcs && kms->funcs->pm_resume) - return kms->funcs->pm_resume(dev); + if (WARN_ON(!priv->pm_state)) + return -ENOENT; - drm_atomic_helper_resume(ddev, priv->pm_state); - drm_kms_helper_poll_enable(ddev); + ret = drm_atomic_helper_resume(ddev, priv->pm_state); + if (!ret) + priv->pm_state = NULL; - return 0; + return ret; } #endif @@ -1167,7 +1225,7 @@ static int add_components_mdp(struct device *mdp_dev, ret = of_graph_parse_endpoint(ep_node, &ep); if (ret) { - dev_err(mdp_dev, "unable to parse port endpoint\n"); + DRM_DEV_ERROR(mdp_dev, "unable to parse port endpoint\n"); of_node_put(ep_node); return ret; } @@ -1189,8 +1247,10 @@ static int add_components_mdp(struct device *mdp_dev, if (!intf) continue; - drm_of_component_match_add(master_dev, matchptr, compare_of, - intf); + if (of_device_is_available(intf)) + drm_of_component_match_add(master_dev, matchptr, + compare_of, intf); + of_node_put(intf); } @@ -1218,13 +1278,13 @@ static int add_display_components(struct device *dev, of_device_is_compatible(dev->of_node, "qcom,sdm845-mdss")) { ret = of_platform_populate(dev->of_node, NULL, NULL, dev); if (ret) { - dev_err(dev, "failed to populate children devices\n"); + DRM_DEV_ERROR(dev, "failed to populate children devices\n"); return ret; } mdp_dev = device_find_child(dev, NULL, compare_name_mdp); if (!mdp_dev) { - dev_err(dev, "failed to find MDSS MDP node\n"); + DRM_DEV_ERROR(dev, "failed to find MDSS MDP node\n"); of_platform_depopulate(dev); return -ENODEV; } @@ -1254,6 +1314,7 @@ static int add_display_components(struct device *dev, static const struct of_device_id msm_gpu_match[] = { { .compatible = "qcom,adreno" }, { .compatible = "qcom,adreno-3xx" }, + { .compatible = "amd,imageon" }, { .compatible = "qcom,kgsl-3d0" }, { }, }; @@ -1298,9 +1359,11 @@ static int msm_pdev_probe(struct platform_device *pdev) struct component_match *match = NULL; int ret; - ret = add_display_components(&pdev->dev, &match); - if (ret) - return ret; + if (get_mdp_ver(pdev)) { + ret = add_display_components(&pdev->dev, &match); + if (ret) + return ret; + } ret = add_gpu_components(&pdev->dev, &match); if (ret) |