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