Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.1-rc1 365 lines 9.4 kB view raw
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Freescale i.MX drm driver 4 * 5 * Copyright (C) 2011 Sascha Hauer, Pengutronix 6 */ 7#include <linux/component.h> 8#include <linux/device.h> 9#include <linux/dma-buf.h> 10#include <linux/module.h> 11#include <linux/platform_device.h> 12#include <drm/drmP.h> 13#include <drm/drm_atomic.h> 14#include <drm/drm_atomic_helper.h> 15#include <drm/drm_fb_cma_helper.h> 16#include <drm/drm_fb_helper.h> 17#include <drm/drm_gem_cma_helper.h> 18#include <drm/drm_gem_framebuffer_helper.h> 19#include <drm/drm_of.h> 20#include <drm/drm_plane_helper.h> 21#include <drm/drm_probe_helper.h> 22#include <video/imx-ipu-v3.h> 23 24#include "imx-drm.h" 25#include "ipuv3-plane.h" 26 27#define MAX_CRTC 4 28 29static int legacyfb_depth = 16; 30module_param(legacyfb_depth, int, 0444); 31 32DEFINE_DRM_GEM_CMA_FOPS(imx_drm_driver_fops); 33 34void imx_drm_connector_destroy(struct drm_connector *connector) 35{ 36 drm_connector_unregister(connector); 37 drm_connector_cleanup(connector); 38} 39EXPORT_SYMBOL_GPL(imx_drm_connector_destroy); 40 41void imx_drm_encoder_destroy(struct drm_encoder *encoder) 42{ 43 drm_encoder_cleanup(encoder); 44} 45EXPORT_SYMBOL_GPL(imx_drm_encoder_destroy); 46 47static int imx_drm_atomic_check(struct drm_device *dev, 48 struct drm_atomic_state *state) 49{ 50 int ret; 51 52 ret = drm_atomic_helper_check(dev, state); 53 if (ret) 54 return ret; 55 56 /* 57 * Check modeset again in case crtc_state->mode_changed is 58 * updated in plane's ->atomic_check callback. 59 */ 60 ret = drm_atomic_helper_check_modeset(dev, state); 61 if (ret) 62 return ret; 63 64 /* Assign PRG/PRE channels and check if all constrains are satisfied. */ 65 ret = ipu_planes_assign_pre(dev, state); 66 if (ret) 67 return ret; 68 69 return ret; 70} 71 72static const struct drm_mode_config_funcs imx_drm_mode_config_funcs = { 73 .fb_create = drm_gem_fb_create, 74 .atomic_check = imx_drm_atomic_check, 75 .atomic_commit = drm_atomic_helper_commit, 76}; 77 78static void imx_drm_atomic_commit_tail(struct drm_atomic_state *state) 79{ 80 struct drm_device *dev = state->dev; 81 struct drm_plane *plane; 82 struct drm_plane_state *old_plane_state, *new_plane_state; 83 bool plane_disabling = false; 84 int i; 85 86 drm_atomic_helper_commit_modeset_disables(dev, state); 87 88 drm_atomic_helper_commit_planes(dev, state, 89 DRM_PLANE_COMMIT_ACTIVE_ONLY | 90 DRM_PLANE_COMMIT_NO_DISABLE_AFTER_MODESET); 91 92 drm_atomic_helper_commit_modeset_enables(dev, state); 93 94 for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) { 95 if (drm_atomic_plane_disabling(old_plane_state, new_plane_state)) 96 plane_disabling = true; 97 } 98 99 /* 100 * The flip done wait is only strictly required by imx-drm if a deferred 101 * plane disable is in-flight. As the core requires blocking commits 102 * to wait for the flip it is done here unconditionally. This keeps the 103 * workitem around a bit longer than required for the majority of 104 * non-blocking commits, but we accept that for the sake of simplicity. 105 */ 106 drm_atomic_helper_wait_for_flip_done(dev, state); 107 108 if (plane_disabling) { 109 for_each_old_plane_in_state(state, plane, old_plane_state, i) 110 ipu_plane_disable_deferred(plane); 111 112 } 113 114 drm_atomic_helper_commit_hw_done(state); 115} 116 117static const struct drm_mode_config_helper_funcs imx_drm_mode_config_helpers = { 118 .atomic_commit_tail = imx_drm_atomic_commit_tail, 119}; 120 121 122int imx_drm_encoder_parse_of(struct drm_device *drm, 123 struct drm_encoder *encoder, struct device_node *np) 124{ 125 uint32_t crtc_mask = drm_of_find_possible_crtcs(drm, np); 126 127 /* 128 * If we failed to find the CRTC(s) which this encoder is 129 * supposed to be connected to, it's because the CRTC has 130 * not been registered yet. Defer probing, and hope that 131 * the required CRTC is added later. 132 */ 133 if (crtc_mask == 0) 134 return -EPROBE_DEFER; 135 136 encoder->possible_crtcs = crtc_mask; 137 138 /* FIXME: this is the mask of outputs which can clone this output. */ 139 encoder->possible_clones = ~0; 140 141 return 0; 142} 143EXPORT_SYMBOL_GPL(imx_drm_encoder_parse_of); 144 145static const struct drm_ioctl_desc imx_drm_ioctls[] = { 146 /* none so far */ 147}; 148 149static struct drm_driver imx_drm_driver = { 150 .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | 151 DRIVER_ATOMIC, 152 .gem_free_object_unlocked = drm_gem_cma_free_object, 153 .gem_vm_ops = &drm_gem_cma_vm_ops, 154 .dumb_create = drm_gem_cma_dumb_create, 155 156 .prime_handle_to_fd = drm_gem_prime_handle_to_fd, 157 .prime_fd_to_handle = drm_gem_prime_fd_to_handle, 158 .gem_prime_import = drm_gem_prime_import, 159 .gem_prime_export = drm_gem_prime_export, 160 .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, 161 .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, 162 .gem_prime_vmap = drm_gem_cma_prime_vmap, 163 .gem_prime_vunmap = drm_gem_cma_prime_vunmap, 164 .gem_prime_mmap = drm_gem_cma_prime_mmap, 165 .ioctls = imx_drm_ioctls, 166 .num_ioctls = ARRAY_SIZE(imx_drm_ioctls), 167 .fops = &imx_drm_driver_fops, 168 .name = "imx-drm", 169 .desc = "i.MX DRM graphics", 170 .date = "20120507", 171 .major = 1, 172 .minor = 0, 173 .patchlevel = 0, 174}; 175 176static int compare_of(struct device *dev, void *data) 177{ 178 struct device_node *np = data; 179 180 /* Special case for DI, dev->of_node may not be set yet */ 181 if (strcmp(dev->driver->name, "imx-ipuv3-crtc") == 0) { 182 struct ipu_client_platformdata *pdata = dev->platform_data; 183 184 return pdata->of_node == np; 185 } 186 187 /* Special case for LDB, one device for two channels */ 188 if (of_node_cmp(np->name, "lvds-channel") == 0) { 189 np = of_get_parent(np); 190 of_node_put(np); 191 } 192 193 return dev->of_node == np; 194} 195 196static int imx_drm_bind(struct device *dev) 197{ 198 struct drm_device *drm; 199 int ret; 200 201 drm = drm_dev_alloc(&imx_drm_driver, dev); 202 if (IS_ERR(drm)) 203 return PTR_ERR(drm); 204 205 /* 206 * enable drm irq mode. 207 * - with irq_enabled = true, we can use the vblank feature. 208 * 209 * P.S. note that we wouldn't use drm irq handler but 210 * just specific driver own one instead because 211 * drm framework supports only one irq handler and 212 * drivers can well take care of their interrupts 213 */ 214 drm->irq_enabled = true; 215 216 /* 217 * set max width and height as default value(4096x4096). 218 * this value would be used to check framebuffer size limitation 219 * at drm_mode_addfb(). 220 */ 221 drm->mode_config.min_width = 1; 222 drm->mode_config.min_height = 1; 223 drm->mode_config.max_width = 4096; 224 drm->mode_config.max_height = 4096; 225 drm->mode_config.funcs = &imx_drm_mode_config_funcs; 226 drm->mode_config.helper_private = &imx_drm_mode_config_helpers; 227 drm->mode_config.allow_fb_modifiers = true; 228 drm->mode_config.normalize_zpos = true; 229 230 drm_mode_config_init(drm); 231 232 ret = drm_vblank_init(drm, MAX_CRTC); 233 if (ret) 234 goto err_kms; 235 236 dev_set_drvdata(dev, drm); 237 238 /* Now try and bind all our sub-components */ 239 ret = component_bind_all(dev, drm); 240 if (ret) 241 goto err_kms; 242 243 drm_mode_config_reset(drm); 244 245 /* 246 * All components are now initialised, so setup the fb helper. 247 * The fb helper takes copies of key hardware information, so the 248 * crtcs/connectors/encoders must not change after this point. 249 */ 250 if (legacyfb_depth != 16 && legacyfb_depth != 32) { 251 dev_warn(dev, "Invalid legacyfb_depth. Defaulting to 16bpp\n"); 252 legacyfb_depth = 16; 253 } 254 255 drm_kms_helper_poll_init(drm); 256 257 ret = drm_dev_register(drm, 0); 258 if (ret) 259 goto err_poll_fini; 260 261 drm_fbdev_generic_setup(drm, legacyfb_depth); 262 263 return 0; 264 265err_poll_fini: 266 drm_kms_helper_poll_fini(drm); 267 component_unbind_all(drm->dev, drm); 268err_kms: 269 drm_mode_config_cleanup(drm); 270 drm_dev_put(drm); 271 272 return ret; 273} 274 275static void imx_drm_unbind(struct device *dev) 276{ 277 struct drm_device *drm = dev_get_drvdata(dev); 278 279 drm_dev_unregister(drm); 280 281 drm_kms_helper_poll_fini(drm); 282 283 drm_mode_config_cleanup(drm); 284 285 component_unbind_all(drm->dev, drm); 286 dev_set_drvdata(dev, NULL); 287 288 drm_dev_put(drm); 289} 290 291static const struct component_master_ops imx_drm_ops = { 292 .bind = imx_drm_bind, 293 .unbind = imx_drm_unbind, 294}; 295 296static int imx_drm_platform_probe(struct platform_device *pdev) 297{ 298 int ret = drm_of_component_probe(&pdev->dev, compare_of, &imx_drm_ops); 299 300 if (!ret) 301 ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); 302 303 return ret; 304} 305 306static int imx_drm_platform_remove(struct platform_device *pdev) 307{ 308 component_master_del(&pdev->dev, &imx_drm_ops); 309 return 0; 310} 311 312#ifdef CONFIG_PM_SLEEP 313static int imx_drm_suspend(struct device *dev) 314{ 315 struct drm_device *drm_dev = dev_get_drvdata(dev); 316 317 return drm_mode_config_helper_suspend(drm_dev); 318} 319 320static int imx_drm_resume(struct device *dev) 321{ 322 struct drm_device *drm_dev = dev_get_drvdata(dev); 323 324 return drm_mode_config_helper_resume(drm_dev); 325} 326#endif 327 328static SIMPLE_DEV_PM_OPS(imx_drm_pm_ops, imx_drm_suspend, imx_drm_resume); 329 330static const struct of_device_id imx_drm_dt_ids[] = { 331 { .compatible = "fsl,imx-display-subsystem", }, 332 { /* sentinel */ }, 333}; 334MODULE_DEVICE_TABLE(of, imx_drm_dt_ids); 335 336static struct platform_driver imx_drm_pdrv = { 337 .probe = imx_drm_platform_probe, 338 .remove = imx_drm_platform_remove, 339 .driver = { 340 .name = "imx-drm", 341 .pm = &imx_drm_pm_ops, 342 .of_match_table = imx_drm_dt_ids, 343 }, 344}; 345 346static struct platform_driver * const drivers[] = { 347 &imx_drm_pdrv, 348 &ipu_drm_driver, 349}; 350 351static int __init imx_drm_init(void) 352{ 353 return platform_register_drivers(drivers, ARRAY_SIZE(drivers)); 354} 355module_init(imx_drm_init); 356 357static void __exit imx_drm_exit(void) 358{ 359 platform_unregister_drivers(drivers, ARRAY_SIZE(drivers)); 360} 361module_exit(imx_drm_exit); 362 363MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); 364MODULE_DESCRIPTION("i.MX drm driver core"); 365MODULE_LICENSE("GPL");