1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) STMicroelectronics SA 2014
4 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
5 * Fabien Dessenne <fabien.dessenne@st.com>
6 * for STMicroelectronics.
9 #include <linux/component.h>
11 #include <linux/module.h>
12 #include <linux/platform_device.h>
13 #include <linux/reset.h>
15 #include <drm/drm_device.h>
16 #include <drm/drm_print.h>
17 #include <drm/drm_vblank.h>
19 #include "sti_compositor.h"
21 #include "sti_cursor.h"
24 #include "sti_plane.h"
29 * stiH407 compositor properties
31 static const struct sti_compositor_data stih407_compositor_data
= {
34 {STI_CURSOR_SUBDEV
, (int)STI_CURSOR
, 0x000},
35 {STI_GPD_SUBDEV
, (int)STI_GDP_0
, 0x100},
36 {STI_GPD_SUBDEV
, (int)STI_GDP_1
, 0x200},
37 {STI_GPD_SUBDEV
, (int)STI_GDP_2
, 0x300},
38 {STI_GPD_SUBDEV
, (int)STI_GDP_3
, 0x400},
39 {STI_VID_SUBDEV
, (int)STI_HQVDP_0
, 0x700},
40 {STI_MIXER_MAIN_SUBDEV
, STI_MIXER_MAIN
, 0xC00},
41 {STI_MIXER_AUX_SUBDEV
, STI_MIXER_AUX
, 0xD00},
45 void sti_compositor_debugfs_init(struct sti_compositor
*compo
,
46 struct drm_minor
*minor
)
50 for (i
= 0; i
< STI_MAX_VID
; i
++)
52 vid_debugfs_init(compo
->vid
[i
], minor
);
54 for (i
= 0; i
< STI_MAX_MIXER
; i
++)
56 sti_mixer_debugfs_init(compo
->mixer
[i
], minor
);
59 static int sti_compositor_bind(struct device
*dev
,
60 struct device
*master
,
63 struct sti_compositor
*compo
= dev_get_drvdata(dev
);
64 struct drm_device
*drm_dev
= data
;
65 unsigned int i
, mixer_id
= 0, vid_id
= 0, crtc_id
= 0;
66 struct sti_private
*dev_priv
= drm_dev
->dev_private
;
67 struct drm_plane
*cursor
= NULL
;
68 struct drm_plane
*primary
= NULL
;
69 struct sti_compositor_subdev_descriptor
*desc
= compo
->data
.subdev_desc
;
70 unsigned int array_size
= compo
->data
.nb_subdev
;
72 dev_priv
->compo
= compo
;
74 /* Register mixer subdev and video subdev first */
75 for (i
= 0; i
< array_size
; i
++) {
76 switch (desc
[i
].type
) {
78 compo
->vid
[vid_id
++] =
79 sti_vid_create(compo
->dev
, drm_dev
, desc
[i
].id
,
80 compo
->regs
+ desc
[i
].offset
);
82 case STI_MIXER_MAIN_SUBDEV
:
83 case STI_MIXER_AUX_SUBDEV
:
84 compo
->mixer
[mixer_id
++] =
85 sti_mixer_create(compo
->dev
, drm_dev
, desc
[i
].id
,
86 compo
->regs
+ desc
[i
].offset
);
89 case STI_CURSOR_SUBDEV
:
90 /* Nothing to do, wait for the second round */
93 DRM_ERROR("Unknown subdev component type\n");
98 /* Register the other subdevs, create crtc and planes */
99 for (i
= 0; i
< array_size
; i
++) {
100 enum drm_plane_type plane_type
= DRM_PLANE_TYPE_OVERLAY
;
102 if (crtc_id
< mixer_id
)
103 plane_type
= DRM_PLANE_TYPE_PRIMARY
;
105 switch (desc
[i
].type
) {
106 case STI_MIXER_MAIN_SUBDEV
:
107 case STI_MIXER_AUX_SUBDEV
:
109 /* Nothing to do, already done at the first round */
111 case STI_CURSOR_SUBDEV
:
112 cursor
= sti_cursor_create(drm_dev
, compo
->dev
,
114 compo
->regs
+ desc
[i
].offset
,
117 DRM_ERROR("Can't create CURSOR plane\n");
122 primary
= sti_gdp_create(drm_dev
, compo
->dev
,
124 compo
->regs
+ desc
[i
].offset
,
128 DRM_ERROR("Can't create GDP plane\n");
133 DRM_ERROR("Unknown subdev component type\n");
137 /* The first planes are reserved for primary planes*/
138 if (crtc_id
< mixer_id
&& primary
) {
139 sti_crtc_init(drm_dev
, compo
->mixer
[crtc_id
],
147 drm_vblank_init(drm_dev
, crtc_id
);
148 /* Allow usage of vblank without having to call drm_irq_install */
149 drm_dev
->irq_enabled
= 1;
154 static void sti_compositor_unbind(struct device
*dev
, struct device
*master
,
160 static const struct component_ops sti_compositor_ops
= {
161 .bind
= sti_compositor_bind
,
162 .unbind
= sti_compositor_unbind
,
165 static const struct of_device_id compositor_of_match
[] = {
167 .compatible
= "st,stih407-compositor",
168 .data
= &stih407_compositor_data
,
173 MODULE_DEVICE_TABLE(of
, compositor_of_match
);
175 static int sti_compositor_probe(struct platform_device
*pdev
)
177 struct device
*dev
= &pdev
->dev
;
178 struct device_node
*np
= dev
->of_node
;
179 struct device_node
*vtg_np
;
180 struct sti_compositor
*compo
;
181 struct resource
*res
;
184 compo
= devm_kzalloc(dev
, sizeof(*compo
), GFP_KERNEL
);
186 DRM_ERROR("Failed to allocate compositor context\n");
190 for (i
= 0; i
< STI_MAX_MIXER
; i
++)
191 compo
->vtg_vblank_nb
[i
].notifier_call
= sti_crtc_vblank_cb
;
193 /* populate data structure depending on compatibility */
194 BUG_ON(!of_match_node(compositor_of_match
, np
)->data
);
196 memcpy(&compo
->data
, of_match_node(compositor_of_match
, np
)->data
,
197 sizeof(struct sti_compositor_data
));
199 /* Get Memory ressources */
200 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
202 DRM_ERROR("Get memory resource failed\n");
205 compo
->regs
= devm_ioremap(dev
, res
->start
, resource_size(res
));
206 if (compo
->regs
== NULL
) {
207 DRM_ERROR("Register mapping failed\n");
211 /* Get clock resources */
212 compo
->clk_compo_main
= devm_clk_get(dev
, "compo_main");
213 if (IS_ERR(compo
->clk_compo_main
)) {
214 DRM_ERROR("Cannot get compo_main clock\n");
215 return PTR_ERR(compo
->clk_compo_main
);
218 compo
->clk_compo_aux
= devm_clk_get(dev
, "compo_aux");
219 if (IS_ERR(compo
->clk_compo_aux
)) {
220 DRM_ERROR("Cannot get compo_aux clock\n");
221 return PTR_ERR(compo
->clk_compo_aux
);
224 compo
->clk_pix_main
= devm_clk_get(dev
, "pix_main");
225 if (IS_ERR(compo
->clk_pix_main
)) {
226 DRM_ERROR("Cannot get pix_main clock\n");
227 return PTR_ERR(compo
->clk_pix_main
);
230 compo
->clk_pix_aux
= devm_clk_get(dev
, "pix_aux");
231 if (IS_ERR(compo
->clk_pix_aux
)) {
232 DRM_ERROR("Cannot get pix_aux clock\n");
233 return PTR_ERR(compo
->clk_pix_aux
);
236 /* Get reset resources */
237 compo
->rst_main
= devm_reset_control_get_shared(dev
, "compo-main");
238 /* Take compo main out of reset */
239 if (!IS_ERR(compo
->rst_main
))
240 reset_control_deassert(compo
->rst_main
);
242 compo
->rst_aux
= devm_reset_control_get_shared(dev
, "compo-aux");
243 /* Take compo aux out of reset */
244 if (!IS_ERR(compo
->rst_aux
))
245 reset_control_deassert(compo
->rst_aux
);
247 vtg_np
= of_parse_phandle(pdev
->dev
.of_node
, "st,vtg", 0);
249 compo
->vtg
[STI_MIXER_MAIN
] = of_vtg_find(vtg_np
);
252 vtg_np
= of_parse_phandle(pdev
->dev
.of_node
, "st,vtg", 1);
254 compo
->vtg
[STI_MIXER_AUX
] = of_vtg_find(vtg_np
);
257 platform_set_drvdata(pdev
, compo
);
259 return component_add(&pdev
->dev
, &sti_compositor_ops
);
262 static int sti_compositor_remove(struct platform_device
*pdev
)
264 component_del(&pdev
->dev
, &sti_compositor_ops
);
268 struct platform_driver sti_compositor_driver
= {
270 .name
= "sti-compositor",
271 .of_match_table
= compositor_of_match
,
273 .probe
= sti_compositor_probe
,
274 .remove
= sti_compositor_remove
,
277 MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
278 MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
279 MODULE_LICENSE("GPL");