Loading...
Note: File does not exist in v4.17.
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (c) 2021 MediaTek Inc.
4 */
5
6#include <drm/drm_fourcc.h>
7#include <drm/drm_of.h>
8#include <linux/clk.h>
9#include <linux/component.h>
10#include <linux/of.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>
19
20#include "mtk_disp_drv.h"
21#include "mtk_drm_crtc.h"
22#include "mtk_drm_ddp_comp.h"
23#include "mtk_drm_drv.h"
24#include "mtk_ethdr.h"
25
26#define MTK_OVL_ADAPTOR_RDMA_MAX_WIDTH 1920
27#define MTK_OVL_ADAPTOR_LAYER_NUM 4
28
29enum mtk_ovl_adaptor_comp_type {
30 OVL_ADAPTOR_TYPE_ETHDR,
31 OVL_ADAPTOR_TYPE_MDP_RDMA,
32 OVL_ADAPTOR_TYPE_MERGE,
33 OVL_ADAPTOR_TYPE_NUM,
34};
35
36enum mtk_ovl_adaptor_comp_id {
37 OVL_ADAPTOR_ETHDR0,
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,
46 OVL_ADAPTOR_MERGE0,
47 OVL_ADAPTOR_MERGE1,
48 OVL_ADAPTOR_MERGE2,
49 OVL_ADAPTOR_MERGE3,
50 OVL_ADAPTOR_ID_MAX
51};
52
53struct ovl_adaptor_comp_match {
54 enum mtk_ovl_adaptor_comp_type type;
55 enum mtk_ddp_comp_id comp_id;
56 int alias_id;
57 const struct mtk_ddp_comp_funcs *funcs;
58};
59
60struct mtk_disp_ovl_adaptor {
61 struct device *ovl_adaptor_comp[OVL_ADAPTOR_ID_MAX];
62 struct device *mmsys_dev;
63 bool children_bound;
64};
65
66static const char * const private_comp_stem[OVL_ADAPTOR_TYPE_NUM] = {
67 [OVL_ADAPTOR_TYPE_ETHDR] = "ethdr",
68 [OVL_ADAPTOR_TYPE_MDP_RDMA] = "vdo1-rdma",
69 [OVL_ADAPTOR_TYPE_MERGE] = "merge",
70};
71
72static const struct mtk_ddp_comp_funcs ethdr = {
73 .clk_enable = mtk_ethdr_clk_enable,
74 .clk_disable = mtk_ethdr_clk_disable,
75 .start = mtk_ethdr_start,
76 .stop = mtk_ethdr_stop,
77};
78
79static const struct mtk_ddp_comp_funcs merge = {
80 .clk_enable = mtk_merge_clk_enable,
81 .clk_disable = mtk_merge_clk_disable,
82};
83
84static const struct mtk_ddp_comp_funcs rdma = {
85 .power_on = mtk_mdp_rdma_power_on,
86 .power_off = mtk_mdp_rdma_power_off,
87 .clk_enable = mtk_mdp_rdma_clk_enable,
88 .clk_disable = mtk_mdp_rdma_clk_disable,
89};
90
91static const struct ovl_adaptor_comp_match comp_matches[OVL_ADAPTOR_ID_MAX] = {
92 [OVL_ADAPTOR_ETHDR0] = { OVL_ADAPTOR_TYPE_ETHDR, DDP_COMPONENT_ETHDR_MIXER, 0, ðdr },
93 [OVL_ADAPTOR_MDP_RDMA0] = { OVL_ADAPTOR_TYPE_MDP_RDMA, DDP_COMPONENT_MDP_RDMA0, 0, &rdma },
94 [OVL_ADAPTOR_MDP_RDMA1] = { OVL_ADAPTOR_TYPE_MDP_RDMA, DDP_COMPONENT_MDP_RDMA1, 1, &rdma },
95 [OVL_ADAPTOR_MDP_RDMA2] = { OVL_ADAPTOR_TYPE_MDP_RDMA, DDP_COMPONENT_MDP_RDMA2, 2, &rdma },
96 [OVL_ADAPTOR_MDP_RDMA3] = { OVL_ADAPTOR_TYPE_MDP_RDMA, DDP_COMPONENT_MDP_RDMA3, 3, &rdma },
97 [OVL_ADAPTOR_MDP_RDMA4] = { OVL_ADAPTOR_TYPE_MDP_RDMA, DDP_COMPONENT_MDP_RDMA4, 4, &rdma },
98 [OVL_ADAPTOR_MDP_RDMA5] = { OVL_ADAPTOR_TYPE_MDP_RDMA, DDP_COMPONENT_MDP_RDMA5, 5, &rdma },
99 [OVL_ADAPTOR_MDP_RDMA6] = { OVL_ADAPTOR_TYPE_MDP_RDMA, DDP_COMPONENT_MDP_RDMA6, 6, &rdma },
100 [OVL_ADAPTOR_MDP_RDMA7] = { OVL_ADAPTOR_TYPE_MDP_RDMA, DDP_COMPONENT_MDP_RDMA7, 7, &rdma },
101 [OVL_ADAPTOR_MERGE0] = { OVL_ADAPTOR_TYPE_MERGE, DDP_COMPONENT_MERGE1, 1, &merge },
102 [OVL_ADAPTOR_MERGE1] = { OVL_ADAPTOR_TYPE_MERGE, DDP_COMPONENT_MERGE2, 2, &merge },
103 [OVL_ADAPTOR_MERGE2] = { OVL_ADAPTOR_TYPE_MERGE, DDP_COMPONENT_MERGE3, 3, &merge },
104 [OVL_ADAPTOR_MERGE3] = { OVL_ADAPTOR_TYPE_MERGE, DDP_COMPONENT_MERGE4, 4, &merge },
105};
106
107void mtk_ovl_adaptor_layer_config(struct device *dev, unsigned int idx,
108 struct mtk_plane_state *state,
109 struct cmdq_pkt *cmdq_pkt)
110{
111 struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(dev);
112 struct mtk_plane_pending_state *pending = &state->pending;
113 struct mtk_mdp_rdma_cfg rdma_config = {0};
114 struct device *rdma_l;
115 struct device *rdma_r;
116 struct device *merge;
117 struct device *ethdr;
118 const struct drm_format_info *fmt_info = drm_format_info(pending->format);
119 bool use_dual_pipe = false;
120 unsigned int align_width;
121 unsigned int l_w = 0;
122 unsigned int r_w = 0;
123
124 dev_dbg(dev, "%s+ idx:%d, enable:%d, fmt:0x%x\n", __func__, idx,
125 pending->enable, pending->format);
126 dev_dbg(dev, "addr 0x%pad, fb w:%d, {%d,%d,%d,%d}\n",
127 &pending->addr, (pending->pitch / fmt_info->cpp[0]),
128 pending->x, pending->y, pending->width, pending->height);
129
130 rdma_l = ovl_adaptor->ovl_adaptor_comp[OVL_ADAPTOR_MDP_RDMA0 + 2 * idx];
131 rdma_r = ovl_adaptor->ovl_adaptor_comp[OVL_ADAPTOR_MDP_RDMA0 + 2 * idx + 1];
132 merge = ovl_adaptor->ovl_adaptor_comp[OVL_ADAPTOR_MERGE0 + idx];
133 ethdr = ovl_adaptor->ovl_adaptor_comp[OVL_ADAPTOR_ETHDR0];
134
135 if (!pending->enable) {
136 mtk_merge_stop_cmdq(merge, cmdq_pkt);
137 mtk_mdp_rdma_stop(rdma_l, cmdq_pkt);
138 mtk_mdp_rdma_stop(rdma_r, cmdq_pkt);
139 mtk_ethdr_layer_config(ethdr, idx, state, cmdq_pkt);
140 return;
141 }
142
143 /* ETHDR is in 1T2P domain, width needs to be 2 pixels align */
144 align_width = ALIGN_DOWN(pending->width, 2);
145
146 if (align_width > MTK_OVL_ADAPTOR_RDMA_MAX_WIDTH)
147 use_dual_pipe = true;
148
149 if (use_dual_pipe) {
150 l_w = (align_width / 2) + ((pending->width / 2) % 2);
151 r_w = align_width - l_w;
152 } else {
153 l_w = align_width;
154 }
155 mtk_merge_advance_config(merge, l_w, r_w, pending->height, 0, 0, cmdq_pkt);
156 mtk_mmsys_merge_async_config(ovl_adaptor->mmsys_dev, idx, align_width / 2,
157 pending->height, cmdq_pkt);
158
159 rdma_config.width = l_w;
160 rdma_config.height = pending->height;
161 rdma_config.addr0 = pending->addr;
162 rdma_config.pitch = pending->pitch;
163 rdma_config.fmt = pending->format;
164 rdma_config.color_encoding = pending->color_encoding;
165 mtk_mdp_rdma_config(rdma_l, &rdma_config, cmdq_pkt);
166
167 if (use_dual_pipe) {
168 rdma_config.x_left = l_w;
169 rdma_config.width = r_w;
170 mtk_mdp_rdma_config(rdma_r, &rdma_config, cmdq_pkt);
171 }
172
173 mtk_merge_start_cmdq(merge, cmdq_pkt);
174
175 mtk_mdp_rdma_start(rdma_l, cmdq_pkt);
176 if (use_dual_pipe)
177 mtk_mdp_rdma_start(rdma_r, cmdq_pkt);
178 else
179 mtk_mdp_rdma_stop(rdma_r, cmdq_pkt);
180
181 mtk_ethdr_layer_config(ethdr, idx, state, cmdq_pkt);
182}
183
184void mtk_ovl_adaptor_config(struct device *dev, unsigned int w,
185 unsigned int h, unsigned int vrefresh,
186 unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
187{
188 struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(dev);
189
190 mtk_ethdr_config(ovl_adaptor->ovl_adaptor_comp[OVL_ADAPTOR_ETHDR0], w, h,
191 vrefresh, bpc, cmdq_pkt);
192}
193
194void mtk_ovl_adaptor_start(struct device *dev)
195{
196 int i;
197 struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(dev);
198
199 for (i = 0; i < OVL_ADAPTOR_ID_MAX; i++) {
200 if (!ovl_adaptor->ovl_adaptor_comp[i] ||
201 !comp_matches[i].funcs->start)
202 continue;
203
204 comp_matches[i].funcs->start(ovl_adaptor->ovl_adaptor_comp[i]);
205 }
206}
207
208void mtk_ovl_adaptor_stop(struct device *dev)
209{
210 int i;
211 struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(dev);
212
213 for (i = 0; i < OVL_ADAPTOR_ID_MAX; i++) {
214 if (!ovl_adaptor->ovl_adaptor_comp[i] ||
215 !comp_matches[i].funcs->stop)
216 continue;
217
218 comp_matches[i].funcs->stop(ovl_adaptor->ovl_adaptor_comp[i]);
219 }
220}
221
222/**
223 * power_off - Power off the devices in OVL adaptor
224 * @dev: Device to be powered off
225 * @num: Number of the devices to be powered off
226 *
227 * Calls the .power_off() ovl_adaptor component callback if it is present.
228 */
229static inline void power_off(struct device *dev, int num)
230{
231 struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(dev);
232 int i;
233
234 if (num > OVL_ADAPTOR_ID_MAX)
235 num = OVL_ADAPTOR_ID_MAX;
236
237 for (i = num - 1; i >= 0; i--) {
238 if (!ovl_adaptor->ovl_adaptor_comp[i] ||
239 !comp_matches[i].funcs->power_off)
240 continue;
241
242 comp_matches[i].funcs->power_off(ovl_adaptor->ovl_adaptor_comp[i]);
243 }
244}
245
246/**
247 * mtk_ovl_adaptor_power_on - Power on the devices in OVL adaptor
248 * @dev: Device to be powered on
249 *
250 * Different from OVL, OVL adaptor is a pseudo device so
251 * we didn't define it in the device tree, pm_runtime_resume_and_get()
252 * called by .atomic_enable() power on no device in OVL adaptor,
253 * we have to implement a function to do the job instead.
254 *
255 * Return: Zero for success or negative number for failure.
256 */
257int mtk_ovl_adaptor_power_on(struct device *dev)
258{
259 struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(dev);
260 int i, ret;
261
262 for (i = 0; i < OVL_ADAPTOR_ID_MAX; i++) {
263 if (!ovl_adaptor->ovl_adaptor_comp[i] ||
264 !comp_matches[i].funcs->power_on)
265 continue;
266
267 ret = comp_matches[i].funcs->power_on(ovl_adaptor->ovl_adaptor_comp[i]);
268 if (ret < 0) {
269 dev_err(dev, "Failed to enable power domain %d, err %d\n", i, ret);
270 power_off(dev, i);
271 return ret;
272 }
273 }
274 return 0;
275}
276
277void mtk_ovl_adaptor_power_off(struct device *dev)
278{
279 power_off(dev, OVL_ADAPTOR_ID_MAX);
280}
281
282int mtk_ovl_adaptor_clk_enable(struct device *dev)
283{
284 struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(dev);
285 struct device *comp;
286 int ret;
287 int i;
288
289 for (i = 0; i < OVL_ADAPTOR_ID_MAX; i++) {
290 comp = ovl_adaptor->ovl_adaptor_comp[i];
291 if (!comp || !comp_matches[i].funcs->clk_enable)
292 continue;
293 ret = comp_matches[i].funcs->clk_enable(comp);
294 if (ret) {
295 dev_err(dev, "Failed to enable clock %d, err %d\n", i, ret);
296 while (--i >= 0)
297 comp_matches[i].funcs->clk_disable(comp);
298 return ret;
299 }
300 }
301 return 0;
302}
303
304void mtk_ovl_adaptor_clk_disable(struct device *dev)
305{
306 struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(dev);
307 struct device *comp;
308 int i;
309
310 for (i = 0; i < OVL_ADAPTOR_ID_MAX; i++) {
311 comp = ovl_adaptor->ovl_adaptor_comp[i];
312 if (!comp || !comp_matches[i].funcs->clk_disable)
313 continue;
314 comp_matches[i].funcs->clk_disable(comp);
315 if (i < OVL_ADAPTOR_MERGE0)
316 pm_runtime_put(comp);
317 }
318}
319
320unsigned int mtk_ovl_adaptor_layer_nr(struct device *dev)
321{
322 return MTK_OVL_ADAPTOR_LAYER_NUM;
323}
324
325struct device *mtk_ovl_adaptor_dma_dev_get(struct device *dev)
326{
327 struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(dev);
328
329 return ovl_adaptor->ovl_adaptor_comp[OVL_ADAPTOR_MDP_RDMA0];
330}
331
332void mtk_ovl_adaptor_register_vblank_cb(struct device *dev, void (*vblank_cb)(void *),
333 void *vblank_cb_data)
334{
335 struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(dev);
336
337 mtk_ethdr_register_vblank_cb(ovl_adaptor->ovl_adaptor_comp[OVL_ADAPTOR_ETHDR0],
338 vblank_cb, vblank_cb_data);
339}
340
341void mtk_ovl_adaptor_unregister_vblank_cb(struct device *dev)
342{
343 struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(dev);
344
345 mtk_ethdr_unregister_vblank_cb(ovl_adaptor->ovl_adaptor_comp[OVL_ADAPTOR_ETHDR0]);
346}
347
348void mtk_ovl_adaptor_enable_vblank(struct device *dev)
349{
350 struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(dev);
351
352 mtk_ethdr_enable_vblank(ovl_adaptor->ovl_adaptor_comp[OVL_ADAPTOR_ETHDR0]);
353}
354
355void mtk_ovl_adaptor_disable_vblank(struct device *dev)
356{
357 struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(dev);
358
359 mtk_ethdr_disable_vblank(ovl_adaptor->ovl_adaptor_comp[OVL_ADAPTOR_ETHDR0]);
360}
361
362const u32 *mtk_ovl_adaptor_get_formats(struct device *dev)
363{
364 struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(dev);
365
366 return mtk_mdp_rdma_get_formats(ovl_adaptor->ovl_adaptor_comp[OVL_ADAPTOR_MDP_RDMA0]);
367}
368
369size_t mtk_ovl_adaptor_get_num_formats(struct device *dev)
370{
371 struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(dev);
372
373 return mtk_mdp_rdma_get_num_formats(ovl_adaptor->ovl_adaptor_comp[OVL_ADAPTOR_MDP_RDMA0]);
374}
375
376void mtk_ovl_adaptor_add_comp(struct device *dev, struct mtk_mutex *mutex)
377{
378 int i;
379 struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(dev);
380
381 for (i = 0; i < OVL_ADAPTOR_ID_MAX; i++) {
382 if (!ovl_adaptor->ovl_adaptor_comp[i])
383 continue;
384 mtk_mutex_add_comp(mutex, comp_matches[i].comp_id);
385 }
386}
387
388void mtk_ovl_adaptor_remove_comp(struct device *dev, struct mtk_mutex *mutex)
389{
390 int i;
391 struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(dev);
392
393 for (i = 0; i < OVL_ADAPTOR_ID_MAX; i++) {
394 if (!ovl_adaptor->ovl_adaptor_comp[i])
395 continue;
396 mtk_mutex_remove_comp(mutex, comp_matches[i].comp_id);
397 }
398}
399
400void mtk_ovl_adaptor_connect(struct device *dev, struct device *mmsys_dev, unsigned int next)
401{
402 mtk_mmsys_ddp_connect(mmsys_dev, DDP_COMPONENT_ETHDR_MIXER, next);
403 mtk_mmsys_ddp_connect(mmsys_dev, DDP_COMPONENT_MDP_RDMA0, DDP_COMPONENT_MERGE1);
404 mtk_mmsys_ddp_connect(mmsys_dev, DDP_COMPONENT_MDP_RDMA1, DDP_COMPONENT_MERGE1);
405 mtk_mmsys_ddp_connect(mmsys_dev, DDP_COMPONENT_MDP_RDMA2, DDP_COMPONENT_MERGE2);
406 mtk_mmsys_ddp_connect(mmsys_dev, DDP_COMPONENT_MERGE1, DDP_COMPONENT_ETHDR_MIXER);
407 mtk_mmsys_ddp_connect(mmsys_dev, DDP_COMPONENT_MERGE2, DDP_COMPONENT_ETHDR_MIXER);
408 mtk_mmsys_ddp_connect(mmsys_dev, DDP_COMPONENT_MERGE3, DDP_COMPONENT_ETHDR_MIXER);
409 mtk_mmsys_ddp_connect(mmsys_dev, DDP_COMPONENT_MERGE4, DDP_COMPONENT_ETHDR_MIXER);
410}
411
412void mtk_ovl_adaptor_disconnect(struct device *dev, struct device *mmsys_dev, unsigned int next)
413{
414 mtk_mmsys_ddp_disconnect(mmsys_dev, DDP_COMPONENT_ETHDR_MIXER, next);
415 mtk_mmsys_ddp_disconnect(mmsys_dev, DDP_COMPONENT_MDP_RDMA0, DDP_COMPONENT_MERGE1);
416 mtk_mmsys_ddp_disconnect(mmsys_dev, DDP_COMPONENT_MDP_RDMA1, DDP_COMPONENT_MERGE1);
417 mtk_mmsys_ddp_disconnect(mmsys_dev, DDP_COMPONENT_MDP_RDMA2, DDP_COMPONENT_MERGE2);
418 mtk_mmsys_ddp_disconnect(mmsys_dev, DDP_COMPONENT_MERGE1, DDP_COMPONENT_ETHDR_MIXER);
419 mtk_mmsys_ddp_disconnect(mmsys_dev, DDP_COMPONENT_MERGE2, DDP_COMPONENT_ETHDR_MIXER);
420 mtk_mmsys_ddp_disconnect(mmsys_dev, DDP_COMPONENT_MERGE3, DDP_COMPONENT_ETHDR_MIXER);
421 mtk_mmsys_ddp_disconnect(mmsys_dev, DDP_COMPONENT_MERGE4, DDP_COMPONENT_ETHDR_MIXER);
422}
423
424static int ovl_adaptor_comp_get_id(struct device *dev, struct device_node *node,
425 enum mtk_ovl_adaptor_comp_type type)
426{
427 int alias_id = of_alias_get_id(node, private_comp_stem[type]);
428 int i;
429
430 for (i = 0; i < ARRAY_SIZE(comp_matches); i++)
431 if (comp_matches[i].type == type &&
432 comp_matches[i].alias_id == alias_id)
433 return i;
434
435 dev_warn(dev, "Failed to get id. type: %d, alias: %d\n", type, alias_id);
436 return -EINVAL;
437}
438
439static const struct of_device_id mtk_ovl_adaptor_comp_dt_ids[] = {
440 { .compatible = "mediatek,mt8195-disp-ethdr", .data = (void *)OVL_ADAPTOR_TYPE_ETHDR },
441 { .compatible = "mediatek,mt8195-disp-merge", .data = (void *)OVL_ADAPTOR_TYPE_MERGE },
442 { .compatible = "mediatek,mt8195-vdo1-rdma", .data = (void *)OVL_ADAPTOR_TYPE_MDP_RDMA },
443 { /* sentinel */ }
444};
445
446static int compare_of(struct device *dev, void *data)
447{
448 return dev->of_node == data;
449}
450
451static int ovl_adaptor_comp_init(struct device *dev, struct component_match **match)
452{
453 struct mtk_disp_ovl_adaptor *priv = dev_get_drvdata(dev);
454 struct device_node *node, *parent;
455 struct platform_device *comp_pdev;
456
457 parent = dev->parent->parent->of_node->parent;
458
459 for_each_child_of_node(parent, node) {
460 const struct of_device_id *of_id;
461 enum mtk_ovl_adaptor_comp_type type;
462 int id;
463
464 of_id = of_match_node(mtk_ovl_adaptor_comp_dt_ids, node);
465 if (!of_id)
466 continue;
467
468 if (!of_device_is_available(node)) {
469 dev_dbg(dev, "Skipping disabled component %pOF\n",
470 node);
471 continue;
472 }
473
474 type = (enum mtk_ovl_adaptor_comp_type)(uintptr_t)of_id->data;
475 id = ovl_adaptor_comp_get_id(dev, node, type);
476 if (id < 0) {
477 dev_warn(dev, "Skipping unknown component %pOF\n",
478 node);
479 continue;
480 }
481
482 comp_pdev = of_find_device_by_node(node);
483 if (!comp_pdev)
484 return -EPROBE_DEFER;
485
486 priv->ovl_adaptor_comp[id] = &comp_pdev->dev;
487
488 drm_of_component_match_add(dev, match, compare_of, node);
489 dev_dbg(dev, "Adding component match for %pOF\n", node);
490 }
491
492 if (!*match) {
493 dev_err(dev, "No match device for ovl_adaptor\n");
494 return -ENODEV;
495 }
496
497 return 0;
498}
499
500static int mtk_disp_ovl_adaptor_comp_bind(struct device *dev, struct device *master,
501 void *data)
502{
503 struct mtk_disp_ovl_adaptor *priv = dev_get_drvdata(dev);
504
505 if (!priv->children_bound)
506 return -EPROBE_DEFER;
507
508 return 0;
509}
510
511static void mtk_disp_ovl_adaptor_comp_unbind(struct device *dev, struct device *master,
512 void *data)
513{
514}
515
516static const struct component_ops mtk_disp_ovl_adaptor_comp_ops = {
517 .bind = mtk_disp_ovl_adaptor_comp_bind,
518 .unbind = mtk_disp_ovl_adaptor_comp_unbind,
519};
520
521static int mtk_disp_ovl_adaptor_master_bind(struct device *dev)
522{
523 struct mtk_disp_ovl_adaptor *priv = dev_get_drvdata(dev);
524 int ret;
525
526 ret = component_bind_all(dev, priv->mmsys_dev);
527 if (ret)
528 return dev_err_probe(dev, ret, "component_bind_all failed!\n");
529
530 priv->children_bound = true;
531 return 0;
532}
533
534static void mtk_disp_ovl_adaptor_master_unbind(struct device *dev)
535{
536 struct mtk_disp_ovl_adaptor *priv = dev_get_drvdata(dev);
537
538 priv->children_bound = false;
539}
540
541static const struct component_master_ops mtk_disp_ovl_adaptor_master_ops = {
542 .bind = mtk_disp_ovl_adaptor_master_bind,
543 .unbind = mtk_disp_ovl_adaptor_master_unbind,
544};
545
546static int mtk_disp_ovl_adaptor_probe(struct platform_device *pdev)
547{
548 struct mtk_disp_ovl_adaptor *priv;
549 struct device *dev = &pdev->dev;
550 struct component_match *match = NULL;
551 int ret;
552
553 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
554 if (!priv)
555 return -ENOMEM;
556
557 platform_set_drvdata(pdev, priv);
558
559 ret = ovl_adaptor_comp_init(dev, &match);
560 if (ret < 0)
561 return ret;
562
563 priv->mmsys_dev = pdev->dev.platform_data;
564
565 component_master_add_with_match(dev, &mtk_disp_ovl_adaptor_master_ops, match);
566
567 pm_runtime_enable(dev);
568
569 ret = component_add(dev, &mtk_disp_ovl_adaptor_comp_ops);
570 if (ret != 0) {
571 pm_runtime_disable(dev);
572 dev_err(dev, "Failed to add component: %d\n", ret);
573 }
574
575 return ret;
576}
577
578static void mtk_disp_ovl_adaptor_remove(struct platform_device *pdev)
579{
580 component_master_del(&pdev->dev, &mtk_disp_ovl_adaptor_master_ops);
581 pm_runtime_disable(&pdev->dev);
582}
583
584struct platform_driver mtk_disp_ovl_adaptor_driver = {
585 .probe = mtk_disp_ovl_adaptor_probe,
586 .remove_new = mtk_disp_ovl_adaptor_remove,
587 .driver = {
588 .name = "mediatek-disp-ovl-adaptor",
589 .owner = THIS_MODULE,
590 },
591};