brintos

brintos / linux-shallow public Read only

0
0
Text · 6.8 KiB · e51ecc4 Raw
287 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2012 Russell King4 */5 6#include <linux/clk.h>7#include <linux/component.h>8#include <linux/module.h>9#include <linux/of.h>10#include <linux/of_graph.h>11#include <linux/platform_device.h>12 13#include <drm/drm_aperture.h>14#include <drm/drm_atomic_helper.h>15#include <drm/drm_drv.h>16#include <drm/drm_ioctl.h>17#include <drm/drm_managed.h>18#include <drm/drm_prime.h>19#include <drm/drm_probe_helper.h>20#include <drm/drm_of.h>21#include <drm/drm_vblank.h>22 23#include "armada_crtc.h"24#include "armada_drm.h"25#include "armada_gem.h"26#include "armada_fb.h"27#include "armada_hw.h"28#include <drm/armada_drm.h>29#include "armada_ioctlP.h"30 31static const struct drm_ioctl_desc armada_ioctls[] = {32	DRM_IOCTL_DEF_DRV(ARMADA_GEM_CREATE, armada_gem_create_ioctl,0),33	DRM_IOCTL_DEF_DRV(ARMADA_GEM_MMAP, armada_gem_mmap_ioctl, 0),34	DRM_IOCTL_DEF_DRV(ARMADA_GEM_PWRITE, armada_gem_pwrite_ioctl, 0),35};36 37DEFINE_DRM_GEM_FOPS(armada_drm_fops);38 39static const struct drm_driver armada_drm_driver = {40	.gem_prime_import	= armada_gem_prime_import,41	.dumb_create		= armada_gem_dumb_create,42	.major			= 1,43	.minor			= 0,44	.name			= "armada-drm",45	.desc			= "Armada SoC DRM",46	.date			= "20120730",47	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,48	.ioctls			= armada_ioctls,49	.num_ioctls = ARRAY_SIZE(armada_ioctls),50	.fops			= &armada_drm_fops,51};52 53static const struct drm_mode_config_funcs armada_drm_mode_config_funcs = {54	.fb_create		= armada_fb_create,55	.atomic_check		= drm_atomic_helper_check,56	.atomic_commit		= drm_atomic_helper_commit,57};58 59static int armada_drm_bind(struct device *dev)60{61	struct armada_private *priv;62	struct resource *mem = NULL;63	int ret, n;64 65	for (n = 0; ; n++) {66		struct resource *r = platform_get_resource(to_platform_device(dev),67							   IORESOURCE_MEM, n);68		if (!r)69			break;70 71		/* Resources above 64K are graphics memory */72		if (resource_size(r) > SZ_64K)73			mem = r;74		else75			return -EINVAL;76	}77 78	if (!mem)79		return -ENXIO;80 81	if (!devm_request_mem_region(dev, mem->start, resource_size(mem),82				     "armada-drm"))83		return -EBUSY;84 85	priv = devm_drm_dev_alloc(dev, &armada_drm_driver,86				  struct armada_private, drm);87	if (IS_ERR(priv)) {88		dev_err(dev, "[" DRM_NAME ":%s] devm_drm_dev_alloc failed: %li\n",89			__func__, PTR_ERR(priv));90		return PTR_ERR(priv);91	}92 93	/* Remove early framebuffers */94	ret = drm_aperture_remove_framebuffers(&armada_drm_driver);95	if (ret) {96		dev_err(dev, "[" DRM_NAME ":%s] can't kick out simple-fb: %d\n",97			__func__, ret);98		return ret;99	}100 101	dev_set_drvdata(dev, &priv->drm);102 103	/* Mode setting support */104	drm_mode_config_init(&priv->drm);105	priv->drm.mode_config.min_width = 320;106	priv->drm.mode_config.min_height = 200;107 108	/*109	 * With vscale enabled, the maximum width is 1920 due to the110	 * 1920 by 3 lines RAM111	 */112	priv->drm.mode_config.max_width = 1920;113	priv->drm.mode_config.max_height = 2048;114 115	priv->drm.mode_config.preferred_depth = 24;116	priv->drm.mode_config.funcs = &armada_drm_mode_config_funcs;117	drm_mm_init(&priv->linear, mem->start, resource_size(mem));118	mutex_init(&priv->linear_lock);119 120	ret = component_bind_all(dev, &priv->drm);121	if (ret)122		goto err_kms;123 124	ret = drm_vblank_init(&priv->drm, priv->drm.mode_config.num_crtc);125	if (ret)126		goto err_comp;127 128	drm_mode_config_reset(&priv->drm);129 130	drm_kms_helper_poll_init(&priv->drm);131 132	ret = drm_dev_register(&priv->drm, 0);133	if (ret)134		goto err_poll;135 136#ifdef CONFIG_DEBUG_FS137	armada_drm_debugfs_init(priv->drm.primary);138#endif139 140	armada_fbdev_setup(&priv->drm);141 142	return 0;143 144 err_poll:145	drm_kms_helper_poll_fini(&priv->drm);146 err_comp:147	component_unbind_all(dev, &priv->drm);148 err_kms:149	drm_mode_config_cleanup(&priv->drm);150	drm_mm_takedown(&priv->linear);151	dev_set_drvdata(dev, NULL);152	return ret;153}154 155static void armada_drm_unbind(struct device *dev)156{157	struct drm_device *drm = dev_get_drvdata(dev);158	struct armada_private *priv = drm_to_armada_dev(drm);159 160	drm_kms_helper_poll_fini(&priv->drm);161 162	drm_dev_unregister(&priv->drm);163 164	drm_atomic_helper_shutdown(&priv->drm);165 166	component_unbind_all(dev, &priv->drm);167 168	drm_mode_config_cleanup(&priv->drm);169	drm_mm_takedown(&priv->linear);170	dev_set_drvdata(dev, NULL);171}172 173static void armada_add_endpoints(struct device *dev,174	struct component_match **match, struct device_node *dev_node)175{176	struct device_node *ep, *remote;177 178	for_each_endpoint_of_node(dev_node, ep) {179		remote = of_graph_get_remote_port_parent(ep);180		if (remote && of_device_is_available(remote))181			drm_of_component_match_add(dev, match, component_compare_of,182						   remote);183		of_node_put(remote);184	}185}186 187static const struct component_master_ops armada_master_ops = {188	.bind = armada_drm_bind,189	.unbind = armada_drm_unbind,190};191 192static int armada_drm_probe(struct platform_device *pdev)193{194	struct component_match *match = NULL;195	struct device *dev = &pdev->dev;196	int ret;197 198	ret = drm_of_component_probe(dev, component_compare_dev_name, &armada_master_ops);199	if (ret != -EINVAL)200		return ret;201 202	if (dev->platform_data) {203		char **devices = dev->platform_data;204		struct device *d;205		int i;206 207		for (i = 0; devices[i]; i++)208			component_match_add(dev, &match, component_compare_dev_name,209					    devices[i]);210 211		if (i == 0) {212			dev_err(dev, "missing 'ports' property\n");213			return -ENODEV;214		}215 216		for (i = 0; devices[i]; i++) {217			d = bus_find_device_by_name(&platform_bus_type, NULL,218						    devices[i]);219			if (d && d->of_node)220				armada_add_endpoints(dev, &match, d->of_node);221			put_device(d);222		}223	}224 225	return component_master_add_with_match(&pdev->dev, &armada_master_ops,226					       match);227}228 229static void armada_drm_remove(struct platform_device *pdev)230{231	component_master_del(&pdev->dev, &armada_master_ops);232}233 234static void armada_drm_shutdown(struct platform_device *pdev)235{236	drm_atomic_helper_shutdown(platform_get_drvdata(pdev));237}238 239static const struct platform_device_id armada_drm_platform_ids[] = {240	{241		.name		= "armada-drm",242	}, {243		.name		= "armada-510-drm",244	},245	{ },246};247MODULE_DEVICE_TABLE(platform, armada_drm_platform_ids);248 249static struct platform_driver armada_drm_platform_driver = {250	.probe	= armada_drm_probe,251	.remove_new = armada_drm_remove,252	.shutdown = armada_drm_shutdown,253	.driver	= {254		.name	= "armada-drm",255	},256	.id_table = armada_drm_platform_ids,257};258 259static int __init armada_drm_init(void)260{261	int ret;262 263	if (drm_firmware_drivers_only())264		return -ENODEV;265 266	ret = platform_driver_register(&armada_lcd_platform_driver);267	if (ret)268		return ret;269	ret = platform_driver_register(&armada_drm_platform_driver);270	if (ret)271		platform_driver_unregister(&armada_lcd_platform_driver);272	return ret;273}274module_init(armada_drm_init);275 276static void __exit armada_drm_exit(void)277{278	platform_driver_unregister(&armada_drm_platform_driver);279	platform_driver_unregister(&armada_lcd_platform_driver);280}281module_exit(armada_drm_exit);282 283MODULE_AUTHOR("Russell King <rmk+kernel@armlinux.org.uk>");284MODULE_DESCRIPTION("Armada DRM Driver");285MODULE_LICENSE("GPL");286MODULE_ALIAS("platform:armada-drm");287