diff options
Diffstat (limited to 'drivers/gpu/drm/msm/msm_drv.c')
-rw-r--r-- | drivers/gpu/drm/msm/msm_drv.c | 171 |
1 files changed, 117 insertions, 54 deletions
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 5e758d95751a..6265be8f4119 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); } @@ -358,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; @@ -396,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); } @@ -419,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)); } @@ -444,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); } @@ -508,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; } @@ -530,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; } } @@ -561,7 +570,7 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) ret); 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; } @@ -573,6 +582,7 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) kthread_run(kthread_worker_fn, &priv->event_thread[i].worker, "crtc_event:%d", priv->event_thread[i].crtc_id); + /** * event thread should also run at same priority as disp_thread * because it is handling frame_done events. A lower priority @@ -613,7 +623,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; } @@ -622,7 +632,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; } } @@ -634,7 +644,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 @@ -742,7 +752,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) @@ -809,7 +823,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) @@ -867,6 +881,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); } @@ -875,23 +893,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); @@ -1070,18 +1131,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; @@ -1091,16 +1149,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 @@ -1185,7 +1243,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; } @@ -1207,8 +1265,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); } @@ -1236,13 +1296,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; } @@ -1272,6 +1332,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" }, { }, }; @@ -1316,9 +1377,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) |