2 * Copyright (C) STMicroelectronics SA 2014
3 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
4 * Fabien Dessenne <fabien.dessenne@st.com>
5 * for STMicroelectronics.
6 * License terms: GNU General Public License (GPL), version 2
9 #include <linux/component.h>
10 #include <linux/module.h>
11 #include <linux/platform_device.h>
12 #include <linux/reset.h>
16 #include "sti_compositor.h"
18 #include "sti_cursor.h"
21 #include "sti_plane.h"
26 * stiH407 compositor properties
28 struct sti_compositor_data stih407_compositor_data
= {
31 {STI_CURSOR_SUBDEV
, (int)STI_CURSOR
, 0x000},
32 {STI_GPD_SUBDEV
, (int)STI_GDP_0
, 0x100},
33 {STI_GPD_SUBDEV
, (int)STI_GDP_1
, 0x200},
34 {STI_GPD_SUBDEV
, (int)STI_GDP_2
, 0x300},
35 {STI_GPD_SUBDEV
, (int)STI_GDP_3
, 0x400},
36 {STI_VID_SUBDEV
, (int)STI_HQVDP_0
, 0x700},
37 {STI_MIXER_MAIN_SUBDEV
, STI_MIXER_MAIN
, 0xC00},
38 {STI_MIXER_AUX_SUBDEV
, STI_MIXER_AUX
, 0xD00},
43 * stiH416 compositor properties
45 * on stih416 MIXER_AUX has a different base address from MIXER_MAIN
46 * Moreover, GDPx is different for Main and Aux Mixer. So this subdev map does
47 * not fit for stiH416 if we want to enable the MIXER_AUX.
49 struct sti_compositor_data stih416_compositor_data
= {
52 {STI_GPD_SUBDEV
, (int)STI_GDP_0
, 0x100},
53 {STI_GPD_SUBDEV
, (int)STI_GDP_1
, 0x200},
54 {STI_MIXER_MAIN_SUBDEV
, STI_MIXER_MAIN
, 0xC00}
58 int sti_compositor_debufs_init(struct sti_compositor
*compo
,
59 struct drm_minor
*minor
)
63 for (i
= 0; compo
->vid
[i
]; i
++) {
64 ret
= vid_debugfs_init(compo
->vid
[i
], minor
);
69 for (i
= 0; compo
->mixer
[i
]; i
++) {
70 ret
= sti_mixer_debugfs_init(compo
->mixer
[i
], minor
);
78 static int sti_compositor_bind(struct device
*dev
,
79 struct device
*master
,
82 struct sti_compositor
*compo
= dev_get_drvdata(dev
);
83 struct drm_device
*drm_dev
= data
;
84 unsigned int i
, mixer_id
= 0, vid_id
= 0, crtc_id
= 0;
85 struct sti_private
*dev_priv
= drm_dev
->dev_private
;
86 struct drm_plane
*cursor
= NULL
;
87 struct drm_plane
*primary
= NULL
;
88 struct sti_compositor_subdev_descriptor
*desc
= compo
->data
.subdev_desc
;
89 unsigned int array_size
= compo
->data
.nb_subdev
;
91 dev_priv
->compo
= compo
;
93 /* Register mixer subdev and video subdev first */
94 for (i
= 0; i
< array_size
; i
++) {
95 switch (desc
[i
].type
) {
97 compo
->vid
[vid_id
++] =
98 sti_vid_create(compo
->dev
, drm_dev
, desc
[i
].id
,
99 compo
->regs
+ desc
[i
].offset
);
101 case STI_MIXER_MAIN_SUBDEV
:
102 case STI_MIXER_AUX_SUBDEV
:
103 compo
->mixer
[mixer_id
++] =
104 sti_mixer_create(compo
->dev
, drm_dev
, desc
[i
].id
,
105 compo
->regs
+ desc
[i
].offset
);
108 case STI_CURSOR_SUBDEV
:
109 /* Nothing to do, wait for the second round */
112 DRM_ERROR("Unknow subdev compoment type\n");
117 /* Register the other subdevs, create crtc and planes */
118 for (i
= 0; i
< array_size
; i
++) {
119 enum drm_plane_type plane_type
= DRM_PLANE_TYPE_OVERLAY
;
121 if (crtc_id
< mixer_id
)
122 plane_type
= DRM_PLANE_TYPE_PRIMARY
;
124 switch (desc
[i
].type
) {
125 case STI_MIXER_MAIN_SUBDEV
:
126 case STI_MIXER_AUX_SUBDEV
:
128 /* Nothing to do, already done at the first round */
130 case STI_CURSOR_SUBDEV
:
131 cursor
= sti_cursor_create(drm_dev
, compo
->dev
,
133 compo
->regs
+ desc
[i
].offset
,
136 DRM_ERROR("Can't create CURSOR plane\n");
141 primary
= sti_gdp_create(drm_dev
, compo
->dev
,
143 compo
->regs
+ desc
[i
].offset
,
147 DRM_ERROR("Can't create GDP plane\n");
152 DRM_ERROR("Unknown subdev compoment type\n");
156 /* The first planes are reserved for primary planes*/
157 if (crtc_id
< mixer_id
&& primary
) {
158 sti_crtc_init(drm_dev
, compo
->mixer
[crtc_id
],
166 drm_vblank_init(drm_dev
, crtc_id
);
167 /* Allow usage of vblank without having to call drm_irq_install */
168 drm_dev
->irq_enabled
= 1;
173 static void sti_compositor_unbind(struct device
*dev
, struct device
*master
,
179 static const struct component_ops sti_compositor_ops
= {
180 .bind
= sti_compositor_bind
,
181 .unbind
= sti_compositor_unbind
,
184 static const struct of_device_id compositor_of_match
[] = {
186 .compatible
= "st,stih416-compositor",
187 .data
= &stih416_compositor_data
,
189 .compatible
= "st,stih407-compositor",
190 .data
= &stih407_compositor_data
,
195 MODULE_DEVICE_TABLE(of
, compositor_of_match
);
197 static int sti_compositor_probe(struct platform_device
*pdev
)
199 struct device
*dev
= &pdev
->dev
;
200 struct device_node
*np
= dev
->of_node
;
201 struct device_node
*vtg_np
;
202 struct sti_compositor
*compo
;
203 struct resource
*res
;
205 compo
= devm_kzalloc(dev
, sizeof(*compo
), GFP_KERNEL
);
207 DRM_ERROR("Failed to allocate compositor context\n");
211 compo
->vtg_vblank_nb
.notifier_call
= sti_crtc_vblank_cb
;
213 /* populate data structure depending on compatibility */
214 BUG_ON(!of_match_node(compositor_of_match
, np
)->data
);
216 memcpy(&compo
->data
, of_match_node(compositor_of_match
, np
)->data
,
217 sizeof(struct sti_compositor_data
));
219 /* Get Memory ressources */
220 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
222 DRM_ERROR("Get memory resource failed\n");
225 compo
->regs
= devm_ioremap(dev
, res
->start
, resource_size(res
));
226 if (compo
->regs
== NULL
) {
227 DRM_ERROR("Register mapping failed\n");
231 /* Get clock resources */
232 compo
->clk_compo_main
= devm_clk_get(dev
, "compo_main");
233 if (IS_ERR(compo
->clk_compo_main
)) {
234 DRM_ERROR("Cannot get compo_main clock\n");
235 return PTR_ERR(compo
->clk_compo_main
);
238 compo
->clk_compo_aux
= devm_clk_get(dev
, "compo_aux");
239 if (IS_ERR(compo
->clk_compo_aux
)) {
240 DRM_ERROR("Cannot get compo_aux clock\n");
241 return PTR_ERR(compo
->clk_compo_aux
);
244 compo
->clk_pix_main
= devm_clk_get(dev
, "pix_main");
245 if (IS_ERR(compo
->clk_pix_main
)) {
246 DRM_ERROR("Cannot get pix_main clock\n");
247 return PTR_ERR(compo
->clk_pix_main
);
250 compo
->clk_pix_aux
= devm_clk_get(dev
, "pix_aux");
251 if (IS_ERR(compo
->clk_pix_aux
)) {
252 DRM_ERROR("Cannot get pix_aux clock\n");
253 return PTR_ERR(compo
->clk_pix_aux
);
256 /* Get reset resources */
257 compo
->rst_main
= devm_reset_control_get_shared(dev
, "compo-main");
258 /* Take compo main out of reset */
259 if (!IS_ERR(compo
->rst_main
))
260 reset_control_deassert(compo
->rst_main
);
262 compo
->rst_aux
= devm_reset_control_get_shared(dev
, "compo-aux");
263 /* Take compo aux out of reset */
264 if (!IS_ERR(compo
->rst_aux
))
265 reset_control_deassert(compo
->rst_aux
);
267 vtg_np
= of_parse_phandle(pdev
->dev
.of_node
, "st,vtg", 0);
269 compo
->vtg_main
= of_vtg_find(vtg_np
);
272 vtg_np
= of_parse_phandle(pdev
->dev
.of_node
, "st,vtg", 1);
274 compo
->vtg_aux
= of_vtg_find(vtg_np
);
277 platform_set_drvdata(pdev
, compo
);
279 return component_add(&pdev
->dev
, &sti_compositor_ops
);
282 static int sti_compositor_remove(struct platform_device
*pdev
)
284 component_del(&pdev
->dev
, &sti_compositor_ops
);
288 struct platform_driver sti_compositor_driver
= {
290 .name
= "sti-compositor",
291 .of_match_table
= compositor_of_match
,
293 .probe
= sti_compositor_probe
,
294 .remove
= sti_compositor_remove
,
297 MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
298 MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
299 MODULE_LICENSE("GPL");