1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2021 MediaTek Inc.
6 #include <drm/drm_fourcc.h>
7 #include <drm/drm_of.h>
9 #include <linux/component.h>
11 #include <linux/of_address.h>
12 #include <linux/of_platform.h>
13 #include <linux/platform_device.h>
14 #include <linux/pm_runtime.h>
15 #include <linux/reset.h>
16 #include <linux/soc/mediatek/mtk-cmdq.h>
17 #include <linux/soc/mediatek/mtk-mmsys.h>
18 #include <linux/soc/mediatek/mtk-mutex.h>
20 #include "mtk_ddp_comp.h"
21 #include "mtk_disp_drv.h"
22 #include "mtk_drm_drv.h"
23 #include "mtk_ethdr.h"
25 #define MTK_OVL_ADAPTOR_RDMA_MAX_WIDTH 1920
26 #define MTK_OVL_ADAPTOR_LAYER_NUM 4
28 enum mtk_ovl_adaptor_comp_type
{
29 OVL_ADAPTOR_TYPE_ETHDR
,
30 OVL_ADAPTOR_TYPE_MDP_RDMA
,
31 OVL_ADAPTOR_TYPE_MERGE
,
32 OVL_ADAPTOR_TYPE_PADDING
,
36 enum mtk_ovl_adaptor_comp_id
{
38 OVL_ADAPTOR_MDP_RDMA0
,
39 OVL_ADAPTOR_MDP_RDMA1
,
40 OVL_ADAPTOR_MDP_RDMA2
,
41 OVL_ADAPTOR_MDP_RDMA3
,
42 OVL_ADAPTOR_MDP_RDMA4
,
43 OVL_ADAPTOR_MDP_RDMA5
,
44 OVL_ADAPTOR_MDP_RDMA6
,
45 OVL_ADAPTOR_MDP_RDMA7
,
61 struct ovl_adaptor_comp_match
{
62 enum mtk_ovl_adaptor_comp_type type
;
63 enum mtk_ddp_comp_id comp_id
;
65 const struct mtk_ddp_comp_funcs
*funcs
;
68 struct mtk_disp_ovl_adaptor
{
69 struct device
*ovl_adaptor_comp
[OVL_ADAPTOR_ID_MAX
];
70 struct device
*mmsys_dev
;
74 static const char * const private_comp_stem
[OVL_ADAPTOR_TYPE_NUM
] = {
75 [OVL_ADAPTOR_TYPE_ETHDR
] = "ethdr",
76 [OVL_ADAPTOR_TYPE_MDP_RDMA
] = "vdo1-rdma",
77 [OVL_ADAPTOR_TYPE_MERGE
] = "merge",
78 [OVL_ADAPTOR_TYPE_PADDING
] = "padding",
81 static const struct mtk_ddp_comp_funcs ethdr
= {
82 .clk_enable
= mtk_ethdr_clk_enable
,
83 .clk_disable
= mtk_ethdr_clk_disable
,
84 .start
= mtk_ethdr_start
,
85 .stop
= mtk_ethdr_stop
,
88 static const struct mtk_ddp_comp_funcs merge
= {
89 .clk_enable
= mtk_merge_clk_enable
,
90 .clk_disable
= mtk_merge_clk_disable
,
91 .mode_valid
= mtk_merge_mode_valid
,
94 static const struct mtk_ddp_comp_funcs padding
= {
95 .clk_enable
= mtk_padding_clk_enable
,
96 .clk_disable
= mtk_padding_clk_disable
,
97 .start
= mtk_padding_start
,
98 .stop
= mtk_padding_stop
,
101 static const struct mtk_ddp_comp_funcs rdma
= {
102 .power_on
= mtk_mdp_rdma_power_on
,
103 .power_off
= mtk_mdp_rdma_power_off
,
104 .clk_enable
= mtk_mdp_rdma_clk_enable
,
105 .clk_disable
= mtk_mdp_rdma_clk_disable
,
108 static const struct ovl_adaptor_comp_match comp_matches
[OVL_ADAPTOR_ID_MAX
] = {
109 [OVL_ADAPTOR_ETHDR0
] = { OVL_ADAPTOR_TYPE_ETHDR
, DDP_COMPONENT_ETHDR_MIXER
, 0, ðdr
},
110 [OVL_ADAPTOR_MDP_RDMA0
] = { OVL_ADAPTOR_TYPE_MDP_RDMA
, DDP_COMPONENT_MDP_RDMA0
, 0, &rdma
},
111 [OVL_ADAPTOR_MDP_RDMA1
] = { OVL_ADAPTOR_TYPE_MDP_RDMA
, DDP_COMPONENT_MDP_RDMA1
, 1, &rdma
},
112 [OVL_ADAPTOR_MDP_RDMA2
] = { OVL_ADAPTOR_TYPE_MDP_RDMA
, DDP_COMPONENT_MDP_RDMA2
, 2, &rdma
},
113 [OVL_ADAPTOR_MDP_RDMA3
] = { OVL_ADAPTOR_TYPE_MDP_RDMA
, DDP_COMPONENT_MDP_RDMA3
, 3, &rdma
},
114 [OVL_ADAPTOR_MDP_RDMA4
] = { OVL_ADAPTOR_TYPE_MDP_RDMA
, DDP_COMPONENT_MDP_RDMA4
, 4, &rdma
},
115 [OVL_ADAPTOR_MDP_RDMA5
] = { OVL_ADAPTOR_TYPE_MDP_RDMA
, DDP_COMPONENT_MDP_RDMA5
, 5, &rdma
},
116 [OVL_ADAPTOR_MDP_RDMA6
] = { OVL_ADAPTOR_TYPE_MDP_RDMA
, DDP_COMPONENT_MDP_RDMA6
, 6, &rdma
},
117 [OVL_ADAPTOR_MDP_RDMA7
] = { OVL_ADAPTOR_TYPE_MDP_RDMA
, DDP_COMPONENT_MDP_RDMA7
, 7, &rdma
},
118 [OVL_ADAPTOR_MERGE0
] = { OVL_ADAPTOR_TYPE_MERGE
, DDP_COMPONENT_MERGE1
, 1, &merge
},
119 [OVL_ADAPTOR_MERGE1
] = { OVL_ADAPTOR_TYPE_MERGE
, DDP_COMPONENT_MERGE2
, 2, &merge
},
120 [OVL_ADAPTOR_MERGE2
] = { OVL_ADAPTOR_TYPE_MERGE
, DDP_COMPONENT_MERGE3
, 3, &merge
},
121 [OVL_ADAPTOR_MERGE3
] = { OVL_ADAPTOR_TYPE_MERGE
, DDP_COMPONENT_MERGE4
, 4, &merge
},
122 [OVL_ADAPTOR_PADDING0
] = { OVL_ADAPTOR_TYPE_PADDING
, DDP_COMPONENT_PADDING0
, 0, &padding
},
123 [OVL_ADAPTOR_PADDING1
] = { OVL_ADAPTOR_TYPE_PADDING
, DDP_COMPONENT_PADDING1
, 1, &padding
},
124 [OVL_ADAPTOR_PADDING2
] = { OVL_ADAPTOR_TYPE_PADDING
, DDP_COMPONENT_PADDING2
, 2, &padding
},
125 [OVL_ADAPTOR_PADDING3
] = { OVL_ADAPTOR_TYPE_PADDING
, DDP_COMPONENT_PADDING3
, 3, &padding
},
126 [OVL_ADAPTOR_PADDING4
] = { OVL_ADAPTOR_TYPE_PADDING
, DDP_COMPONENT_PADDING4
, 4, &padding
},
127 [OVL_ADAPTOR_PADDING5
] = { OVL_ADAPTOR_TYPE_PADDING
, DDP_COMPONENT_PADDING5
, 5, &padding
},
128 [OVL_ADAPTOR_PADDING6
] = { OVL_ADAPTOR_TYPE_PADDING
, DDP_COMPONENT_PADDING6
, 6, &padding
},
129 [OVL_ADAPTOR_PADDING7
] = { OVL_ADAPTOR_TYPE_PADDING
, DDP_COMPONENT_PADDING7
, 7, &padding
},
132 void mtk_ovl_adaptor_layer_config(struct device
*dev
, unsigned int idx
,
133 struct mtk_plane_state
*state
,
134 struct cmdq_pkt
*cmdq_pkt
)
136 struct mtk_disp_ovl_adaptor
*ovl_adaptor
= dev_get_drvdata(dev
);
137 struct mtk_plane_pending_state
*pending
= &state
->pending
;
138 struct mtk_mdp_rdma_cfg rdma_config
= {0};
139 struct device
*rdma_l
;
140 struct device
*rdma_r
;
141 struct device
*merge
;
142 struct device
*ethdr
;
143 const struct drm_format_info
*fmt_info
= drm_format_info(pending
->format
);
144 bool use_dual_pipe
= false;
145 unsigned int align_width
;
146 unsigned int l_w
= 0;
147 unsigned int r_w
= 0;
149 dev_dbg(dev
, "%s+ idx:%d, enable:%d, fmt:0x%x\n", __func__
, idx
,
150 pending
->enable
, pending
->format
);
151 dev_dbg(dev
, "addr 0x%pad, fb w:%d, {%d,%d,%d,%d}\n",
152 &pending
->addr
, (pending
->pitch
/ fmt_info
->cpp
[0]),
153 pending
->x
, pending
->y
, pending
->width
, pending
->height
);
155 rdma_l
= ovl_adaptor
->ovl_adaptor_comp
[OVL_ADAPTOR_MDP_RDMA0
+ 2 * idx
];
156 rdma_r
= ovl_adaptor
->ovl_adaptor_comp
[OVL_ADAPTOR_MDP_RDMA0
+ 2 * idx
+ 1];
157 merge
= ovl_adaptor
->ovl_adaptor_comp
[OVL_ADAPTOR_MERGE0
+ idx
];
158 ethdr
= ovl_adaptor
->ovl_adaptor_comp
[OVL_ADAPTOR_ETHDR0
];
160 if (!pending
->enable
|| !pending
->width
|| !pending
->height
) {
161 mtk_merge_stop_cmdq(merge
, cmdq_pkt
);
162 mtk_mdp_rdma_stop(rdma_l
, cmdq_pkt
);
163 mtk_mdp_rdma_stop(rdma_r
, cmdq_pkt
);
164 mtk_ethdr_layer_config(ethdr
, idx
, state
, cmdq_pkt
);
168 /* ETHDR is in 1T2P domain, width needs to be 2 pixels align */
169 align_width
= ALIGN_DOWN(pending
->width
, 2);
171 if (align_width
> MTK_OVL_ADAPTOR_RDMA_MAX_WIDTH
)
172 use_dual_pipe
= true;
175 l_w
= (align_width
/ 2) + ((pending
->width
/ 2) % 2);
176 r_w
= align_width
- l_w
;
180 mtk_merge_advance_config(merge
, l_w
, r_w
, pending
->height
, 0, 0, cmdq_pkt
);
181 mtk_mmsys_merge_async_config(ovl_adaptor
->mmsys_dev
, idx
, align_width
/ 2,
182 pending
->height
, cmdq_pkt
);
184 rdma_config
.width
= l_w
;
185 rdma_config
.height
= pending
->height
;
186 rdma_config
.addr0
= pending
->addr
;
187 rdma_config
.pitch
= pending
->pitch
;
188 rdma_config
.fmt
= pending
->format
;
189 rdma_config
.color_encoding
= pending
->color_encoding
;
190 mtk_mdp_rdma_config(rdma_l
, &rdma_config
, cmdq_pkt
);
193 rdma_config
.x_left
= l_w
;
194 rdma_config
.width
= r_w
;
195 mtk_mdp_rdma_config(rdma_r
, &rdma_config
, cmdq_pkt
);
198 mtk_merge_start_cmdq(merge
, cmdq_pkt
);
200 mtk_mdp_rdma_start(rdma_l
, cmdq_pkt
);
202 mtk_mdp_rdma_start(rdma_r
, cmdq_pkt
);
204 mtk_mdp_rdma_stop(rdma_r
, cmdq_pkt
);
206 mtk_ethdr_layer_config(ethdr
, idx
, state
, cmdq_pkt
);
209 void mtk_ovl_adaptor_config(struct device
*dev
, unsigned int w
,
210 unsigned int h
, unsigned int vrefresh
,
211 unsigned int bpc
, struct cmdq_pkt
*cmdq_pkt
)
213 struct mtk_disp_ovl_adaptor
*ovl_adaptor
= dev_get_drvdata(dev
);
215 mtk_ethdr_config(ovl_adaptor
->ovl_adaptor_comp
[OVL_ADAPTOR_ETHDR0
], w
, h
,
216 vrefresh
, bpc
, cmdq_pkt
);
219 void mtk_ovl_adaptor_start(struct device
*dev
)
222 struct mtk_disp_ovl_adaptor
*ovl_adaptor
= dev_get_drvdata(dev
);
224 for (i
= 0; i
< OVL_ADAPTOR_ID_MAX
; i
++) {
225 if (!ovl_adaptor
->ovl_adaptor_comp
[i
] ||
226 !comp_matches
[i
].funcs
->start
)
229 comp_matches
[i
].funcs
->start(ovl_adaptor
->ovl_adaptor_comp
[i
]);
233 void mtk_ovl_adaptor_stop(struct device
*dev
)
236 struct mtk_disp_ovl_adaptor
*ovl_adaptor
= dev_get_drvdata(dev
);
238 for (i
= 0; i
< OVL_ADAPTOR_ID_MAX
; i
++) {
239 if (!ovl_adaptor
->ovl_adaptor_comp
[i
] ||
240 !comp_matches
[i
].funcs
->stop
)
243 comp_matches
[i
].funcs
->stop(ovl_adaptor
->ovl_adaptor_comp
[i
]);
248 * power_off - Power off the devices in OVL adaptor
249 * @dev: Device to be powered off
250 * @num: Number of the devices to be powered off
252 * Calls the .power_off() ovl_adaptor component callback if it is present.
254 static inline void power_off(struct device
*dev
, int num
)
256 struct mtk_disp_ovl_adaptor
*ovl_adaptor
= dev_get_drvdata(dev
);
259 if (num
> OVL_ADAPTOR_ID_MAX
)
260 num
= OVL_ADAPTOR_ID_MAX
;
262 for (i
= num
- 1; i
>= 0; i
--) {
263 if (!ovl_adaptor
->ovl_adaptor_comp
[i
] ||
264 !comp_matches
[i
].funcs
->power_off
)
267 comp_matches
[i
].funcs
->power_off(ovl_adaptor
->ovl_adaptor_comp
[i
]);
272 * mtk_ovl_adaptor_power_on - Power on the devices in OVL adaptor
273 * @dev: Device to be powered on
275 * Different from OVL, OVL adaptor is a pseudo device so
276 * we didn't define it in the device tree, pm_runtime_resume_and_get()
277 * called by .atomic_enable() power on no device in OVL adaptor,
278 * we have to implement a function to do the job instead.
280 * Return: Zero for success or negative number for failure.
282 int mtk_ovl_adaptor_power_on(struct device
*dev
)
284 struct mtk_disp_ovl_adaptor
*ovl_adaptor
= dev_get_drvdata(dev
);
287 for (i
= 0; i
< OVL_ADAPTOR_ID_MAX
; i
++) {
288 if (!ovl_adaptor
->ovl_adaptor_comp
[i
] ||
289 !comp_matches
[i
].funcs
->power_on
)
292 ret
= comp_matches
[i
].funcs
->power_on(ovl_adaptor
->ovl_adaptor_comp
[i
]);
294 dev_err(dev
, "Failed to enable power domain %d, err %d\n", i
, ret
);
302 void mtk_ovl_adaptor_power_off(struct device
*dev
)
304 power_off(dev
, OVL_ADAPTOR_ID_MAX
);
307 int mtk_ovl_adaptor_clk_enable(struct device
*dev
)
309 struct mtk_disp_ovl_adaptor
*ovl_adaptor
= dev_get_drvdata(dev
);
314 for (i
= 0; i
< OVL_ADAPTOR_ID_MAX
; i
++) {
315 comp
= ovl_adaptor
->ovl_adaptor_comp
[i
];
316 if (!comp
|| !comp_matches
[i
].funcs
->clk_enable
)
318 ret
= comp_matches
[i
].funcs
->clk_enable(comp
);
320 dev_err(dev
, "Failed to enable clock %d, err %d\n", i
, ret
);
322 comp_matches
[i
].funcs
->clk_disable(comp
);
329 void mtk_ovl_adaptor_clk_disable(struct device
*dev
)
331 struct mtk_disp_ovl_adaptor
*ovl_adaptor
= dev_get_drvdata(dev
);
335 for (i
= 0; i
< OVL_ADAPTOR_ID_MAX
; i
++) {
336 comp
= ovl_adaptor
->ovl_adaptor_comp
[i
];
337 if (!comp
|| !comp_matches
[i
].funcs
->clk_disable
)
339 comp_matches
[i
].funcs
->clk_disable(comp
);
340 if (i
< OVL_ADAPTOR_MERGE0
)
341 pm_runtime_put(comp
);
345 enum drm_mode_status
mtk_ovl_adaptor_mode_valid(struct device
*dev
,
346 const struct drm_display_mode
*mode
)
350 struct mtk_disp_ovl_adaptor
*ovl_adaptor
= dev_get_drvdata(dev
);
352 for (i
= 0; i
< OVL_ADAPTOR_ID_MAX
; i
++) {
353 dev
= ovl_adaptor
->ovl_adaptor_comp
[i
];
354 if (!dev
|| !comp_matches
[i
].funcs
->mode_valid
)
356 return comp_matches
[i
].funcs
->mode_valid(dev
, mode
);
361 unsigned int mtk_ovl_adaptor_layer_nr(struct device
*dev
)
363 return MTK_OVL_ADAPTOR_LAYER_NUM
;
366 struct device
*mtk_ovl_adaptor_dma_dev_get(struct device
*dev
)
368 struct mtk_disp_ovl_adaptor
*ovl_adaptor
= dev_get_drvdata(dev
);
370 return ovl_adaptor
->ovl_adaptor_comp
[OVL_ADAPTOR_MDP_RDMA0
];
373 void mtk_ovl_adaptor_register_vblank_cb(struct device
*dev
, void (*vblank_cb
)(void *),
374 void *vblank_cb_data
)
376 struct mtk_disp_ovl_adaptor
*ovl_adaptor
= dev_get_drvdata(dev
);
378 mtk_ethdr_register_vblank_cb(ovl_adaptor
->ovl_adaptor_comp
[OVL_ADAPTOR_ETHDR0
],
379 vblank_cb
, vblank_cb_data
);
382 void mtk_ovl_adaptor_unregister_vblank_cb(struct device
*dev
)
384 struct mtk_disp_ovl_adaptor
*ovl_adaptor
= dev_get_drvdata(dev
);
386 mtk_ethdr_unregister_vblank_cb(ovl_adaptor
->ovl_adaptor_comp
[OVL_ADAPTOR_ETHDR0
]);
389 void mtk_ovl_adaptor_enable_vblank(struct device
*dev
)
391 struct mtk_disp_ovl_adaptor
*ovl_adaptor
= dev_get_drvdata(dev
);
393 mtk_ethdr_enable_vblank(ovl_adaptor
->ovl_adaptor_comp
[OVL_ADAPTOR_ETHDR0
]);
396 void mtk_ovl_adaptor_disable_vblank(struct device
*dev
)
398 struct mtk_disp_ovl_adaptor
*ovl_adaptor
= dev_get_drvdata(dev
);
400 mtk_ethdr_disable_vblank(ovl_adaptor
->ovl_adaptor_comp
[OVL_ADAPTOR_ETHDR0
]);
403 u32
mtk_ovl_adaptor_get_blend_modes(struct device
*dev
)
405 struct mtk_disp_ovl_adaptor
*ovl_adaptor
= dev_get_drvdata(dev
);
407 return mtk_ethdr_get_blend_modes(ovl_adaptor
->ovl_adaptor_comp
[OVL_ADAPTOR_ETHDR0
]);
410 const u32
*mtk_ovl_adaptor_get_formats(struct device
*dev
)
412 struct mtk_disp_ovl_adaptor
*ovl_adaptor
= dev_get_drvdata(dev
);
414 return mtk_mdp_rdma_get_formats(ovl_adaptor
->ovl_adaptor_comp
[OVL_ADAPTOR_MDP_RDMA0
]);
417 size_t mtk_ovl_adaptor_get_num_formats(struct device
*dev
)
419 struct mtk_disp_ovl_adaptor
*ovl_adaptor
= dev_get_drvdata(dev
);
421 return mtk_mdp_rdma_get_num_formats(ovl_adaptor
->ovl_adaptor_comp
[OVL_ADAPTOR_MDP_RDMA0
]);
424 void mtk_ovl_adaptor_add_comp(struct device
*dev
, struct mtk_mutex
*mutex
)
427 struct mtk_disp_ovl_adaptor
*ovl_adaptor
= dev_get_drvdata(dev
);
429 for (i
= 0; i
< OVL_ADAPTOR_ID_MAX
; i
++) {
430 if (!ovl_adaptor
->ovl_adaptor_comp
[i
])
432 mtk_mutex_add_comp(mutex
, comp_matches
[i
].comp_id
);
436 void mtk_ovl_adaptor_remove_comp(struct device
*dev
, struct mtk_mutex
*mutex
)
439 struct mtk_disp_ovl_adaptor
*ovl_adaptor
= dev_get_drvdata(dev
);
441 for (i
= 0; i
< OVL_ADAPTOR_ID_MAX
; i
++) {
442 if (!ovl_adaptor
->ovl_adaptor_comp
[i
])
444 mtk_mutex_remove_comp(mutex
, comp_matches
[i
].comp_id
);
448 void mtk_ovl_adaptor_connect(struct device
*dev
, struct device
*mmsys_dev
, unsigned int next
)
450 mtk_mmsys_ddp_connect(mmsys_dev
, DDP_COMPONENT_ETHDR_MIXER
, next
);
451 mtk_mmsys_ddp_connect(mmsys_dev
, DDP_COMPONENT_MDP_RDMA0
, DDP_COMPONENT_MERGE1
);
452 mtk_mmsys_ddp_connect(mmsys_dev
, DDP_COMPONENT_MDP_RDMA1
, DDP_COMPONENT_MERGE1
);
453 mtk_mmsys_ddp_connect(mmsys_dev
, DDP_COMPONENT_MDP_RDMA2
, DDP_COMPONENT_MERGE2
);
454 mtk_mmsys_ddp_connect(mmsys_dev
, DDP_COMPONENT_MERGE1
, DDP_COMPONENT_ETHDR_MIXER
);
455 mtk_mmsys_ddp_connect(mmsys_dev
, DDP_COMPONENT_MERGE2
, DDP_COMPONENT_ETHDR_MIXER
);
456 mtk_mmsys_ddp_connect(mmsys_dev
, DDP_COMPONENT_MERGE3
, DDP_COMPONENT_ETHDR_MIXER
);
457 mtk_mmsys_ddp_connect(mmsys_dev
, DDP_COMPONENT_MERGE4
, DDP_COMPONENT_ETHDR_MIXER
);
460 void mtk_ovl_adaptor_disconnect(struct device
*dev
, struct device
*mmsys_dev
, unsigned int next
)
462 mtk_mmsys_ddp_disconnect(mmsys_dev
, DDP_COMPONENT_ETHDR_MIXER
, next
);
463 mtk_mmsys_ddp_disconnect(mmsys_dev
, DDP_COMPONENT_MDP_RDMA0
, DDP_COMPONENT_MERGE1
);
464 mtk_mmsys_ddp_disconnect(mmsys_dev
, DDP_COMPONENT_MDP_RDMA1
, DDP_COMPONENT_MERGE1
);
465 mtk_mmsys_ddp_disconnect(mmsys_dev
, DDP_COMPONENT_MDP_RDMA2
, DDP_COMPONENT_MERGE2
);
466 mtk_mmsys_ddp_disconnect(mmsys_dev
, DDP_COMPONENT_MERGE1
, DDP_COMPONENT_ETHDR_MIXER
);
467 mtk_mmsys_ddp_disconnect(mmsys_dev
, DDP_COMPONENT_MERGE2
, DDP_COMPONENT_ETHDR_MIXER
);
468 mtk_mmsys_ddp_disconnect(mmsys_dev
, DDP_COMPONENT_MERGE3
, DDP_COMPONENT_ETHDR_MIXER
);
469 mtk_mmsys_ddp_disconnect(mmsys_dev
, DDP_COMPONENT_MERGE4
, DDP_COMPONENT_ETHDR_MIXER
);
472 static int ovl_adaptor_comp_get_id(struct device
*dev
, struct device_node
*node
,
473 enum mtk_ovl_adaptor_comp_type type
)
475 int alias_id
= of_alias_get_id(node
, private_comp_stem
[type
]);
478 for (i
= 0; i
< ARRAY_SIZE(comp_matches
); i
++)
479 if (comp_matches
[i
].type
== type
&&
480 comp_matches
[i
].alias_id
== alias_id
)
483 dev_warn(dev
, "Failed to get id. type: %d, alias: %d\n", type
, alias_id
);
487 static const struct of_device_id mtk_ovl_adaptor_comp_dt_ids
[] = {
488 { .compatible
= "mediatek,mt8188-disp-padding", .data
= (void *)OVL_ADAPTOR_TYPE_PADDING
},
489 { .compatible
= "mediatek,mt8195-disp-ethdr", .data
= (void *)OVL_ADAPTOR_TYPE_ETHDR
},
490 { .compatible
= "mediatek,mt8195-disp-merge", .data
= (void *)OVL_ADAPTOR_TYPE_MERGE
},
491 { .compatible
= "mediatek,mt8195-vdo1-rdma", .data
= (void *)OVL_ADAPTOR_TYPE_MDP_RDMA
},
495 static int compare_of(struct device
*dev
, void *data
)
497 return dev
->of_node
== data
;
500 static int ovl_adaptor_of_get_ddp_comp_type(struct device_node
*node
,
501 enum mtk_ovl_adaptor_comp_type
*ctype
)
503 const struct of_device_id
*of_id
= of_match_node(mtk_ovl_adaptor_comp_dt_ids
, node
);
508 *ctype
= (enum mtk_ovl_adaptor_comp_type
)((uintptr_t)of_id
->data
);
513 bool mtk_ovl_adaptor_is_comp_present(struct device_node
*node
)
515 enum mtk_ovl_adaptor_comp_type type
;
518 ret
= ovl_adaptor_of_get_ddp_comp_type(node
, &type
);
522 if (type
>= OVL_ADAPTOR_TYPE_NUM
)
526 * In the context of mediatek-drm, ETHDR, MDP_RDMA and Padding are
527 * used exclusively by OVL Adaptor: if this component is not one of
528 * those, it's likely not an OVL Adaptor path.
530 return type
== OVL_ADAPTOR_TYPE_ETHDR
||
531 type
== OVL_ADAPTOR_TYPE_MDP_RDMA
||
532 type
== OVL_ADAPTOR_TYPE_PADDING
;
535 static int ovl_adaptor_comp_init(struct device
*dev
, struct component_match
**match
)
537 struct mtk_disp_ovl_adaptor
*priv
= dev_get_drvdata(dev
);
538 struct device_node
*parent
;
539 struct platform_device
*comp_pdev
;
541 parent
= dev
->parent
->parent
->of_node
->parent
;
543 for_each_child_of_node_scoped(parent
, node
) {
544 enum mtk_ovl_adaptor_comp_type type
;
547 ret
= ovl_adaptor_of_get_ddp_comp_type(node
, &type
);
551 if (!of_device_is_available(node
)) {
552 dev_dbg(dev
, "Skipping disabled component %pOF\n",
557 id
= ovl_adaptor_comp_get_id(dev
, node
, type
);
559 dev_warn(dev
, "Skipping unknown component %pOF\n",
564 comp_pdev
= of_find_device_by_node(node
);
566 return -EPROBE_DEFER
;
568 priv
->ovl_adaptor_comp
[id
] = &comp_pdev
->dev
;
570 drm_of_component_match_add(dev
, match
, compare_of
, node
);
571 dev_dbg(dev
, "Adding component match for %pOF\n", node
);
575 dev_err(dev
, "No match device for ovl_adaptor\n");
582 static int mtk_disp_ovl_adaptor_comp_bind(struct device
*dev
, struct device
*master
,
585 struct mtk_disp_ovl_adaptor
*priv
= dev_get_drvdata(dev
);
587 if (!priv
->children_bound
)
588 return -EPROBE_DEFER
;
593 static void mtk_disp_ovl_adaptor_comp_unbind(struct device
*dev
, struct device
*master
,
598 static const struct component_ops mtk_disp_ovl_adaptor_comp_ops
= {
599 .bind
= mtk_disp_ovl_adaptor_comp_bind
,
600 .unbind
= mtk_disp_ovl_adaptor_comp_unbind
,
603 static int mtk_disp_ovl_adaptor_master_bind(struct device
*dev
)
605 struct mtk_disp_ovl_adaptor
*priv
= dev_get_drvdata(dev
);
608 ret
= component_bind_all(dev
, priv
->mmsys_dev
);
610 return dev_err_probe(dev
, ret
, "component_bind_all failed!\n");
612 priv
->children_bound
= true;
616 static void mtk_disp_ovl_adaptor_master_unbind(struct device
*dev
)
618 struct mtk_disp_ovl_adaptor
*priv
= dev_get_drvdata(dev
);
620 priv
->children_bound
= false;
623 static const struct component_master_ops mtk_disp_ovl_adaptor_master_ops
= {
624 .bind
= mtk_disp_ovl_adaptor_master_bind
,
625 .unbind
= mtk_disp_ovl_adaptor_master_unbind
,
628 static int mtk_disp_ovl_adaptor_probe(struct platform_device
*pdev
)
630 struct mtk_disp_ovl_adaptor
*priv
;
631 struct device
*dev
= &pdev
->dev
;
632 struct component_match
*match
= NULL
;
635 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
639 platform_set_drvdata(pdev
, priv
);
641 ret
= ovl_adaptor_comp_init(dev
, &match
);
645 priv
->mmsys_dev
= pdev
->dev
.platform_data
;
647 component_master_add_with_match(dev
, &mtk_disp_ovl_adaptor_master_ops
, match
);
649 pm_runtime_enable(dev
);
651 ret
= component_add(dev
, &mtk_disp_ovl_adaptor_comp_ops
);
653 pm_runtime_disable(dev
);
654 return dev_err_probe(dev
, ret
, "Failed to add component\n");
660 static void mtk_disp_ovl_adaptor_remove(struct platform_device
*pdev
)
662 component_master_del(&pdev
->dev
, &mtk_disp_ovl_adaptor_master_ops
);
663 pm_runtime_disable(&pdev
->dev
);
666 struct platform_driver mtk_disp_ovl_adaptor_driver
= {
667 .probe
= mtk_disp_ovl_adaptor_probe
,
668 .remove
= mtk_disp_ovl_adaptor_remove
,
670 .name
= "mediatek-disp-ovl-adaptor",