File Index
Files and directories
Sign in
FILE

dc-drv.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/imx/dc/dc-drv.c C
  1// SPDX-License-Identifier: GPL-2.0+
  2/*
  3 * Copyright 2024 NXP
  4 */
  5
  6#include <linux/clk.h>
  7#include <linux/component.h>
  8#include <linux/device.h>
  9#include <linux/dma-mapping.h>
 10#include <linux/mod_devicetable.h>
 11#include <linux/module.h>
 12#include <linux/of.h>
 13#include <linux/of_platform.h>
 14#include <linux/platform_device.h>
 15#include <linux/pm.h>
 16#include <linux/pm_runtime.h>
 17
 18#include <drm/clients/drm_client_setup.h>
 19#include <drm/drm_atomic_helper.h>
 20#include <drm/drm_drv.h>
 21#include <drm/drm_fbdev_dma.h>
 22#include <drm/drm_fourcc.h>
 23#include <drm/drm_gem_dma_helper.h>
 24#include <drm/drm_managed.h>
 25#include <drm/drm_modeset_helper.h>
 26#include <drm/drm_of.h>
 27
 28#include "dc-de.h"
 29#include "dc-drv.h"
 30#include "dc-pe.h"
 31
 32struct dc_priv {
 33	struct drm_device *drm;
 34	struct clk *clk_cfg;
 35};
 36
 37DEFINE_DRM_GEM_DMA_FOPS(dc_drm_driver_fops);
 38
 39static struct drm_driver dc_drm_driver = {
 40	.driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC,
 41	DRM_GEM_DMA_DRIVER_OPS,
 42	DRM_FBDEV_DMA_DRIVER_OPS,
 43	.fops = &dc_drm_driver_fops,
 44	.name = "imx8-dc",
 45	.desc = "i.MX8 DC DRM graphics",
 46	.major = 1,
 47	.minor = 0,
 48	.patchlevel = 0,
 49};
 50
 51static void
 52dc_add_components(struct device *dev, struct component_match **matchptr)
 53{
 54	struct device_node *child, *grandchild;
 55
 56	for_each_available_child_of_node(dev->of_node, child) {
 57		/* The interrupt controller is not a component. */
 58		if (of_device_is_compatible(child, "fsl,imx8qxp-dc-intc"))
 59			continue;
 60
 61		drm_of_component_match_add(dev, matchptr, component_compare_of,
 62					   child);
 63
 64		for_each_available_child_of_node(child, grandchild)
 65			drm_of_component_match_add(dev, matchptr,
 66						   component_compare_of,
 67						   grandchild);
 68	}
 69}
 70
 71static int dc_drm_component_bind_all(struct dc_drm_device *dc_drm)
 72{
 73	struct drm_device *drm = &dc_drm->base;
 74	int ret;
 75
 76	ret = component_bind_all(drm->dev, dc_drm);
 77	if (ret)
 78		return ret;
 79
 80	dc_de_post_bind(dc_drm);
 81	dc_pe_post_bind(dc_drm);
 82
 83	return 0;
 84}
 85
 86static void dc_drm_component_unbind_all(void *ptr)
 87{
 88	struct dc_drm_device *dc_drm = ptr;
 89	struct drm_device *drm = &dc_drm->base;
 90
 91	component_unbind_all(drm->dev, dc_drm);
 92}
 93
 94static int dc_drm_bind(struct device *dev)
 95{
 96	struct dc_priv *priv = dev_get_drvdata(dev);
 97	struct dc_drm_device *dc_drm;
 98	struct drm_device *drm;
 99	int ret;
100
101	dc_drm = devm_drm_dev_alloc(dev, &dc_drm_driver, struct dc_drm_device,
102				    base);
103	if (IS_ERR(dc_drm))
104		return PTR_ERR(dc_drm);
105
106	drm = &dc_drm->base;
107
108	ret = dc_drm_component_bind_all(dc_drm);
109	if (ret)
110		return ret;
111
112	ret = devm_add_action_or_reset(dev, dc_drm_component_unbind_all,
113				       dc_drm);
114	if (ret)
115		return ret;
116
117	ret = dc_kms_init(dc_drm);
118	if (ret)
119		return ret;
120
121	ret = drm_dev_register(drm, 0);
122	if (ret) {
123		dev_err(dev, "failed to register drm device: %d\n", ret);
124		goto err;
125	}
126
127	drm_client_setup_with_fourcc(drm, DRM_FORMAT_XRGB8888);
128
129	priv->drm = drm;
130
131	return 0;
132
133err:
134	dc_kms_uninit(dc_drm);
135
136	return ret;
137}
138
139static void dc_drm_unbind(struct device *dev)
140{
141	struct dc_priv *priv = dev_get_drvdata(dev);
142	struct dc_drm_device *dc_drm = to_dc_drm_device(priv->drm);
143	struct drm_device *drm = &dc_drm->base;
144
145	priv->drm = NULL;
146	drm_dev_unplug(drm);
147	dc_kms_uninit(dc_drm);
148	drm_atomic_helper_shutdown(drm);
149}
150
151static const struct component_master_ops dc_drm_ops = {
152	.bind = dc_drm_bind,
153	.unbind = dc_drm_unbind,
154};
155
156static int dc_probe(struct platform_device *pdev)
157{
158	struct component_match *match = NULL;
159	struct dc_priv *priv;
160	int ret;
161
162	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
163	if (!priv)
164		return -ENOMEM;
165
166	priv->clk_cfg = devm_clk_get(&pdev->dev, NULL);
167	if (IS_ERR(priv->clk_cfg))
168		return dev_err_probe(&pdev->dev, PTR_ERR(priv->clk_cfg),
169				     "failed to get cfg clock\n");
170
171	dev_set_drvdata(&pdev->dev, priv);
172
173	ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
174	if (ret)
175		return ret;
176
177	ret = devm_pm_runtime_enable(&pdev->dev);
178	if (ret)
179		return ret;
180
181	ret = devm_of_platform_populate(&pdev->dev);
182	if (ret)
183		return ret;
184
185	dc_add_components(&pdev->dev, &match);
186
187	ret = component_master_add_with_match(&pdev->dev, &dc_drm_ops, match);
188	if (ret)
189		return dev_err_probe(&pdev->dev, ret,
190				     "failed to add component master\n");
191
192	return 0;
193}
194
195static void dc_remove(struct platform_device *pdev)
196{
197	component_master_del(&pdev->dev, &dc_drm_ops);
198}
199
200static int dc_runtime_suspend(struct device *dev)
201{
202	struct dc_priv *priv = dev_get_drvdata(dev);
203
204	clk_disable_unprepare(priv->clk_cfg);
205
206	return 0;
207}
208
209static int dc_runtime_resume(struct device *dev)
210{
211	struct dc_priv *priv = dev_get_drvdata(dev);
212	int ret;
213
214	ret = clk_prepare_enable(priv->clk_cfg);
215	if (ret)
216		dev_err(dev, "failed to enable cfg clock: %d\n", ret);
217
218	return ret;
219}
220
221static int dc_suspend(struct device *dev)
222{
223	struct dc_priv *priv = dev_get_drvdata(dev);
224
225	return drm_mode_config_helper_suspend(priv->drm);
226}
227
228static int dc_resume(struct device *dev)
229{
230	struct dc_priv *priv = dev_get_drvdata(dev);
231
232	return drm_mode_config_helper_resume(priv->drm);
233}
234
235static void dc_shutdown(struct platform_device *pdev)
236{
237	struct dc_priv *priv = dev_get_drvdata(&pdev->dev);
238
239	drm_atomic_helper_shutdown(priv->drm);
240}
241
242static const struct dev_pm_ops dc_pm_ops = {
243	RUNTIME_PM_OPS(dc_runtime_suspend, dc_runtime_resume, NULL)
244	SYSTEM_SLEEP_PM_OPS(dc_suspend, dc_resume)
245};
246
247static const struct of_device_id dc_dt_ids[] = {
248	{ .compatible = "fsl,imx8qxp-dc", },
249	{ /* sentinel */ }
250};
251MODULE_DEVICE_TABLE(of, dc_dt_ids);
252
253static struct platform_driver dc_driver = {
254	.probe = dc_probe,
255	.remove = dc_remove,
256	.shutdown = dc_shutdown,
257	.driver = {
258		.name = "imx8-dc",
259		.of_match_table	= dc_dt_ids,
260		.pm = pm_sleep_ptr(&dc_pm_ops),
261	},
262};
263
264static struct platform_driver * const dc_drivers[] = {
265	&dc_cf_driver,
266	&dc_de_driver,
267	&dc_ed_driver,
268	&dc_fg_driver,
269	&dc_fl_driver,
270	&dc_fw_driver,
271	&dc_ic_driver,
272	&dc_lb_driver,
273	&dc_pe_driver,
274	&dc_tc_driver,
275	&dc_driver,
276};
277
278static int __init dc_drm_init(void)
279{
280	return platform_register_drivers(dc_drivers, ARRAY_SIZE(dc_drivers));
281}
282
283static void __exit dc_drm_exit(void)
284{
285	platform_unregister_drivers(dc_drivers, ARRAY_SIZE(dc_drivers));
286}
287
288module_init(dc_drm_init);
289module_exit(dc_drm_exit);
290
291MODULE_DESCRIPTION("i.MX8 Display Controller DRM Driver");
292MODULE_AUTHOR("Liu Ying <victor.liu@nxp.com>");
293MODULE_LICENSE("GPL");
~/ Read-only file preview.