Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2012 Russell King
0004  */
0005 
0006 #include <linux/clk.h>
0007 #include <linux/component.h>
0008 #include <linux/module.h>
0009 #include <linux/of_graph.h>
0010 #include <linux/platform_device.h>
0011 
0012 #include <drm/drm_aperture.h>
0013 #include <drm/drm_atomic_helper.h>
0014 #include <drm/drm_drv.h>
0015 #include <drm/drm_ioctl.h>
0016 #include <drm/drm_managed.h>
0017 #include <drm/drm_prime.h>
0018 #include <drm/drm_probe_helper.h>
0019 #include <drm/drm_fb_helper.h>
0020 #include <drm/drm_of.h>
0021 #include <drm/drm_vblank.h>
0022 
0023 #include "armada_crtc.h"
0024 #include "armada_drm.h"
0025 #include "armada_gem.h"
0026 #include "armada_fb.h"
0027 #include "armada_hw.h"
0028 #include <drm/armada_drm.h>
0029 #include "armada_ioctlP.h"
0030 
0031 static const struct drm_ioctl_desc armada_ioctls[] = {
0032     DRM_IOCTL_DEF_DRV(ARMADA_GEM_CREATE, armada_gem_create_ioctl,0),
0033     DRM_IOCTL_DEF_DRV(ARMADA_GEM_MMAP, armada_gem_mmap_ioctl, 0),
0034     DRM_IOCTL_DEF_DRV(ARMADA_GEM_PWRITE, armada_gem_pwrite_ioctl, 0),
0035 };
0036 
0037 DEFINE_DRM_GEM_FOPS(armada_drm_fops);
0038 
0039 static const struct drm_driver armada_drm_driver = {
0040     .lastclose      = drm_fb_helper_lastclose,
0041     .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
0042     .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
0043     .gem_prime_import   = armada_gem_prime_import,
0044     .dumb_create        = armada_gem_dumb_create,
0045     .major          = 1,
0046     .minor          = 0,
0047     .name           = "armada-drm",
0048     .desc           = "Armada SoC DRM",
0049     .date           = "20120730",
0050     .driver_features    = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
0051     .ioctls         = armada_ioctls,
0052     .num_ioctls = ARRAY_SIZE(armada_ioctls),
0053     .fops           = &armada_drm_fops,
0054 };
0055 
0056 static const struct drm_mode_config_funcs armada_drm_mode_config_funcs = {
0057     .fb_create      = armada_fb_create,
0058     .output_poll_changed    = drm_fb_helper_output_poll_changed,
0059     .atomic_check       = drm_atomic_helper_check,
0060     .atomic_commit      = drm_atomic_helper_commit,
0061 };
0062 
0063 static int armada_drm_bind(struct device *dev)
0064 {
0065     struct armada_private *priv;
0066     struct resource *mem = NULL;
0067     int ret, n;
0068 
0069     for (n = 0; ; n++) {
0070         struct resource *r = platform_get_resource(to_platform_device(dev),
0071                                IORESOURCE_MEM, n);
0072         if (!r)
0073             break;
0074 
0075         /* Resources above 64K are graphics memory */
0076         if (resource_size(r) > SZ_64K)
0077             mem = r;
0078         else
0079             return -EINVAL;
0080     }
0081 
0082     if (!mem)
0083         return -ENXIO;
0084 
0085     if (!devm_request_mem_region(dev, mem->start, resource_size(mem),
0086                      "armada-drm"))
0087         return -EBUSY;
0088 
0089     priv = devm_drm_dev_alloc(dev, &armada_drm_driver,
0090                   struct armada_private, drm);
0091     if (IS_ERR(priv)) {
0092         dev_err(dev, "[" DRM_NAME ":%s] devm_drm_dev_alloc failed: %li\n",
0093             __func__, PTR_ERR(priv));
0094         return PTR_ERR(priv);
0095     }
0096 
0097     /* Remove early framebuffers */
0098     ret = drm_aperture_remove_framebuffers(false, &armada_drm_driver);
0099     if (ret) {
0100         dev_err(dev, "[" DRM_NAME ":%s] can't kick out simple-fb: %d\n",
0101             __func__, ret);
0102         kfree(priv);
0103         return ret;
0104     }
0105 
0106     dev_set_drvdata(dev, &priv->drm);
0107 
0108     /* Mode setting support */
0109     drm_mode_config_init(&priv->drm);
0110     priv->drm.mode_config.min_width = 320;
0111     priv->drm.mode_config.min_height = 200;
0112 
0113     /*
0114      * With vscale enabled, the maximum width is 1920 due to the
0115      * 1920 by 3 lines RAM
0116      */
0117     priv->drm.mode_config.max_width = 1920;
0118     priv->drm.mode_config.max_height = 2048;
0119 
0120     priv->drm.mode_config.preferred_depth = 24;
0121     priv->drm.mode_config.funcs = &armada_drm_mode_config_funcs;
0122     drm_mm_init(&priv->linear, mem->start, resource_size(mem));
0123     mutex_init(&priv->linear_lock);
0124 
0125     ret = component_bind_all(dev, &priv->drm);
0126     if (ret)
0127         goto err_kms;
0128 
0129     ret = drm_vblank_init(&priv->drm, priv->drm.mode_config.num_crtc);
0130     if (ret)
0131         goto err_comp;
0132 
0133     drm_mode_config_reset(&priv->drm);
0134 
0135     ret = armada_fbdev_init(&priv->drm);
0136     if (ret)
0137         goto err_comp;
0138 
0139     drm_kms_helper_poll_init(&priv->drm);
0140 
0141     ret = drm_dev_register(&priv->drm, 0);
0142     if (ret)
0143         goto err_poll;
0144 
0145 #ifdef CONFIG_DEBUG_FS
0146     armada_drm_debugfs_init(priv->drm.primary);
0147 #endif
0148 
0149     return 0;
0150 
0151  err_poll:
0152     drm_kms_helper_poll_fini(&priv->drm);
0153     armada_fbdev_fini(&priv->drm);
0154  err_comp:
0155     component_unbind_all(dev, &priv->drm);
0156  err_kms:
0157     drm_mode_config_cleanup(&priv->drm);
0158     drm_mm_takedown(&priv->linear);
0159     return ret;
0160 }
0161 
0162 static void armada_drm_unbind(struct device *dev)
0163 {
0164     struct drm_device *drm = dev_get_drvdata(dev);
0165     struct armada_private *priv = drm_to_armada_dev(drm);
0166 
0167     drm_kms_helper_poll_fini(&priv->drm);
0168     armada_fbdev_fini(&priv->drm);
0169 
0170     drm_dev_unregister(&priv->drm);
0171 
0172     drm_atomic_helper_shutdown(&priv->drm);
0173 
0174     component_unbind_all(dev, &priv->drm);
0175 
0176     drm_mode_config_cleanup(&priv->drm);
0177     drm_mm_takedown(&priv->linear);
0178 }
0179 
0180 static void armada_add_endpoints(struct device *dev,
0181     struct component_match **match, struct device_node *dev_node)
0182 {
0183     struct device_node *ep, *remote;
0184 
0185     for_each_endpoint_of_node(dev_node, ep) {
0186         remote = of_graph_get_remote_port_parent(ep);
0187         if (remote && of_device_is_available(remote))
0188             drm_of_component_match_add(dev, match, component_compare_of,
0189                            remote);
0190         of_node_put(remote);
0191     }
0192 }
0193 
0194 static const struct component_master_ops armada_master_ops = {
0195     .bind = armada_drm_bind,
0196     .unbind = armada_drm_unbind,
0197 };
0198 
0199 static int armada_drm_probe(struct platform_device *pdev)
0200 {
0201     struct component_match *match = NULL;
0202     struct device *dev = &pdev->dev;
0203     int ret;
0204 
0205     ret = drm_of_component_probe(dev, component_compare_dev_name, &armada_master_ops);
0206     if (ret != -EINVAL)
0207         return ret;
0208 
0209     if (dev->platform_data) {
0210         char **devices = dev->platform_data;
0211         struct device *d;
0212         int i;
0213 
0214         for (i = 0; devices[i]; i++)
0215             component_match_add(dev, &match, component_compare_dev_name,
0216                         devices[i]);
0217 
0218         if (i == 0) {
0219             dev_err(dev, "missing 'ports' property\n");
0220             return -ENODEV;
0221         }
0222 
0223         for (i = 0; devices[i]; i++) {
0224             d = bus_find_device_by_name(&platform_bus_type, NULL,
0225                             devices[i]);
0226             if (d && d->of_node)
0227                 armada_add_endpoints(dev, &match, d->of_node);
0228             put_device(d);
0229         }
0230     }
0231 
0232     return component_master_add_with_match(&pdev->dev, &armada_master_ops,
0233                            match);
0234 }
0235 
0236 static int armada_drm_remove(struct platform_device *pdev)
0237 {
0238     component_master_del(&pdev->dev, &armada_master_ops);
0239     return 0;
0240 }
0241 
0242 static const struct platform_device_id armada_drm_platform_ids[] = {
0243     {
0244         .name       = "armada-drm",
0245     }, {
0246         .name       = "armada-510-drm",
0247     },
0248     { },
0249 };
0250 MODULE_DEVICE_TABLE(platform, armada_drm_platform_ids);
0251 
0252 static struct platform_driver armada_drm_platform_driver = {
0253     .probe  = armada_drm_probe,
0254     .remove = armada_drm_remove,
0255     .driver = {
0256         .name   = "armada-drm",
0257     },
0258     .id_table = armada_drm_platform_ids,
0259 };
0260 
0261 static int __init armada_drm_init(void)
0262 {
0263     int ret;
0264 
0265     if (drm_firmware_drivers_only())
0266         return -ENODEV;
0267 
0268     ret = platform_driver_register(&armada_lcd_platform_driver);
0269     if (ret)
0270         return ret;
0271     ret = platform_driver_register(&armada_drm_platform_driver);
0272     if (ret)
0273         platform_driver_unregister(&armada_lcd_platform_driver);
0274     return ret;
0275 }
0276 module_init(armada_drm_init);
0277 
0278 static void __exit armada_drm_exit(void)
0279 {
0280     platform_driver_unregister(&armada_drm_platform_driver);
0281     platform_driver_unregister(&armada_lcd_platform_driver);
0282 }
0283 module_exit(armada_drm_exit);
0284 
0285 MODULE_AUTHOR("Russell King <rmk+kernel@armlinux.org.uk>");
0286 MODULE_DESCRIPTION("Armada DRM Driver");
0287 MODULE_LICENSE("GPL");
0288 MODULE_ALIAS("platform:armada-drm");