| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (c) 2011 Samsung Electronics Co., Ltd. |
|---|
| 3 | 4 | * Authors: |
|---|
| 4 | 5 | * Inki Dae <inki.dae@samsung.com> |
|---|
| 5 | 6 | * Joonyoung Shim <jy0922.shim@samsung.com> |
|---|
| 6 | 7 | * Seung-Woo Kim <sw0312.kim@samsung.com> |
|---|
| 7 | | - * |
|---|
| 8 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 9 | | - * under the terms of the GNU General Public License as published by the |
|---|
| 10 | | - * Free Software Foundation; either version 2 of the License, or (at your |
|---|
| 11 | | - * option) any later version. |
|---|
| 12 | 8 | */ |
|---|
| 13 | 9 | |
|---|
| 10 | +#include <linux/component.h> |
|---|
| 11 | +#include <linux/dma-mapping.h> |
|---|
| 12 | +#include <linux/platform_device.h> |
|---|
| 14 | 13 | #include <linux/pm_runtime.h> |
|---|
| 15 | | -#include <drm/drmP.h> |
|---|
| 14 | +#include <linux/uaccess.h> |
|---|
| 15 | + |
|---|
| 16 | 16 | #include <drm/drm_atomic.h> |
|---|
| 17 | 17 | #include <drm/drm_atomic_helper.h> |
|---|
| 18 | | -#include <drm/drm_crtc_helper.h> |
|---|
| 18 | +#include <drm/drm_drv.h> |
|---|
| 19 | 19 | #include <drm/drm_fb_helper.h> |
|---|
| 20 | | - |
|---|
| 21 | | -#include <linux/component.h> |
|---|
| 22 | | - |
|---|
| 20 | +#include <drm/drm_file.h> |
|---|
| 21 | +#include <drm/drm_fourcc.h> |
|---|
| 22 | +#include <drm/drm_ioctl.h> |
|---|
| 23 | +#include <drm/drm_probe_helper.h> |
|---|
| 24 | +#include <drm/drm_vblank.h> |
|---|
| 23 | 25 | #include <drm/exynos_drm.h> |
|---|
| 24 | 26 | |
|---|
| 25 | 27 | #include "exynos_drm_drv.h" |
|---|
| 26 | | -#include "exynos_drm_fbdev.h" |
|---|
| 27 | 28 | #include "exynos_drm_fb.h" |
|---|
| 28 | | -#include "exynos_drm_gem.h" |
|---|
| 29 | | -#include "exynos_drm_plane.h" |
|---|
| 30 | | -#include "exynos_drm_ipp.h" |
|---|
| 31 | | -#include "exynos_drm_vidi.h" |
|---|
| 29 | +#include "exynos_drm_fbdev.h" |
|---|
| 32 | 30 | #include "exynos_drm_g2d.h" |
|---|
| 33 | | -#include "exynos_drm_iommu.h" |
|---|
| 31 | +#include "exynos_drm_gem.h" |
|---|
| 32 | +#include "exynos_drm_ipp.h" |
|---|
| 33 | +#include "exynos_drm_plane.h" |
|---|
| 34 | +#include "exynos_drm_vidi.h" |
|---|
| 34 | 35 | |
|---|
| 35 | 36 | #define DRIVER_NAME "exynos" |
|---|
| 36 | 37 | #define DRIVER_DESC "Samsung SoC DRM" |
|---|
| .. | .. |
|---|
| 75 | 76 | } |
|---|
| 76 | 77 | |
|---|
| 77 | 78 | static const struct vm_operations_struct exynos_drm_gem_vm_ops = { |
|---|
| 78 | | - .fault = exynos_drm_gem_fault, |
|---|
| 79 | 79 | .open = drm_gem_vm_open, |
|---|
| 80 | 80 | .close = drm_gem_vm_close, |
|---|
| 81 | 81 | }; |
|---|
| 82 | 82 | |
|---|
| 83 | 83 | static const struct drm_ioctl_desc exynos_ioctls[] = { |
|---|
| 84 | 84 | DRM_IOCTL_DEF_DRV(EXYNOS_GEM_CREATE, exynos_drm_gem_create_ioctl, |
|---|
| 85 | | - DRM_AUTH | DRM_RENDER_ALLOW), |
|---|
| 85 | + DRM_RENDER_ALLOW), |
|---|
| 86 | 86 | DRM_IOCTL_DEF_DRV(EXYNOS_GEM_MAP, exynos_drm_gem_map_ioctl, |
|---|
| 87 | | - DRM_AUTH | DRM_RENDER_ALLOW), |
|---|
| 87 | + DRM_RENDER_ALLOW), |
|---|
| 88 | 88 | DRM_IOCTL_DEF_DRV(EXYNOS_GEM_GET, exynos_drm_gem_get_ioctl, |
|---|
| 89 | 89 | DRM_RENDER_ALLOW), |
|---|
| 90 | 90 | DRM_IOCTL_DEF_DRV(EXYNOS_VIDI_CONNECTION, vidi_connection_ioctl, |
|---|
| 91 | 91 | DRM_AUTH), |
|---|
| 92 | 92 | DRM_IOCTL_DEF_DRV(EXYNOS_G2D_GET_VER, exynos_g2d_get_ver_ioctl, |
|---|
| 93 | | - DRM_AUTH | DRM_RENDER_ALLOW), |
|---|
| 93 | + DRM_RENDER_ALLOW), |
|---|
| 94 | 94 | DRM_IOCTL_DEF_DRV(EXYNOS_G2D_SET_CMDLIST, exynos_g2d_set_cmdlist_ioctl, |
|---|
| 95 | | - DRM_AUTH | DRM_RENDER_ALLOW), |
|---|
| 95 | + DRM_RENDER_ALLOW), |
|---|
| 96 | 96 | DRM_IOCTL_DEF_DRV(EXYNOS_G2D_EXEC, exynos_g2d_exec_ioctl, |
|---|
| 97 | | - DRM_AUTH | DRM_RENDER_ALLOW), |
|---|
| 97 | + DRM_RENDER_ALLOW), |
|---|
| 98 | 98 | DRM_IOCTL_DEF_DRV(EXYNOS_IPP_GET_RESOURCES, |
|---|
| 99 | 99 | exynos_drm_ipp_get_res_ioctl, |
|---|
| 100 | | - DRM_AUTH | DRM_RENDER_ALLOW), |
|---|
| 100 | + DRM_RENDER_ALLOW), |
|---|
| 101 | 101 | DRM_IOCTL_DEF_DRV(EXYNOS_IPP_GET_CAPS, exynos_drm_ipp_get_caps_ioctl, |
|---|
| 102 | | - DRM_AUTH | DRM_RENDER_ALLOW), |
|---|
| 102 | + DRM_RENDER_ALLOW), |
|---|
| 103 | 103 | DRM_IOCTL_DEF_DRV(EXYNOS_IPP_GET_LIMITS, |
|---|
| 104 | 104 | exynos_drm_ipp_get_limits_ioctl, |
|---|
| 105 | | - DRM_AUTH | DRM_RENDER_ALLOW), |
|---|
| 105 | + DRM_RENDER_ALLOW), |
|---|
| 106 | 106 | DRM_IOCTL_DEF_DRV(EXYNOS_IPP_COMMIT, exynos_drm_ipp_commit_ioctl, |
|---|
| 107 | | - DRM_AUTH | DRM_RENDER_ALLOW), |
|---|
| 107 | + DRM_RENDER_ALLOW), |
|---|
| 108 | 108 | }; |
|---|
| 109 | 109 | |
|---|
| 110 | 110 | static const struct file_operations exynos_drm_driver_fops = { |
|---|
| .. | .. |
|---|
| 119 | 119 | }; |
|---|
| 120 | 120 | |
|---|
| 121 | 121 | static struct drm_driver exynos_drm_driver = { |
|---|
| 122 | | - .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME |
|---|
| 122 | + .driver_features = DRIVER_MODESET | DRIVER_GEM |
|---|
| 123 | 123 | | DRIVER_ATOMIC | DRIVER_RENDER, |
|---|
| 124 | 124 | .open = exynos_drm_open, |
|---|
| 125 | 125 | .lastclose = drm_fb_helper_lastclose, |
|---|
| .. | .. |
|---|
| 129 | 129 | .dumb_create = exynos_drm_gem_dumb_create, |
|---|
| 130 | 130 | .prime_handle_to_fd = drm_gem_prime_handle_to_fd, |
|---|
| 131 | 131 | .prime_fd_to_handle = drm_gem_prime_fd_to_handle, |
|---|
| 132 | | - .gem_prime_export = drm_gem_prime_export, |
|---|
| 133 | 132 | .gem_prime_import = exynos_drm_gem_prime_import, |
|---|
| 134 | 133 | .gem_prime_get_sg_table = exynos_drm_gem_prime_get_sg_table, |
|---|
| 135 | 134 | .gem_prime_import_sg_table = exynos_drm_gem_prime_import_sg_table, |
|---|
| .. | .. |
|---|
| 149 | 148 | static int exynos_drm_suspend(struct device *dev) |
|---|
| 150 | 149 | { |
|---|
| 151 | 150 | struct drm_device *drm_dev = dev_get_drvdata(dev); |
|---|
| 152 | | - struct exynos_drm_private *private; |
|---|
| 153 | 151 | |
|---|
| 154 | | - if (!drm_dev) |
|---|
| 155 | | - return 0; |
|---|
| 156 | | - |
|---|
| 157 | | - private = drm_dev->dev_private; |
|---|
| 158 | | - |
|---|
| 159 | | - drm_kms_helper_poll_disable(drm_dev); |
|---|
| 160 | | - exynos_drm_fbdev_suspend(drm_dev); |
|---|
| 161 | | - private->suspend_state = drm_atomic_helper_suspend(drm_dev); |
|---|
| 162 | | - if (IS_ERR(private->suspend_state)) { |
|---|
| 163 | | - exynos_drm_fbdev_resume(drm_dev); |
|---|
| 164 | | - drm_kms_helper_poll_enable(drm_dev); |
|---|
| 165 | | - return PTR_ERR(private->suspend_state); |
|---|
| 166 | | - } |
|---|
| 167 | | - |
|---|
| 168 | | - return 0; |
|---|
| 152 | + return drm_mode_config_helper_suspend(drm_dev); |
|---|
| 169 | 153 | } |
|---|
| 170 | 154 | |
|---|
| 171 | 155 | static void exynos_drm_resume(struct device *dev) |
|---|
| 172 | 156 | { |
|---|
| 173 | 157 | struct drm_device *drm_dev = dev_get_drvdata(dev); |
|---|
| 174 | | - struct exynos_drm_private *private; |
|---|
| 175 | 158 | |
|---|
| 176 | | - if (!drm_dev) |
|---|
| 177 | | - return; |
|---|
| 178 | | - |
|---|
| 179 | | - private = drm_dev->dev_private; |
|---|
| 180 | | - drm_atomic_helper_resume(drm_dev, private->suspend_state); |
|---|
| 181 | | - exynos_drm_fbdev_resume(drm_dev); |
|---|
| 182 | | - drm_kms_helper_poll_enable(drm_dev); |
|---|
| 159 | + drm_mode_config_helper_resume(drm_dev); |
|---|
| 183 | 160 | } |
|---|
| 184 | 161 | |
|---|
| 185 | 162 | static const struct dev_pm_ops exynos_drm_pm_ops = { |
|---|
| .. | .. |
|---|
| 197 | 174 | |
|---|
| 198 | 175 | #define DRM_COMPONENT_DRIVER BIT(0) /* supports component framework */ |
|---|
| 199 | 176 | #define DRM_VIRTUAL_DEVICE BIT(1) /* create virtual platform device */ |
|---|
| 200 | | -#define DRM_DMA_DEVICE BIT(2) /* can be used for dma allocations */ |
|---|
| 201 | | -#define DRM_FIMC_DEVICE BIT(3) /* devices shared with V4L2 subsystem */ |
|---|
| 177 | +#define DRM_FIMC_DEVICE BIT(2) /* devices shared with V4L2 subsystem */ |
|---|
| 202 | 178 | |
|---|
| 203 | 179 | #define DRV_PTR(drv, cond) (IS_ENABLED(cond) ? &drv : NULL) |
|---|
| 204 | 180 | |
|---|
| .. | .. |
|---|
| 209 | 185 | static struct exynos_drm_driver_info exynos_drm_drivers[] = { |
|---|
| 210 | 186 | { |
|---|
| 211 | 187 | DRV_PTR(fimd_driver, CONFIG_DRM_EXYNOS_FIMD), |
|---|
| 212 | | - DRM_COMPONENT_DRIVER | DRM_DMA_DEVICE |
|---|
| 188 | + DRM_COMPONENT_DRIVER |
|---|
| 213 | 189 | }, { |
|---|
| 214 | 190 | DRV_PTR(exynos5433_decon_driver, CONFIG_DRM_EXYNOS5433_DECON), |
|---|
| 215 | | - DRM_COMPONENT_DRIVER | DRM_DMA_DEVICE |
|---|
| 191 | + DRM_COMPONENT_DRIVER |
|---|
| 216 | 192 | }, { |
|---|
| 217 | 193 | DRV_PTR(decon_driver, CONFIG_DRM_EXYNOS7_DECON), |
|---|
| 218 | | - DRM_COMPONENT_DRIVER | DRM_DMA_DEVICE |
|---|
| 194 | + DRM_COMPONENT_DRIVER |
|---|
| 219 | 195 | }, { |
|---|
| 220 | 196 | DRV_PTR(mixer_driver, CONFIG_DRM_EXYNOS_MIXER), |
|---|
| 221 | | - DRM_COMPONENT_DRIVER | DRM_DMA_DEVICE |
|---|
| 197 | + DRM_COMPONENT_DRIVER |
|---|
| 222 | 198 | }, { |
|---|
| 223 | 199 | DRV_PTR(mic_driver, CONFIG_DRM_EXYNOS_MIC), |
|---|
| 224 | 200 | DRM_COMPONENT_DRIVER |
|---|
| .. | .. |
|---|
| 272 | 248 | if (!info->driver || !(info->flags & DRM_COMPONENT_DRIVER)) |
|---|
| 273 | 249 | continue; |
|---|
| 274 | 250 | |
|---|
| 275 | | - while ((d = bus_find_device(&platform_bus_type, p, |
|---|
| 276 | | - &info->driver->driver, |
|---|
| 277 | | - (void *)platform_bus_type.match))) { |
|---|
| 251 | + while ((d = platform_find_device_by_driver(p, &info->driver->driver))) { |
|---|
| 278 | 252 | put_device(p); |
|---|
| 279 | 253 | |
|---|
| 280 | 254 | if (!(info->flags & DRM_FIMC_DEVICE) || |
|---|
| .. | .. |
|---|
| 289 | 263 | return match ?: ERR_PTR(-ENODEV); |
|---|
| 290 | 264 | } |
|---|
| 291 | 265 | |
|---|
| 292 | | -static struct device *exynos_drm_get_dma_device(void) |
|---|
| 293 | | -{ |
|---|
| 294 | | - int i; |
|---|
| 295 | | - |
|---|
| 296 | | - for (i = 0; i < ARRAY_SIZE(exynos_drm_drivers); ++i) { |
|---|
| 297 | | - struct exynos_drm_driver_info *info = &exynos_drm_drivers[i]; |
|---|
| 298 | | - struct device *dev; |
|---|
| 299 | | - |
|---|
| 300 | | - if (!info->driver || !(info->flags & DRM_DMA_DEVICE)) |
|---|
| 301 | | - continue; |
|---|
| 302 | | - |
|---|
| 303 | | - while ((dev = bus_find_device(&platform_bus_type, NULL, |
|---|
| 304 | | - &info->driver->driver, |
|---|
| 305 | | - (void *)platform_bus_type.match))) { |
|---|
| 306 | | - put_device(dev); |
|---|
| 307 | | - return dev; |
|---|
| 308 | | - } |
|---|
| 309 | | - } |
|---|
| 310 | | - return NULL; |
|---|
| 311 | | -} |
|---|
| 312 | | - |
|---|
| 313 | 266 | static int exynos_drm_bind(struct device *dev) |
|---|
| 314 | 267 | { |
|---|
| 315 | 268 | struct exynos_drm_private *private; |
|---|
| 316 | 269 | struct drm_encoder *encoder; |
|---|
| 317 | 270 | struct drm_device *drm; |
|---|
| 318 | 271 | unsigned int clone_mask; |
|---|
| 319 | | - int cnt, ret; |
|---|
| 272 | + int ret; |
|---|
| 320 | 273 | |
|---|
| 321 | 274 | drm = drm_dev_alloc(&exynos_drm_driver, dev); |
|---|
| 322 | 275 | if (IS_ERR(drm)) |
|---|
| .. | .. |
|---|
| 334 | 287 | dev_set_drvdata(dev, drm); |
|---|
| 335 | 288 | drm->dev_private = (void *)private; |
|---|
| 336 | 289 | |
|---|
| 337 | | - /* the first real CRTC device is used for all dma mapping operations */ |
|---|
| 338 | | - private->dma_dev = exynos_drm_get_dma_device(); |
|---|
| 339 | | - if (!private->dma_dev) { |
|---|
| 340 | | - DRM_ERROR("no device found for DMA mapping operations.\n"); |
|---|
| 341 | | - ret = -ENODEV; |
|---|
| 342 | | - goto err_free_private; |
|---|
| 343 | | - } |
|---|
| 344 | | - DRM_INFO("Exynos DRM: using %s device for DMA mapping operations\n", |
|---|
| 345 | | - dev_name(private->dma_dev)); |
|---|
| 346 | | - |
|---|
| 347 | | - /* create common IOMMU mapping for all devices attached to Exynos DRM */ |
|---|
| 348 | | - ret = drm_create_iommu_mapping(drm); |
|---|
| 349 | | - if (ret < 0) { |
|---|
| 350 | | - DRM_ERROR("failed to create iommu mapping.\n"); |
|---|
| 351 | | - goto err_free_private; |
|---|
| 352 | | - } |
|---|
| 353 | | - |
|---|
| 354 | 290 | drm_mode_config_init(drm); |
|---|
| 355 | 291 | |
|---|
| 356 | 292 | exynos_drm_mode_config_init(drm); |
|---|
| 357 | 293 | |
|---|
| 358 | 294 | /* setup possible_clones. */ |
|---|
| 359 | | - cnt = 0; |
|---|
| 360 | 295 | clone_mask = 0; |
|---|
| 361 | 296 | list_for_each_entry(encoder, &drm->mode_config.encoder_list, head) |
|---|
| 362 | | - clone_mask |= (1 << (cnt++)); |
|---|
| 297 | + clone_mask |= drm_encoder_mask(encoder); |
|---|
| 363 | 298 | |
|---|
| 364 | 299 | list_for_each_entry(encoder, &drm->mode_config.encoder_list, head) |
|---|
| 365 | 300 | encoder->possible_clones = clone_mask; |
|---|
| .. | .. |
|---|
| 407 | 342 | component_unbind_all(drm->dev, drm); |
|---|
| 408 | 343 | err_mode_config_cleanup: |
|---|
| 409 | 344 | drm_mode_config_cleanup(drm); |
|---|
| 410 | | - drm_release_iommu_mapping(drm); |
|---|
| 411 | | -err_free_private: |
|---|
| 345 | + exynos_drm_cleanup_dma(drm); |
|---|
| 412 | 346 | kfree(private); |
|---|
| 413 | 347 | err_free_drm: |
|---|
| 414 | 348 | drm_dev_put(drm); |
|---|
| .. | .. |
|---|
| 427 | 361 | |
|---|
| 428 | 362 | component_unbind_all(drm->dev, drm); |
|---|
| 429 | 363 | drm_mode_config_cleanup(drm); |
|---|
| 430 | | - drm_release_iommu_mapping(drm); |
|---|
| 364 | + exynos_drm_cleanup_dma(drm); |
|---|
| 431 | 365 | |
|---|
| 432 | 366 | kfree(drm->dev_private); |
|---|
| 433 | 367 | drm->dev_private = NULL; |
|---|
| .. | .. |
|---|
| 481 | 415 | if (!info->driver || !(info->flags & DRM_VIRTUAL_DEVICE)) |
|---|
| 482 | 416 | continue; |
|---|
| 483 | 417 | |
|---|
| 484 | | - while ((dev = bus_find_device(&platform_bus_type, NULL, |
|---|
| 485 | | - &info->driver->driver, |
|---|
| 486 | | - (void *)platform_bus_type.match))) { |
|---|
| 418 | + while ((dev = platform_find_device_by_driver(NULL, |
|---|
| 419 | + &info->driver->driver))) { |
|---|
| 487 | 420 | put_device(dev); |
|---|
| 488 | 421 | platform_device_unregister(to_platform_device(dev)); |
|---|
| 489 | 422 | } |
|---|