1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (c) 2015 MediaTek Inc. |
4 | * Author: YT SHEN <yt.shen@mediatek.com> |
5 | */ |
6 | |
7 | #include <linux/component.h> |
8 | #include <linux/module.h> |
9 | #include <linux/of.h> |
10 | #include <linux/of_platform.h> |
11 | #include <linux/platform_device.h> |
12 | #include <linux/pm_runtime.h> |
13 | #include <linux/dma-mapping.h> |
14 | |
15 | #include <drm/drm_atomic.h> |
16 | #include <drm/drm_atomic_helper.h> |
17 | #include <drm/drm_drv.h> |
18 | #include <drm/drm_fbdev_generic.h> |
19 | #include <drm/drm_fourcc.h> |
20 | #include <drm/drm_gem.h> |
21 | #include <drm/drm_gem_framebuffer_helper.h> |
22 | #include <drm/drm_ioctl.h> |
23 | #include <drm/drm_of.h> |
24 | #include <drm/drm_probe_helper.h> |
25 | #include <drm/drm_vblank.h> |
26 | |
27 | #include "mtk_drm_crtc.h" |
28 | #include "mtk_drm_ddp_comp.h" |
29 | #include "mtk_drm_drv.h" |
30 | #include "mtk_drm_gem.h" |
31 | |
32 | #define DRIVER_NAME "mediatek" |
33 | #define DRIVER_DESC "Mediatek SoC DRM" |
34 | #define DRIVER_DATE "20150513" |
35 | #define DRIVER_MAJOR 1 |
36 | #define DRIVER_MINOR 0 |
37 | |
38 | static const struct drm_mode_config_helper_funcs mtk_drm_mode_config_helpers = { |
39 | .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, |
40 | }; |
41 | |
42 | static struct drm_framebuffer * |
43 | mtk_drm_mode_fb_create(struct drm_device *dev, |
44 | struct drm_file *file, |
45 | const struct drm_mode_fb_cmd2 *cmd) |
46 | { |
47 | const struct drm_format_info *info = drm_get_format_info(dev, mode_cmd: cmd); |
48 | |
49 | if (info->num_planes != 1) |
50 | return ERR_PTR(error: -EINVAL); |
51 | |
52 | return drm_gem_fb_create(dev, file, mode_cmd: cmd); |
53 | } |
54 | |
55 | static const struct drm_mode_config_funcs mtk_drm_mode_config_funcs = { |
56 | .fb_create = mtk_drm_mode_fb_create, |
57 | .atomic_check = drm_atomic_helper_check, |
58 | .atomic_commit = drm_atomic_helper_commit, |
59 | }; |
60 | |
61 | static const unsigned int mt2701_mtk_ddp_main[] = { |
62 | DDP_COMPONENT_OVL0, |
63 | DDP_COMPONENT_RDMA0, |
64 | DDP_COMPONENT_COLOR0, |
65 | DDP_COMPONENT_BLS, |
66 | DDP_COMPONENT_DSI0, |
67 | }; |
68 | |
69 | static const unsigned int mt2701_mtk_ddp_ext[] = { |
70 | DDP_COMPONENT_RDMA1, |
71 | DDP_COMPONENT_DPI0, |
72 | }; |
73 | |
74 | static const unsigned int mt7623_mtk_ddp_main[] = { |
75 | DDP_COMPONENT_OVL0, |
76 | DDP_COMPONENT_RDMA0, |
77 | DDP_COMPONENT_COLOR0, |
78 | DDP_COMPONENT_BLS, |
79 | DDP_COMPONENT_DPI0, |
80 | }; |
81 | |
82 | static const unsigned int mt7623_mtk_ddp_ext[] = { |
83 | DDP_COMPONENT_RDMA1, |
84 | DDP_COMPONENT_DSI0, |
85 | }; |
86 | |
87 | static const unsigned int mt2712_mtk_ddp_main[] = { |
88 | DDP_COMPONENT_OVL0, |
89 | DDP_COMPONENT_COLOR0, |
90 | DDP_COMPONENT_AAL0, |
91 | DDP_COMPONENT_OD0, |
92 | DDP_COMPONENT_RDMA0, |
93 | DDP_COMPONENT_DPI0, |
94 | DDP_COMPONENT_PWM0, |
95 | }; |
96 | |
97 | static const unsigned int mt2712_mtk_ddp_ext[] = { |
98 | DDP_COMPONENT_OVL1, |
99 | DDP_COMPONENT_COLOR1, |
100 | DDP_COMPONENT_AAL1, |
101 | DDP_COMPONENT_OD1, |
102 | DDP_COMPONENT_RDMA1, |
103 | DDP_COMPONENT_DPI1, |
104 | DDP_COMPONENT_PWM1, |
105 | }; |
106 | |
107 | static const unsigned int mt2712_mtk_ddp_third[] = { |
108 | DDP_COMPONENT_RDMA2, |
109 | DDP_COMPONENT_DSI3, |
110 | DDP_COMPONENT_PWM2, |
111 | }; |
112 | |
113 | static unsigned int mt8167_mtk_ddp_main[] = { |
114 | DDP_COMPONENT_OVL0, |
115 | DDP_COMPONENT_COLOR0, |
116 | DDP_COMPONENT_CCORR, |
117 | DDP_COMPONENT_AAL0, |
118 | DDP_COMPONENT_GAMMA, |
119 | DDP_COMPONENT_DITHER0, |
120 | DDP_COMPONENT_RDMA0, |
121 | DDP_COMPONENT_DSI0, |
122 | }; |
123 | |
124 | static const unsigned int mt8173_mtk_ddp_main[] = { |
125 | DDP_COMPONENT_OVL0, |
126 | DDP_COMPONENT_COLOR0, |
127 | DDP_COMPONENT_AAL0, |
128 | DDP_COMPONENT_OD0, |
129 | DDP_COMPONENT_RDMA0, |
130 | DDP_COMPONENT_UFOE, |
131 | DDP_COMPONENT_DSI0, |
132 | DDP_COMPONENT_PWM0, |
133 | }; |
134 | |
135 | static const unsigned int mt8173_mtk_ddp_ext[] = { |
136 | DDP_COMPONENT_OVL1, |
137 | DDP_COMPONENT_COLOR1, |
138 | DDP_COMPONENT_GAMMA, |
139 | DDP_COMPONENT_RDMA1, |
140 | DDP_COMPONENT_DPI0, |
141 | }; |
142 | |
143 | static const unsigned int mt8183_mtk_ddp_main[] = { |
144 | DDP_COMPONENT_OVL0, |
145 | DDP_COMPONENT_OVL_2L0, |
146 | DDP_COMPONENT_RDMA0, |
147 | DDP_COMPONENT_COLOR0, |
148 | DDP_COMPONENT_CCORR, |
149 | DDP_COMPONENT_AAL0, |
150 | DDP_COMPONENT_GAMMA, |
151 | DDP_COMPONENT_DITHER0, |
152 | DDP_COMPONENT_DSI0, |
153 | }; |
154 | |
155 | static const unsigned int mt8183_mtk_ddp_ext[] = { |
156 | DDP_COMPONENT_OVL_2L1, |
157 | DDP_COMPONENT_RDMA1, |
158 | DDP_COMPONENT_DPI0, |
159 | }; |
160 | |
161 | static const unsigned int mt8186_mtk_ddp_main[] = { |
162 | DDP_COMPONENT_OVL0, |
163 | DDP_COMPONENT_RDMA0, |
164 | DDP_COMPONENT_COLOR0, |
165 | DDP_COMPONENT_CCORR, |
166 | DDP_COMPONENT_AAL0, |
167 | DDP_COMPONENT_GAMMA, |
168 | DDP_COMPONENT_POSTMASK0, |
169 | DDP_COMPONENT_DITHER0, |
170 | DDP_COMPONENT_DSI0, |
171 | }; |
172 | |
173 | static const unsigned int mt8186_mtk_ddp_ext[] = { |
174 | DDP_COMPONENT_OVL_2L0, |
175 | DDP_COMPONENT_RDMA1, |
176 | DDP_COMPONENT_DPI0, |
177 | }; |
178 | |
179 | static const unsigned int mt8188_mtk_ddp_main[] = { |
180 | DDP_COMPONENT_OVL0, |
181 | DDP_COMPONENT_RDMA0, |
182 | DDP_COMPONENT_COLOR0, |
183 | DDP_COMPONENT_CCORR, |
184 | DDP_COMPONENT_AAL0, |
185 | DDP_COMPONENT_GAMMA, |
186 | DDP_COMPONENT_POSTMASK0, |
187 | DDP_COMPONENT_DITHER0, |
188 | }; |
189 | |
190 | static const struct mtk_drm_route mt8188_mtk_ddp_main_routes[] = { |
191 | {0, DDP_COMPONENT_DP_INTF0}, |
192 | {0, DDP_COMPONENT_DSI0}, |
193 | }; |
194 | |
195 | static const unsigned int mt8192_mtk_ddp_main[] = { |
196 | DDP_COMPONENT_OVL0, |
197 | DDP_COMPONENT_OVL_2L0, |
198 | DDP_COMPONENT_RDMA0, |
199 | DDP_COMPONENT_COLOR0, |
200 | DDP_COMPONENT_CCORR, |
201 | DDP_COMPONENT_AAL0, |
202 | DDP_COMPONENT_GAMMA, |
203 | DDP_COMPONENT_POSTMASK0, |
204 | DDP_COMPONENT_DITHER0, |
205 | DDP_COMPONENT_DSI0, |
206 | }; |
207 | |
208 | static const unsigned int mt8192_mtk_ddp_ext[] = { |
209 | DDP_COMPONENT_OVL_2L2, |
210 | DDP_COMPONENT_RDMA4, |
211 | DDP_COMPONENT_DPI0, |
212 | }; |
213 | |
214 | static const unsigned int mt8195_mtk_ddp_main[] = { |
215 | DDP_COMPONENT_OVL0, |
216 | DDP_COMPONENT_RDMA0, |
217 | DDP_COMPONENT_COLOR0, |
218 | DDP_COMPONENT_CCORR, |
219 | DDP_COMPONENT_AAL0, |
220 | DDP_COMPONENT_GAMMA, |
221 | DDP_COMPONENT_DITHER0, |
222 | DDP_COMPONENT_DSC0, |
223 | DDP_COMPONENT_MERGE0, |
224 | DDP_COMPONENT_DP_INTF0, |
225 | }; |
226 | |
227 | static const unsigned int mt8195_mtk_ddp_ext[] = { |
228 | DDP_COMPONENT_DRM_OVL_ADAPTOR, |
229 | DDP_COMPONENT_MERGE5, |
230 | DDP_COMPONENT_DP_INTF1, |
231 | }; |
232 | |
233 | static const struct mtk_mmsys_driver_data mt2701_mmsys_driver_data = { |
234 | .main_path = mt2701_mtk_ddp_main, |
235 | .main_len = ARRAY_SIZE(mt2701_mtk_ddp_main), |
236 | .ext_path = mt2701_mtk_ddp_ext, |
237 | .ext_len = ARRAY_SIZE(mt2701_mtk_ddp_ext), |
238 | .shadow_register = true, |
239 | .mmsys_dev_num = 1, |
240 | }; |
241 | |
242 | static const struct mtk_mmsys_driver_data mt7623_mmsys_driver_data = { |
243 | .main_path = mt7623_mtk_ddp_main, |
244 | .main_len = ARRAY_SIZE(mt7623_mtk_ddp_main), |
245 | .ext_path = mt7623_mtk_ddp_ext, |
246 | .ext_len = ARRAY_SIZE(mt7623_mtk_ddp_ext), |
247 | .shadow_register = true, |
248 | .mmsys_dev_num = 1, |
249 | }; |
250 | |
251 | static const struct mtk_mmsys_driver_data mt2712_mmsys_driver_data = { |
252 | .main_path = mt2712_mtk_ddp_main, |
253 | .main_len = ARRAY_SIZE(mt2712_mtk_ddp_main), |
254 | .ext_path = mt2712_mtk_ddp_ext, |
255 | .ext_len = ARRAY_SIZE(mt2712_mtk_ddp_ext), |
256 | .third_path = mt2712_mtk_ddp_third, |
257 | .third_len = ARRAY_SIZE(mt2712_mtk_ddp_third), |
258 | .mmsys_dev_num = 1, |
259 | }; |
260 | |
261 | static const struct mtk_mmsys_driver_data mt8167_mmsys_driver_data = { |
262 | .main_path = mt8167_mtk_ddp_main, |
263 | .main_len = ARRAY_SIZE(mt8167_mtk_ddp_main), |
264 | .mmsys_dev_num = 1, |
265 | }; |
266 | |
267 | static const struct mtk_mmsys_driver_data mt8173_mmsys_driver_data = { |
268 | .main_path = mt8173_mtk_ddp_main, |
269 | .main_len = ARRAY_SIZE(mt8173_mtk_ddp_main), |
270 | .ext_path = mt8173_mtk_ddp_ext, |
271 | .ext_len = ARRAY_SIZE(mt8173_mtk_ddp_ext), |
272 | .mmsys_dev_num = 1, |
273 | }; |
274 | |
275 | static const struct mtk_mmsys_driver_data mt8183_mmsys_driver_data = { |
276 | .main_path = mt8183_mtk_ddp_main, |
277 | .main_len = ARRAY_SIZE(mt8183_mtk_ddp_main), |
278 | .ext_path = mt8183_mtk_ddp_ext, |
279 | .ext_len = ARRAY_SIZE(mt8183_mtk_ddp_ext), |
280 | .mmsys_dev_num = 1, |
281 | }; |
282 | |
283 | static const struct mtk_mmsys_driver_data mt8186_mmsys_driver_data = { |
284 | .main_path = mt8186_mtk_ddp_main, |
285 | .main_len = ARRAY_SIZE(mt8186_mtk_ddp_main), |
286 | .ext_path = mt8186_mtk_ddp_ext, |
287 | .ext_len = ARRAY_SIZE(mt8186_mtk_ddp_ext), |
288 | .mmsys_dev_num = 1, |
289 | }; |
290 | |
291 | static const struct mtk_mmsys_driver_data mt8188_vdosys0_driver_data = { |
292 | .main_path = mt8188_mtk_ddp_main, |
293 | .main_len = ARRAY_SIZE(mt8188_mtk_ddp_main), |
294 | .conn_routes = mt8188_mtk_ddp_main_routes, |
295 | .num_conn_routes = ARRAY_SIZE(mt8188_mtk_ddp_main_routes), |
296 | .mmsys_dev_num = 2, |
297 | }; |
298 | |
299 | static const struct mtk_mmsys_driver_data mt8192_mmsys_driver_data = { |
300 | .main_path = mt8192_mtk_ddp_main, |
301 | .main_len = ARRAY_SIZE(mt8192_mtk_ddp_main), |
302 | .ext_path = mt8192_mtk_ddp_ext, |
303 | .ext_len = ARRAY_SIZE(mt8192_mtk_ddp_ext), |
304 | .mmsys_dev_num = 1, |
305 | }; |
306 | |
307 | static const struct mtk_mmsys_driver_data mt8195_vdosys0_driver_data = { |
308 | .main_path = mt8195_mtk_ddp_main, |
309 | .main_len = ARRAY_SIZE(mt8195_mtk_ddp_main), |
310 | .mmsys_dev_num = 2, |
311 | }; |
312 | |
313 | static const struct mtk_mmsys_driver_data mt8195_vdosys1_driver_data = { |
314 | .ext_path = mt8195_mtk_ddp_ext, |
315 | .ext_len = ARRAY_SIZE(mt8195_mtk_ddp_ext), |
316 | .mmsys_id = 1, |
317 | .mmsys_dev_num = 2, |
318 | }; |
319 | |
320 | static const struct of_device_id mtk_drm_of_ids[] = { |
321 | { .compatible = "mediatek,mt2701-mmsys" , |
322 | .data = &mt2701_mmsys_driver_data}, |
323 | { .compatible = "mediatek,mt7623-mmsys" , |
324 | .data = &mt7623_mmsys_driver_data}, |
325 | { .compatible = "mediatek,mt2712-mmsys" , |
326 | .data = &mt2712_mmsys_driver_data}, |
327 | { .compatible = "mediatek,mt8167-mmsys" , |
328 | .data = &mt8167_mmsys_driver_data}, |
329 | { .compatible = "mediatek,mt8173-mmsys" , |
330 | .data = &mt8173_mmsys_driver_data}, |
331 | { .compatible = "mediatek,mt8183-mmsys" , |
332 | .data = &mt8183_mmsys_driver_data}, |
333 | { .compatible = "mediatek,mt8186-mmsys" , |
334 | .data = &mt8186_mmsys_driver_data}, |
335 | { .compatible = "mediatek,mt8188-vdosys0" , |
336 | .data = &mt8188_vdosys0_driver_data}, |
337 | { .compatible = "mediatek,mt8188-vdosys1" , |
338 | .data = &mt8195_vdosys1_driver_data}, |
339 | { .compatible = "mediatek,mt8192-mmsys" , |
340 | .data = &mt8192_mmsys_driver_data}, |
341 | { .compatible = "mediatek,mt8195-mmsys" , |
342 | .data = &mt8195_vdosys0_driver_data}, |
343 | { .compatible = "mediatek,mt8195-vdosys0" , |
344 | .data = &mt8195_vdosys0_driver_data}, |
345 | { .compatible = "mediatek,mt8195-vdosys1" , |
346 | .data = &mt8195_vdosys1_driver_data}, |
347 | { } |
348 | }; |
349 | MODULE_DEVICE_TABLE(of, mtk_drm_of_ids); |
350 | |
351 | static int mtk_drm_match(struct device *dev, void *data) |
352 | { |
353 | if (!strncmp(dev_name(dev), "mediatek-drm" , sizeof("mediatek-drm" ) - 1)) |
354 | return true; |
355 | return false; |
356 | } |
357 | |
358 | static bool mtk_drm_get_all_drm_priv(struct device *dev) |
359 | { |
360 | struct mtk_drm_private *drm_priv = dev_get_drvdata(dev); |
361 | struct mtk_drm_private *all_drm_priv[MAX_CRTC]; |
362 | struct mtk_drm_private *temp_drm_priv; |
363 | struct device_node *phandle = dev->parent->of_node; |
364 | const struct of_device_id *of_id; |
365 | struct device_node *node; |
366 | struct device *drm_dev; |
367 | unsigned int cnt = 0; |
368 | int i, j; |
369 | |
370 | for_each_child_of_node(phandle->parent, node) { |
371 | struct platform_device *pdev; |
372 | |
373 | of_id = of_match_node(matches: mtk_drm_of_ids, node); |
374 | if (!of_id) |
375 | continue; |
376 | |
377 | pdev = of_find_device_by_node(np: node); |
378 | if (!pdev) |
379 | continue; |
380 | |
381 | drm_dev = device_find_child(dev: &pdev->dev, NULL, match: mtk_drm_match); |
382 | if (!drm_dev) |
383 | continue; |
384 | |
385 | temp_drm_priv = dev_get_drvdata(dev: drm_dev); |
386 | if (!temp_drm_priv) |
387 | continue; |
388 | |
389 | if (temp_drm_priv->data->main_len) |
390 | all_drm_priv[CRTC_MAIN] = temp_drm_priv; |
391 | else if (temp_drm_priv->data->ext_len) |
392 | all_drm_priv[CRTC_EXT] = temp_drm_priv; |
393 | else if (temp_drm_priv->data->third_len) |
394 | all_drm_priv[CRTC_THIRD] = temp_drm_priv; |
395 | |
396 | if (temp_drm_priv->mtk_drm_bound) |
397 | cnt++; |
398 | |
399 | if (cnt == MAX_CRTC) |
400 | break; |
401 | } |
402 | |
403 | if (drm_priv->data->mmsys_dev_num == cnt) { |
404 | for (i = 0; i < cnt; i++) |
405 | for (j = 0; j < cnt; j++) |
406 | all_drm_priv[j]->all_drm_private[i] = all_drm_priv[i]; |
407 | |
408 | return true; |
409 | } |
410 | |
411 | return false; |
412 | } |
413 | |
414 | static bool mtk_drm_find_mmsys_comp(struct mtk_drm_private *private, int comp_id) |
415 | { |
416 | const struct mtk_mmsys_driver_data *drv_data = private->data; |
417 | int i; |
418 | |
419 | if (drv_data->main_path) |
420 | for (i = 0; i < drv_data->main_len; i++) |
421 | if (drv_data->main_path[i] == comp_id) |
422 | return true; |
423 | |
424 | if (drv_data->ext_path) |
425 | for (i = 0; i < drv_data->ext_len; i++) |
426 | if (drv_data->ext_path[i] == comp_id) |
427 | return true; |
428 | |
429 | if (drv_data->third_path) |
430 | for (i = 0; i < drv_data->third_len; i++) |
431 | if (drv_data->third_path[i] == comp_id) |
432 | return true; |
433 | |
434 | if (drv_data->num_conn_routes) |
435 | for (i = 0; i < drv_data->num_conn_routes; i++) |
436 | if (drv_data->conn_routes[i].route_ddp == comp_id) |
437 | return true; |
438 | |
439 | return false; |
440 | } |
441 | |
442 | static int mtk_drm_kms_init(struct drm_device *drm) |
443 | { |
444 | struct mtk_drm_private *private = drm->dev_private; |
445 | struct mtk_drm_private *priv_n; |
446 | struct device *dma_dev = NULL; |
447 | struct drm_crtc *crtc; |
448 | int ret, i, j; |
449 | |
450 | if (drm_firmware_drivers_only()) |
451 | return -ENODEV; |
452 | |
453 | ret = drmm_mode_config_init(dev: drm); |
454 | if (ret) |
455 | goto put_mutex_dev; |
456 | |
457 | drm->mode_config.min_width = 64; |
458 | drm->mode_config.min_height = 64; |
459 | |
460 | /* |
461 | * set max width and height as default value(4096x4096). |
462 | * this value would be used to check framebuffer size limitation |
463 | * at drm_mode_addfb(). |
464 | */ |
465 | drm->mode_config.max_width = 4096; |
466 | drm->mode_config.max_height = 4096; |
467 | drm->mode_config.funcs = &mtk_drm_mode_config_funcs; |
468 | drm->mode_config.helper_private = &mtk_drm_mode_config_helpers; |
469 | |
470 | for (i = 0; i < private->data->mmsys_dev_num; i++) { |
471 | drm->dev_private = private->all_drm_private[i]; |
472 | ret = component_bind_all(parent: private->all_drm_private[i]->dev, data: drm); |
473 | if (ret) |
474 | goto put_mutex_dev; |
475 | } |
476 | |
477 | /* |
478 | * Ensure internal panels are at the top of the connector list before |
479 | * crtc creation. |
480 | */ |
481 | drm_helper_move_panel_connectors_to_head(drm); |
482 | |
483 | /* |
484 | * 1. We currently support two fixed data streams, each optional, |
485 | * and each statically assigned to a crtc: |
486 | * OVL0 -> COLOR0 -> AAL -> OD -> RDMA0 -> UFOE -> DSI0 ... |
487 | * 2. For multi mmsys architecture, crtc path data are located in |
488 | * different drm private data structures. Loop through crtc index to |
489 | * create crtc from the main path and then ext_path and finally the |
490 | * third path. |
491 | */ |
492 | for (i = 0; i < MAX_CRTC; i++) { |
493 | for (j = 0; j < private->data->mmsys_dev_num; j++) { |
494 | priv_n = private->all_drm_private[j]; |
495 | |
496 | if (i == CRTC_MAIN && priv_n->data->main_len) { |
497 | ret = mtk_drm_crtc_create(drm_dev: drm, path: priv_n->data->main_path, |
498 | path_len: priv_n->data->main_len, priv_data_index: j, |
499 | conn_routes: priv_n->data->conn_routes, |
500 | num_conn_routes: priv_n->data->num_conn_routes); |
501 | if (ret) |
502 | goto err_component_unbind; |
503 | |
504 | continue; |
505 | } else if (i == CRTC_EXT && priv_n->data->ext_len) { |
506 | ret = mtk_drm_crtc_create(drm_dev: drm, path: priv_n->data->ext_path, |
507 | path_len: priv_n->data->ext_len, priv_data_index: j, NULL, num_conn_routes: 0); |
508 | if (ret) |
509 | goto err_component_unbind; |
510 | |
511 | continue; |
512 | } else if (i == CRTC_THIRD && priv_n->data->third_len) { |
513 | ret = mtk_drm_crtc_create(drm_dev: drm, path: priv_n->data->third_path, |
514 | path_len: priv_n->data->third_len, priv_data_index: j, NULL, num_conn_routes: 0); |
515 | if (ret) |
516 | goto err_component_unbind; |
517 | |
518 | continue; |
519 | } |
520 | } |
521 | } |
522 | |
523 | /* Use OVL device for all DMA memory allocations */ |
524 | crtc = drm_crtc_from_index(dev: drm, idx: 0); |
525 | if (crtc) |
526 | dma_dev = mtk_drm_crtc_dma_dev_get(crtc); |
527 | if (!dma_dev) { |
528 | ret = -ENODEV; |
529 | dev_err(drm->dev, "Need at least one OVL device\n" ); |
530 | goto err_component_unbind; |
531 | } |
532 | |
533 | for (i = 0; i < private->data->mmsys_dev_num; i++) |
534 | private->all_drm_private[i]->dma_dev = dma_dev; |
535 | |
536 | /* |
537 | * Configure the DMA segment size to make sure we get contiguous IOVA |
538 | * when importing PRIME buffers. |
539 | */ |
540 | ret = dma_set_max_seg_size(dev: dma_dev, UINT_MAX); |
541 | if (ret) { |
542 | dev_err(dma_dev, "Failed to set DMA segment size\n" ); |
543 | goto err_component_unbind; |
544 | } |
545 | |
546 | ret = drm_vblank_init(dev: drm, num_crtcs: MAX_CRTC); |
547 | if (ret < 0) |
548 | goto err_component_unbind; |
549 | |
550 | drm_kms_helper_poll_init(dev: drm); |
551 | drm_mode_config_reset(dev: drm); |
552 | |
553 | return 0; |
554 | |
555 | err_component_unbind: |
556 | for (i = 0; i < private->data->mmsys_dev_num; i++) |
557 | component_unbind_all(parent: private->all_drm_private[i]->dev, data: drm); |
558 | put_mutex_dev: |
559 | for (i = 0; i < private->data->mmsys_dev_num; i++) |
560 | put_device(dev: private->all_drm_private[i]->mutex_dev); |
561 | |
562 | return ret; |
563 | } |
564 | |
565 | static void mtk_drm_kms_deinit(struct drm_device *drm) |
566 | { |
567 | drm_kms_helper_poll_fini(dev: drm); |
568 | drm_atomic_helper_shutdown(dev: drm); |
569 | |
570 | component_unbind_all(parent: drm->dev, data: drm); |
571 | } |
572 | |
573 | DEFINE_DRM_GEM_FOPS(mtk_drm_fops); |
574 | |
575 | /* |
576 | * We need to override this because the device used to import the memory is |
577 | * not dev->dev, as drm_gem_prime_import() expects. |
578 | */ |
579 | static struct drm_gem_object *mtk_drm_gem_prime_import(struct drm_device *dev, |
580 | struct dma_buf *dma_buf) |
581 | { |
582 | struct mtk_drm_private *private = dev->dev_private; |
583 | |
584 | return drm_gem_prime_import_dev(dev, dma_buf, attach_dev: private->dma_dev); |
585 | } |
586 | |
587 | static const struct drm_driver mtk_drm_driver = { |
588 | .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC, |
589 | |
590 | .dumb_create = mtk_drm_gem_dumb_create, |
591 | |
592 | .gem_prime_import = mtk_drm_gem_prime_import, |
593 | .gem_prime_import_sg_table = mtk_gem_prime_import_sg_table, |
594 | .fops = &mtk_drm_fops, |
595 | |
596 | .name = DRIVER_NAME, |
597 | .desc = DRIVER_DESC, |
598 | .date = DRIVER_DATE, |
599 | .major = DRIVER_MAJOR, |
600 | .minor = DRIVER_MINOR, |
601 | }; |
602 | |
603 | static int compare_dev(struct device *dev, void *data) |
604 | { |
605 | return dev == (struct device *)data; |
606 | } |
607 | |
608 | static int mtk_drm_bind(struct device *dev) |
609 | { |
610 | struct mtk_drm_private *private = dev_get_drvdata(dev); |
611 | struct platform_device *pdev; |
612 | struct drm_device *drm; |
613 | int ret, i; |
614 | |
615 | pdev = of_find_device_by_node(np: private->mutex_node); |
616 | if (!pdev) { |
617 | dev_err(dev, "Waiting for disp-mutex device %pOF\n" , |
618 | private->mutex_node); |
619 | of_node_put(node: private->mutex_node); |
620 | return -EPROBE_DEFER; |
621 | } |
622 | |
623 | private->mutex_dev = &pdev->dev; |
624 | private->mtk_drm_bound = true; |
625 | private->dev = dev; |
626 | |
627 | if (!mtk_drm_get_all_drm_priv(dev)) |
628 | return 0; |
629 | |
630 | drm = drm_dev_alloc(driver: &mtk_drm_driver, parent: dev); |
631 | if (IS_ERR(ptr: drm)) |
632 | return PTR_ERR(ptr: drm); |
633 | |
634 | private->drm_master = true; |
635 | drm->dev_private = private; |
636 | for (i = 0; i < private->data->mmsys_dev_num; i++) |
637 | private->all_drm_private[i]->drm = drm; |
638 | |
639 | ret = mtk_drm_kms_init(drm); |
640 | if (ret < 0) |
641 | goto err_free; |
642 | |
643 | ret = drm_dev_register(dev: drm, flags: 0); |
644 | if (ret < 0) |
645 | goto err_deinit; |
646 | |
647 | drm_fbdev_generic_setup(dev: drm, preferred_bpp: 32); |
648 | |
649 | return 0; |
650 | |
651 | err_deinit: |
652 | mtk_drm_kms_deinit(drm); |
653 | err_free: |
654 | private->drm = NULL; |
655 | drm_dev_put(dev: drm); |
656 | return ret; |
657 | } |
658 | |
659 | static void mtk_drm_unbind(struct device *dev) |
660 | { |
661 | struct mtk_drm_private *private = dev_get_drvdata(dev); |
662 | |
663 | /* for multi mmsys dev, unregister drm dev in mmsys master */ |
664 | if (private->drm_master) { |
665 | drm_dev_unregister(dev: private->drm); |
666 | mtk_drm_kms_deinit(drm: private->drm); |
667 | drm_dev_put(dev: private->drm); |
668 | } |
669 | private->mtk_drm_bound = false; |
670 | private->drm_master = false; |
671 | private->drm = NULL; |
672 | } |
673 | |
674 | static const struct component_master_ops mtk_drm_ops = { |
675 | .bind = mtk_drm_bind, |
676 | .unbind = mtk_drm_unbind, |
677 | }; |
678 | |
679 | static const struct of_device_id mtk_ddp_comp_dt_ids[] = { |
680 | { .compatible = "mediatek,mt8167-disp-aal" , |
681 | .data = (void *)MTK_DISP_AAL}, |
682 | { .compatible = "mediatek,mt8173-disp-aal" , |
683 | .data = (void *)MTK_DISP_AAL}, |
684 | { .compatible = "mediatek,mt8183-disp-aal" , |
685 | .data = (void *)MTK_DISP_AAL}, |
686 | { .compatible = "mediatek,mt8192-disp-aal" , |
687 | .data = (void *)MTK_DISP_AAL}, |
688 | { .compatible = "mediatek,mt8167-disp-ccorr" , |
689 | .data = (void *)MTK_DISP_CCORR }, |
690 | { .compatible = "mediatek,mt8183-disp-ccorr" , |
691 | .data = (void *)MTK_DISP_CCORR }, |
692 | { .compatible = "mediatek,mt8192-disp-ccorr" , |
693 | .data = (void *)MTK_DISP_CCORR }, |
694 | { .compatible = "mediatek,mt2701-disp-color" , |
695 | .data = (void *)MTK_DISP_COLOR }, |
696 | { .compatible = "mediatek,mt8167-disp-color" , |
697 | .data = (void *)MTK_DISP_COLOR }, |
698 | { .compatible = "mediatek,mt8173-disp-color" , |
699 | .data = (void *)MTK_DISP_COLOR }, |
700 | { .compatible = "mediatek,mt8167-disp-dither" , |
701 | .data = (void *)MTK_DISP_DITHER }, |
702 | { .compatible = "mediatek,mt8183-disp-dither" , |
703 | .data = (void *)MTK_DISP_DITHER }, |
704 | { .compatible = "mediatek,mt8195-disp-dsc" , |
705 | .data = (void *)MTK_DISP_DSC }, |
706 | { .compatible = "mediatek,mt8167-disp-gamma" , |
707 | .data = (void *)MTK_DISP_GAMMA, }, |
708 | { .compatible = "mediatek,mt8173-disp-gamma" , |
709 | .data = (void *)MTK_DISP_GAMMA, }, |
710 | { .compatible = "mediatek,mt8183-disp-gamma" , |
711 | .data = (void *)MTK_DISP_GAMMA, }, |
712 | { .compatible = "mediatek,mt8195-disp-merge" , |
713 | .data = (void *)MTK_DISP_MERGE }, |
714 | { .compatible = "mediatek,mt2701-disp-mutex" , |
715 | .data = (void *)MTK_DISP_MUTEX }, |
716 | { .compatible = "mediatek,mt2712-disp-mutex" , |
717 | .data = (void *)MTK_DISP_MUTEX }, |
718 | { .compatible = "mediatek,mt8167-disp-mutex" , |
719 | .data = (void *)MTK_DISP_MUTEX }, |
720 | { .compatible = "mediatek,mt8173-disp-mutex" , |
721 | .data = (void *)MTK_DISP_MUTEX }, |
722 | { .compatible = "mediatek,mt8183-disp-mutex" , |
723 | .data = (void *)MTK_DISP_MUTEX }, |
724 | { .compatible = "mediatek,mt8186-disp-mutex" , |
725 | .data = (void *)MTK_DISP_MUTEX }, |
726 | { .compatible = "mediatek,mt8188-disp-mutex" , |
727 | .data = (void *)MTK_DISP_MUTEX }, |
728 | { .compatible = "mediatek,mt8192-disp-mutex" , |
729 | .data = (void *)MTK_DISP_MUTEX }, |
730 | { .compatible = "mediatek,mt8195-disp-mutex" , |
731 | .data = (void *)MTK_DISP_MUTEX }, |
732 | { .compatible = "mediatek,mt8173-disp-od" , |
733 | .data = (void *)MTK_DISP_OD }, |
734 | { .compatible = "mediatek,mt2701-disp-ovl" , |
735 | .data = (void *)MTK_DISP_OVL }, |
736 | { .compatible = "mediatek,mt8167-disp-ovl" , |
737 | .data = (void *)MTK_DISP_OVL }, |
738 | { .compatible = "mediatek,mt8173-disp-ovl" , |
739 | .data = (void *)MTK_DISP_OVL }, |
740 | { .compatible = "mediatek,mt8183-disp-ovl" , |
741 | .data = (void *)MTK_DISP_OVL }, |
742 | { .compatible = "mediatek,mt8192-disp-ovl" , |
743 | .data = (void *)MTK_DISP_OVL }, |
744 | { .compatible = "mediatek,mt8183-disp-ovl-2l" , |
745 | .data = (void *)MTK_DISP_OVL_2L }, |
746 | { .compatible = "mediatek,mt8192-disp-ovl-2l" , |
747 | .data = (void *)MTK_DISP_OVL_2L }, |
748 | { .compatible = "mediatek,mt8192-disp-postmask" , |
749 | .data = (void *)MTK_DISP_POSTMASK }, |
750 | { .compatible = "mediatek,mt2701-disp-pwm" , |
751 | .data = (void *)MTK_DISP_BLS }, |
752 | { .compatible = "mediatek,mt8167-disp-pwm" , |
753 | .data = (void *)MTK_DISP_PWM }, |
754 | { .compatible = "mediatek,mt8173-disp-pwm" , |
755 | .data = (void *)MTK_DISP_PWM }, |
756 | { .compatible = "mediatek,mt2701-disp-rdma" , |
757 | .data = (void *)MTK_DISP_RDMA }, |
758 | { .compatible = "mediatek,mt8167-disp-rdma" , |
759 | .data = (void *)MTK_DISP_RDMA }, |
760 | { .compatible = "mediatek,mt8173-disp-rdma" , |
761 | .data = (void *)MTK_DISP_RDMA }, |
762 | { .compatible = "mediatek,mt8183-disp-rdma" , |
763 | .data = (void *)MTK_DISP_RDMA }, |
764 | { .compatible = "mediatek,mt8195-disp-rdma" , |
765 | .data = (void *)MTK_DISP_RDMA }, |
766 | { .compatible = "mediatek,mt8173-disp-ufoe" , |
767 | .data = (void *)MTK_DISP_UFOE }, |
768 | { .compatible = "mediatek,mt8173-disp-wdma" , |
769 | .data = (void *)MTK_DISP_WDMA }, |
770 | { .compatible = "mediatek,mt2701-dpi" , |
771 | .data = (void *)MTK_DPI }, |
772 | { .compatible = "mediatek,mt8167-dsi" , |
773 | .data = (void *)MTK_DSI }, |
774 | { .compatible = "mediatek,mt8173-dpi" , |
775 | .data = (void *)MTK_DPI }, |
776 | { .compatible = "mediatek,mt8183-dpi" , |
777 | .data = (void *)MTK_DPI }, |
778 | { .compatible = "mediatek,mt8186-dpi" , |
779 | .data = (void *)MTK_DPI }, |
780 | { .compatible = "mediatek,mt8188-dp-intf" , |
781 | .data = (void *)MTK_DP_INTF }, |
782 | { .compatible = "mediatek,mt8192-dpi" , |
783 | .data = (void *)MTK_DPI }, |
784 | { .compatible = "mediatek,mt8195-dp-intf" , |
785 | .data = (void *)MTK_DP_INTF }, |
786 | { .compatible = "mediatek,mt2701-dsi" , |
787 | .data = (void *)MTK_DSI }, |
788 | { .compatible = "mediatek,mt8173-dsi" , |
789 | .data = (void *)MTK_DSI }, |
790 | { .compatible = "mediatek,mt8183-dsi" , |
791 | .data = (void *)MTK_DSI }, |
792 | { .compatible = "mediatek,mt8186-dsi" , |
793 | .data = (void *)MTK_DSI }, |
794 | { .compatible = "mediatek,mt8188-dsi" , |
795 | .data = (void *)MTK_DSI }, |
796 | { } |
797 | }; |
798 | |
799 | static int mtk_drm_probe(struct platform_device *pdev) |
800 | { |
801 | struct device *dev = &pdev->dev; |
802 | struct device_node *phandle = dev->parent->of_node; |
803 | const struct of_device_id *of_id; |
804 | struct mtk_drm_private *private; |
805 | struct device_node *node; |
806 | struct component_match *match = NULL; |
807 | struct platform_device *ovl_adaptor; |
808 | int ret; |
809 | int i; |
810 | |
811 | private = devm_kzalloc(dev, size: sizeof(*private), GFP_KERNEL); |
812 | if (!private) |
813 | return -ENOMEM; |
814 | |
815 | private->mmsys_dev = dev->parent; |
816 | if (!private->mmsys_dev) { |
817 | dev_err(dev, "Failed to get MMSYS device\n" ); |
818 | return -ENODEV; |
819 | } |
820 | |
821 | of_id = of_match_node(matches: mtk_drm_of_ids, node: phandle); |
822 | if (!of_id) |
823 | return -ENODEV; |
824 | |
825 | private->data = of_id->data; |
826 | |
827 | private->all_drm_private = devm_kmalloc_array(dev, n: private->data->mmsys_dev_num, |
828 | size: sizeof(*private->all_drm_private), |
829 | GFP_KERNEL); |
830 | if (!private->all_drm_private) |
831 | return -ENOMEM; |
832 | |
833 | /* Bringup ovl_adaptor */ |
834 | if (mtk_drm_find_mmsys_comp(private, DDP_COMPONENT_DRM_OVL_ADAPTOR)) { |
835 | ovl_adaptor = platform_device_register_data(parent: dev, name: "mediatek-disp-ovl-adaptor" , |
836 | PLATFORM_DEVID_AUTO, |
837 | data: (void *)private->mmsys_dev, |
838 | size: sizeof(*private->mmsys_dev)); |
839 | private->ddp_comp[DDP_COMPONENT_DRM_OVL_ADAPTOR].dev = &ovl_adaptor->dev; |
840 | mtk_ddp_comp_init(NULL, comp: &private->ddp_comp[DDP_COMPONENT_DRM_OVL_ADAPTOR], |
841 | DDP_COMPONENT_DRM_OVL_ADAPTOR); |
842 | component_match_add(parent: dev, matchptr: &match, compare: compare_dev, compare_data: &ovl_adaptor->dev); |
843 | } |
844 | |
845 | /* Iterate over sibling DISP function blocks */ |
846 | for_each_child_of_node(phandle->parent, node) { |
847 | const struct of_device_id *of_id; |
848 | enum mtk_ddp_comp_type comp_type; |
849 | int comp_id; |
850 | |
851 | of_id = of_match_node(matches: mtk_ddp_comp_dt_ids, node); |
852 | if (!of_id) |
853 | continue; |
854 | |
855 | if (!of_device_is_available(device: node)) { |
856 | dev_dbg(dev, "Skipping disabled component %pOF\n" , |
857 | node); |
858 | continue; |
859 | } |
860 | |
861 | comp_type = (enum mtk_ddp_comp_type)(uintptr_t)of_id->data; |
862 | |
863 | if (comp_type == MTK_DISP_MUTEX) { |
864 | int id; |
865 | |
866 | id = of_alias_get_id(np: node, stem: "mutex" ); |
867 | if (id < 0 || id == private->data->mmsys_id) { |
868 | private->mutex_node = of_node_get(node); |
869 | dev_dbg(dev, "get mutex for mmsys %d" , private->data->mmsys_id); |
870 | } |
871 | continue; |
872 | } |
873 | |
874 | comp_id = mtk_ddp_comp_get_id(node, comp_type); |
875 | if (comp_id < 0) { |
876 | dev_warn(dev, "Skipping unknown component %pOF\n" , |
877 | node); |
878 | continue; |
879 | } |
880 | |
881 | if (!mtk_drm_find_mmsys_comp(private, comp_id)) |
882 | continue; |
883 | |
884 | private->comp_node[comp_id] = of_node_get(node); |
885 | |
886 | /* |
887 | * Currently only the AAL, CCORR, COLOR, GAMMA, MERGE, OVL, RDMA, DSI, and DPI |
888 | * blocks have separate component platform drivers and initialize their own |
889 | * DDP component structure. The others are initialized here. |
890 | */ |
891 | if (comp_type == MTK_DISP_AAL || |
892 | comp_type == MTK_DISP_CCORR || |
893 | comp_type == MTK_DISP_COLOR || |
894 | comp_type == MTK_DISP_GAMMA || |
895 | comp_type == MTK_DISP_MERGE || |
896 | comp_type == MTK_DISP_OVL || |
897 | comp_type == MTK_DISP_OVL_2L || |
898 | comp_type == MTK_DISP_OVL_ADAPTOR || |
899 | comp_type == MTK_DISP_RDMA || |
900 | comp_type == MTK_DP_INTF || |
901 | comp_type == MTK_DPI || |
902 | comp_type == MTK_DSI) { |
903 | dev_info(dev, "Adding component match for %pOF\n" , |
904 | node); |
905 | drm_of_component_match_add(master: dev, matchptr: &match, compare: component_compare_of, |
906 | node); |
907 | } |
908 | |
909 | ret = mtk_ddp_comp_init(comp_node: node, comp: &private->ddp_comp[comp_id], comp_id); |
910 | if (ret) { |
911 | of_node_put(node); |
912 | goto err_node; |
913 | } |
914 | } |
915 | |
916 | if (!private->mutex_node) { |
917 | dev_err(dev, "Failed to find disp-mutex node\n" ); |
918 | ret = -ENODEV; |
919 | goto err_node; |
920 | } |
921 | |
922 | pm_runtime_enable(dev); |
923 | |
924 | platform_set_drvdata(pdev, data: private); |
925 | |
926 | ret = component_master_add_with_match(dev, &mtk_drm_ops, match); |
927 | if (ret) |
928 | goto err_pm; |
929 | |
930 | return 0; |
931 | |
932 | err_pm: |
933 | pm_runtime_disable(dev); |
934 | err_node: |
935 | of_node_put(node: private->mutex_node); |
936 | for (i = 0; i < DDP_COMPONENT_DRM_ID_MAX; i++) |
937 | of_node_put(node: private->comp_node[i]); |
938 | return ret; |
939 | } |
940 | |
941 | static void mtk_drm_remove(struct platform_device *pdev) |
942 | { |
943 | struct mtk_drm_private *private = platform_get_drvdata(pdev); |
944 | int i; |
945 | |
946 | component_master_del(&pdev->dev, &mtk_drm_ops); |
947 | pm_runtime_disable(dev: &pdev->dev); |
948 | of_node_put(node: private->mutex_node); |
949 | for (i = 0; i < DDP_COMPONENT_DRM_ID_MAX; i++) |
950 | of_node_put(node: private->comp_node[i]); |
951 | } |
952 | |
953 | static int mtk_drm_sys_prepare(struct device *dev) |
954 | { |
955 | struct mtk_drm_private *private = dev_get_drvdata(dev); |
956 | struct drm_device *drm = private->drm; |
957 | |
958 | if (private->drm_master) |
959 | return drm_mode_config_helper_suspend(dev: drm); |
960 | else |
961 | return 0; |
962 | } |
963 | |
964 | static void mtk_drm_sys_complete(struct device *dev) |
965 | { |
966 | struct mtk_drm_private *private = dev_get_drvdata(dev); |
967 | struct drm_device *drm = private->drm; |
968 | int ret = 0; |
969 | |
970 | if (private->drm_master) |
971 | ret = drm_mode_config_helper_resume(dev: drm); |
972 | if (ret) |
973 | dev_err(dev, "Failed to resume\n" ); |
974 | } |
975 | |
976 | static const struct dev_pm_ops mtk_drm_pm_ops = { |
977 | .prepare = mtk_drm_sys_prepare, |
978 | .complete = mtk_drm_sys_complete, |
979 | }; |
980 | |
981 | static struct platform_driver mtk_drm_platform_driver = { |
982 | .probe = mtk_drm_probe, |
983 | .remove_new = mtk_drm_remove, |
984 | .driver = { |
985 | .name = "mediatek-drm" , |
986 | .pm = &mtk_drm_pm_ops, |
987 | }, |
988 | }; |
989 | |
990 | static struct platform_driver * const mtk_drm_drivers[] = { |
991 | &mtk_disp_aal_driver, |
992 | &mtk_disp_ccorr_driver, |
993 | &mtk_disp_color_driver, |
994 | &mtk_disp_gamma_driver, |
995 | &mtk_disp_merge_driver, |
996 | &mtk_disp_ovl_adaptor_driver, |
997 | &mtk_disp_ovl_driver, |
998 | &mtk_disp_rdma_driver, |
999 | &mtk_dpi_driver, |
1000 | &mtk_drm_platform_driver, |
1001 | &mtk_dsi_driver, |
1002 | &mtk_ethdr_driver, |
1003 | &mtk_mdp_rdma_driver, |
1004 | &mtk_padding_driver, |
1005 | }; |
1006 | |
1007 | static int __init mtk_drm_init(void) |
1008 | { |
1009 | return platform_register_drivers(mtk_drm_drivers, |
1010 | ARRAY_SIZE(mtk_drm_drivers)); |
1011 | } |
1012 | |
1013 | static void __exit mtk_drm_exit(void) |
1014 | { |
1015 | platform_unregister_drivers(drivers: mtk_drm_drivers, |
1016 | ARRAY_SIZE(mtk_drm_drivers)); |
1017 | } |
1018 | |
1019 | module_init(mtk_drm_init); |
1020 | module_exit(mtk_drm_exit); |
1021 | |
1022 | MODULE_AUTHOR("YT SHEN <yt.shen@mediatek.com>" ); |
1023 | MODULE_DESCRIPTION("Mediatek SoC DRM driver" ); |
1024 | MODULE_LICENSE("GPL v2" ); |
1025 | |