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