xref: /linux/drivers/gpu/drm/imx/dc/dc-drv.c (revision 260f6f4fda93c8485c8037865c941b42b9cba5d2)
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 
32 struct dc_priv {
33 	struct drm_device *drm;
34 	struct clk *clk_cfg;
35 };
36 
37 DEFINE_DRM_GEM_DMA_FOPS(dc_drm_driver_fops);
38 
39 static 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 
51 static void
dc_add_components(struct device * dev,struct component_match ** matchptr)52 dc_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 
dc_drm_component_bind_all(struct dc_drm_device * dc_drm)71 static 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 
dc_drm_component_unbind_all(void * ptr)86 static 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 
dc_drm_bind(struct device * dev)94 static 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 
133 err:
134 	dc_kms_uninit(dc_drm);
135 
136 	return ret;
137 }
138 
dc_drm_unbind(struct device * dev)139 static 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 
151 static const struct component_master_ops dc_drm_ops = {
152 	.bind = dc_drm_bind,
153 	.unbind = dc_drm_unbind,
154 };
155 
dc_probe(struct platform_device * pdev)156 static 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 
dc_remove(struct platform_device * pdev)195 static void dc_remove(struct platform_device *pdev)
196 {
197 	component_master_del(&pdev->dev, &dc_drm_ops);
198 }
199 
dc_runtime_suspend(struct device * dev)200 static 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 
dc_runtime_resume(struct device * dev)209 static 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 
dc_suspend(struct device * dev)221 static 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 
dc_resume(struct device * dev)228 static 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 
dc_shutdown(struct platform_device * pdev)235 static 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 
242 static 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 
247 static const struct of_device_id dc_dt_ids[] = {
248 	{ .compatible = "fsl,imx8qxp-dc", },
249 	{ /* sentinel */ }
250 };
251 MODULE_DEVICE_TABLE(of, dc_dt_ids);
252 
253 static 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 
264 static 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 
dc_drm_init(void)278 static int __init dc_drm_init(void)
279 {
280 	return platform_register_drivers(dc_drivers, ARRAY_SIZE(dc_drivers));
281 }
282 
dc_drm_exit(void)283 static void __exit dc_drm_exit(void)
284 {
285 	platform_unregister_drivers(dc_drivers, ARRAY_SIZE(dc_drivers));
286 }
287 
288 module_init(dc_drm_init);
289 module_exit(dc_drm_exit);
290 
291 MODULE_DESCRIPTION("i.MX8 Display Controller DRM Driver");
292 MODULE_AUTHOR("Liu Ying <victor.liu@nxp.com>");
293 MODULE_LICENSE("GPL");
294