0001
0002
0003
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
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
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
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
0115
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");