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 int 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
);
61 static int sti_compositor_bind(struct device
*dev
,
62 struct device
*master
,
65 struct sti_compositor
*compo
= dev_get_drvdata(dev
);
66 struct drm_device
*drm_dev
= data
;
67 unsigned int i
, mixer_id
= 0, vid_id
= 0, crtc_id
= 0;
68 struct sti_private
*dev_priv
= drm_dev
->dev_private
;
69 struct drm_plane
*cursor
= NULL
;
70 struct drm_plane
*primary
= NULL
;
71 struct sti_compositor_subdev_descriptor
*desc
= compo
->data
.subdev_desc
;
72 unsigned int array_size
= compo
->data
.nb_subdev
;
74 dev_priv
->compo
= compo
;
76 /* Register mixer subdev and video subdev first */
77 for (i
= 0; i
< array_size
; i
++) {
78 switch (desc
[i
].type
) {
80 compo
->vid
[vid_id
++] =
81 sti_vid_create(compo
->dev
, drm_dev
, desc
[i
].id
,
82 compo
->regs
+ desc
[i
].offset
);
84 case STI_MIXER_MAIN_SUBDEV
:
85 case STI_MIXER_AUX_SUBDEV
:
86 compo
->mixer
[mixer_id
++] =
87 sti_mixer_create(compo
->dev
, drm_dev
, desc
[i
].id
,
88 compo
->regs
+ desc
[i
].offset
);
91 case STI_CURSOR_SUBDEV
:
92 /* Nothing to do, wait for the second round */
95 DRM_ERROR("Unknown subdev component type\n");
100 /* Register the other subdevs, create crtc and planes */
101 for (i
= 0; i
< array_size
; i
++) {
102 enum drm_plane_type plane_type
= DRM_PLANE_TYPE_OVERLAY
;
104 if (crtc_id
< mixer_id
)
105 plane_type
= DRM_PLANE_TYPE_PRIMARY
;
107 switch (desc
[i
].type
) {
108 case STI_MIXER_MAIN_SUBDEV
:
109 case STI_MIXER_AUX_SUBDEV
:
111 /* Nothing to do, already done at the first round */
113 case STI_CURSOR_SUBDEV
:
114 cursor
= sti_cursor_create(drm_dev
, compo
->dev
,
116 compo
->regs
+ desc
[i
].offset
,
119 DRM_ERROR("Can't create CURSOR plane\n");
124 primary
= sti_gdp_create(drm_dev
, compo
->dev
,
126 compo
->regs
+ desc
[i
].offset
,
130 DRM_ERROR("Can't create GDP plane\n");
135 DRM_ERROR("Unknown subdev component type\n");
139 /* The first planes are reserved for primary planes*/
140 if (crtc_id
< mixer_id
&& primary
) {
141 sti_crtc_init(drm_dev
, compo
->mixer
[crtc_id
],
149 drm_vblank_init(drm_dev
, crtc_id
);
150 /* Allow usage of vblank without having to call drm_irq_install */
151 drm_dev
->irq_enabled
= 1;
156 static void sti_compositor_unbind(struct device
*dev
, struct device
*master
,
162 static const struct component_ops sti_compositor_ops
= {
163 .bind
= sti_compositor_bind
,
164 .unbind
= sti_compositor_unbind
,
167 static const struct of_device_id compositor_of_match
[] = {
169 .compatible
= "st,stih407-compositor",
170 .data
= &stih407_compositor_data
,
175 MODULE_DEVICE_TABLE(of
, compositor_of_match
);
177 static int sti_compositor_probe(struct platform_device
*pdev
)
179 struct device
*dev
= &pdev
->dev
;
180 struct device_node
*np
= dev
->of_node
;
181 struct device_node
*vtg_np
;
182 struct sti_compositor
*compo
;
183 struct resource
*res
;
186 compo
= devm_kzalloc(dev
, sizeof(*compo
), GFP_KERNEL
);
188 DRM_ERROR("Failed to allocate compositor context\n");
192 for (i
= 0; i
< STI_MAX_MIXER
; i
++)
193 compo
->vtg_vblank_nb
[i
].notifier_call
= sti_crtc_vblank_cb
;
195 /* populate data structure depending on compatibility */
196 BUG_ON(!of_match_node(compositor_of_match
, np
)->data
);
198 memcpy(&compo
->data
, of_match_node(compositor_of_match
, np
)->data
,
199 sizeof(struct sti_compositor_data
));
201 /* Get Memory ressources */
202 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
204 DRM_ERROR("Get memory resource failed\n");
207 compo
->regs
= devm_ioremap(dev
, res
->start
, resource_size(res
));
208 if (compo
->regs
== NULL
) {
209 DRM_ERROR("Register mapping failed\n");
213 /* Get clock resources */
214 compo
->clk_compo_main
= devm_clk_get(dev
, "compo_main");
215 if (IS_ERR(compo
->clk_compo_main
)) {
216 DRM_ERROR("Cannot get compo_main clock\n");
217 return PTR_ERR(compo
->clk_compo_main
);
220 compo
->clk_compo_aux
= devm_clk_get(dev
, "compo_aux");
221 if (IS_ERR(compo
->clk_compo_aux
)) {
222 DRM_ERROR("Cannot get compo_aux clock\n");
223 return PTR_ERR(compo
->clk_compo_aux
);
226 compo
->clk_pix_main
= devm_clk_get(dev
, "pix_main");
227 if (IS_ERR(compo
->clk_pix_main
)) {
228 DRM_ERROR("Cannot get pix_main clock\n");
229 return PTR_ERR(compo
->clk_pix_main
);
232 compo
->clk_pix_aux
= devm_clk_get(dev
, "pix_aux");
233 if (IS_ERR(compo
->clk_pix_aux
)) {
234 DRM_ERROR("Cannot get pix_aux clock\n");
235 return PTR_ERR(compo
->clk_pix_aux
);
238 /* Get reset resources */
239 compo
->rst_main
= devm_reset_control_get_shared(dev
, "compo-main");
240 /* Take compo main out of reset */
241 if (!IS_ERR(compo
->rst_main
))
242 reset_control_deassert(compo
->rst_main
);
244 compo
->rst_aux
= devm_reset_control_get_shared(dev
, "compo-aux");
245 /* Take compo aux out of reset */
246 if (!IS_ERR(compo
->rst_aux
))
247 reset_control_deassert(compo
->rst_aux
);
249 vtg_np
= of_parse_phandle(pdev
->dev
.of_node
, "st,vtg", 0);
251 compo
->vtg
[STI_MIXER_MAIN
] = of_vtg_find(vtg_np
);
254 vtg_np
= of_parse_phandle(pdev
->dev
.of_node
, "st,vtg", 1);
256 compo
->vtg
[STI_MIXER_AUX
] = of_vtg_find(vtg_np
);
259 platform_set_drvdata(pdev
, compo
);
261 return component_add(&pdev
->dev
, &sti_compositor_ops
);
264 static int sti_compositor_remove(struct platform_device
*pdev
)
266 component_del(&pdev
->dev
, &sti_compositor_ops
);
270 struct platform_driver sti_compositor_driver
= {
272 .name
= "sti-compositor",
273 .of_match_table
= compositor_of_match
,
275 .probe
= sti_compositor_probe
,
276 .remove
= sti_compositor_remove
,
279 MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
280 MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
281 MODULE_LICENSE("GPL");