xref: /linux/drivers/gpu/drm/imx/dc/dc-pe.c (revision 8d2b0853add1d7534dc0794e3c8e0b9e8c4ec640)
1*0e177d5cSLiu Ying // SPDX-License-Identifier: GPL-2.0+
2*0e177d5cSLiu Ying /*
3*0e177d5cSLiu Ying  * Copyright 2024 NXP
4*0e177d5cSLiu Ying  */
5*0e177d5cSLiu Ying 
6*0e177d5cSLiu Ying #include <linux/clk.h>
7*0e177d5cSLiu Ying #include <linux/component.h>
8*0e177d5cSLiu Ying #include <linux/mod_devicetable.h>
9*0e177d5cSLiu Ying #include <linux/module.h>
10*0e177d5cSLiu Ying #include <linux/of.h>
11*0e177d5cSLiu Ying #include <linux/of_platform.h>
12*0e177d5cSLiu Ying #include <linux/platform_device.h>
13*0e177d5cSLiu Ying #include <linux/pm.h>
14*0e177d5cSLiu Ying #include <linux/pm_runtime.h>
15*0e177d5cSLiu Ying 
16*0e177d5cSLiu Ying #include "dc-drv.h"
17*0e177d5cSLiu Ying #include "dc-fu.h"
18*0e177d5cSLiu Ying #include "dc-pe.h"
19*0e177d5cSLiu Ying 
20*0e177d5cSLiu Ying static int dc_pe_bind(struct device *dev, struct device *master, void *data)
21*0e177d5cSLiu Ying {
22*0e177d5cSLiu Ying 	struct dc_drm_device *dc_drm = data;
23*0e177d5cSLiu Ying 	struct dc_pe *pe;
24*0e177d5cSLiu Ying 	int ret;
25*0e177d5cSLiu Ying 
26*0e177d5cSLiu Ying 	pe = devm_kzalloc(dev, sizeof(*pe), GFP_KERNEL);
27*0e177d5cSLiu Ying 	if (!pe)
28*0e177d5cSLiu Ying 		return -ENOMEM;
29*0e177d5cSLiu Ying 
30*0e177d5cSLiu Ying 	pe->clk_axi = devm_clk_get(dev, NULL);
31*0e177d5cSLiu Ying 	if (IS_ERR(pe->clk_axi))
32*0e177d5cSLiu Ying 		return dev_err_probe(dev, PTR_ERR(pe->clk_axi),
33*0e177d5cSLiu Ying 				     "failed to get AXI clock\n");
34*0e177d5cSLiu Ying 
35*0e177d5cSLiu Ying 	pe->dev = dev;
36*0e177d5cSLiu Ying 
37*0e177d5cSLiu Ying 	dev_set_drvdata(dev, pe);
38*0e177d5cSLiu Ying 
39*0e177d5cSLiu Ying 	ret = devm_pm_runtime_enable(dev);
40*0e177d5cSLiu Ying 	if (ret)
41*0e177d5cSLiu Ying 		return ret;
42*0e177d5cSLiu Ying 
43*0e177d5cSLiu Ying 	dc_drm->pe = pe;
44*0e177d5cSLiu Ying 
45*0e177d5cSLiu Ying 	return 0;
46*0e177d5cSLiu Ying }
47*0e177d5cSLiu Ying 
48*0e177d5cSLiu Ying /*
49*0e177d5cSLiu Ying  * It's possible to get the child device pointers from the child component
50*0e177d5cSLiu Ying  * bind callbacks, but it depends on the component helper behavior to bind
51*0e177d5cSLiu Ying  * the pixel engine component first.  To avoid the dependency, post bind to
52*0e177d5cSLiu Ying  * get the pointers from dc_drm in a safe manner.
53*0e177d5cSLiu Ying  */
54*0e177d5cSLiu Ying void dc_pe_post_bind(struct dc_drm_device *dc_drm)
55*0e177d5cSLiu Ying {
56*0e177d5cSLiu Ying 	struct dc_pe *pe = dc_drm->pe;
57*0e177d5cSLiu Ying 	int i;
58*0e177d5cSLiu Ying 
59*0e177d5cSLiu Ying 	for (i = 0; i < DC_DISPLAYS; i++) {
60*0e177d5cSLiu Ying 		pe->cf_safe[i] = dc_drm->cf_safe[i];
61*0e177d5cSLiu Ying 		pe->cf_cont[i] = dc_drm->cf_cont[i];
62*0e177d5cSLiu Ying 		pe->ed_safe[i] = dc_drm->ed_safe[i];
63*0e177d5cSLiu Ying 		pe->ed_cont[i] = dc_drm->ed_cont[i];
64*0e177d5cSLiu Ying 	}
65*0e177d5cSLiu Ying 
66*0e177d5cSLiu Ying 	for (i = 0; i < DC_DISP_FU_CNT; i++)
67*0e177d5cSLiu Ying 		pe->fu_disp[i] = dc_drm->fu_disp[i];
68*0e177d5cSLiu Ying 
69*0e177d5cSLiu Ying 	for (i = 0; i < DC_LB_CNT; i++)
70*0e177d5cSLiu Ying 		pe->lb[i] = dc_drm->lb[i];
71*0e177d5cSLiu Ying }
72*0e177d5cSLiu Ying 
73*0e177d5cSLiu Ying static const struct component_ops dc_pe_ops = {
74*0e177d5cSLiu Ying 	.bind = dc_pe_bind,
75*0e177d5cSLiu Ying };
76*0e177d5cSLiu Ying 
77*0e177d5cSLiu Ying static int dc_pe_probe(struct platform_device *pdev)
78*0e177d5cSLiu Ying {
79*0e177d5cSLiu Ying 	int ret;
80*0e177d5cSLiu Ying 
81*0e177d5cSLiu Ying 	ret = devm_of_platform_populate(&pdev->dev);
82*0e177d5cSLiu Ying 	if (ret < 0)
83*0e177d5cSLiu Ying 		return ret;
84*0e177d5cSLiu Ying 
85*0e177d5cSLiu Ying 	ret = component_add(&pdev->dev, &dc_pe_ops);
86*0e177d5cSLiu Ying 	if (ret)
87*0e177d5cSLiu Ying 		return dev_err_probe(&pdev->dev, ret,
88*0e177d5cSLiu Ying 				     "failed to add component\n");
89*0e177d5cSLiu Ying 
90*0e177d5cSLiu Ying 	return 0;
91*0e177d5cSLiu Ying }
92*0e177d5cSLiu Ying 
93*0e177d5cSLiu Ying static void dc_pe_remove(struct platform_device *pdev)
94*0e177d5cSLiu Ying {
95*0e177d5cSLiu Ying 	component_del(&pdev->dev, &dc_pe_ops);
96*0e177d5cSLiu Ying }
97*0e177d5cSLiu Ying 
98*0e177d5cSLiu Ying static int dc_pe_runtime_suspend(struct device *dev)
99*0e177d5cSLiu Ying {
100*0e177d5cSLiu Ying 	struct dc_pe *pe = dev_get_drvdata(dev);
101*0e177d5cSLiu Ying 
102*0e177d5cSLiu Ying 	clk_disable_unprepare(pe->clk_axi);
103*0e177d5cSLiu Ying 
104*0e177d5cSLiu Ying 	return 0;
105*0e177d5cSLiu Ying }
106*0e177d5cSLiu Ying 
107*0e177d5cSLiu Ying static int dc_pe_runtime_resume(struct device *dev)
108*0e177d5cSLiu Ying {
109*0e177d5cSLiu Ying 	struct dc_pe *pe = dev_get_drvdata(dev);
110*0e177d5cSLiu Ying 	int i, ret;
111*0e177d5cSLiu Ying 
112*0e177d5cSLiu Ying 	ret = clk_prepare_enable(pe->clk_axi);
113*0e177d5cSLiu Ying 	if (ret) {
114*0e177d5cSLiu Ying 		dev_err(dev, "failed to enable AXI clock: %d\n", ret);
115*0e177d5cSLiu Ying 		return ret;
116*0e177d5cSLiu Ying 	}
117*0e177d5cSLiu Ying 
118*0e177d5cSLiu Ying 	for (i = 0; i < ARRAY_SIZE(pe->cf_safe); i++)
119*0e177d5cSLiu Ying 		dc_cf_init(pe->cf_safe[i]);
120*0e177d5cSLiu Ying 
121*0e177d5cSLiu Ying 	for (i = 0; i < ARRAY_SIZE(pe->cf_cont); i++)
122*0e177d5cSLiu Ying 		dc_cf_init(pe->cf_cont[i]);
123*0e177d5cSLiu Ying 
124*0e177d5cSLiu Ying 	for (i = 0; i < ARRAY_SIZE(pe->ed_safe); i++)
125*0e177d5cSLiu Ying 		dc_ed_init(pe->ed_safe[i]);
126*0e177d5cSLiu Ying 
127*0e177d5cSLiu Ying 	for (i = 0; i < ARRAY_SIZE(pe->ed_cont); i++)
128*0e177d5cSLiu Ying 		dc_ed_init(pe->ed_cont[i]);
129*0e177d5cSLiu Ying 
130*0e177d5cSLiu Ying 	for (i = 0; i < ARRAY_SIZE(pe->fu_disp); i++)
131*0e177d5cSLiu Ying 		pe->fu_disp[i]->ops.init(pe->fu_disp[i]);
132*0e177d5cSLiu Ying 
133*0e177d5cSLiu Ying 	for (i = 0; i < ARRAY_SIZE(pe->lb); i++)
134*0e177d5cSLiu Ying 		dc_lb_init(pe->lb[i]);
135*0e177d5cSLiu Ying 
136*0e177d5cSLiu Ying 	return 0;
137*0e177d5cSLiu Ying }
138*0e177d5cSLiu Ying 
139*0e177d5cSLiu Ying static const struct dev_pm_ops dc_pe_pm_ops = {
140*0e177d5cSLiu Ying 	RUNTIME_PM_OPS(dc_pe_runtime_suspend, dc_pe_runtime_resume, NULL)
141*0e177d5cSLiu Ying };
142*0e177d5cSLiu Ying 
143*0e177d5cSLiu Ying static const struct of_device_id dc_pe_dt_ids[] = {
144*0e177d5cSLiu Ying 	{ .compatible = "fsl,imx8qxp-dc-pixel-engine", },
145*0e177d5cSLiu Ying 	{ /* sentinel */ }
146*0e177d5cSLiu Ying };
147*0e177d5cSLiu Ying MODULE_DEVICE_TABLE(of, dc_pe_dt_ids);
148*0e177d5cSLiu Ying 
149*0e177d5cSLiu Ying struct platform_driver dc_pe_driver = {
150*0e177d5cSLiu Ying 	.probe = dc_pe_probe,
151*0e177d5cSLiu Ying 	.remove = dc_pe_remove,
152*0e177d5cSLiu Ying 	.driver = {
153*0e177d5cSLiu Ying 		.name = "imx8-dc-pixel-engine",
154*0e177d5cSLiu Ying 		.suppress_bind_attrs = true,
155*0e177d5cSLiu Ying 		.of_match_table = dc_pe_dt_ids,
156*0e177d5cSLiu Ying 		.pm = pm_sleep_ptr(&dc_pe_pm_ops),
157*0e177d5cSLiu Ying 	},
158*0e177d5cSLiu Ying };
159