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 static int sti_compositor_bind(struct device
*dev
,
59 struct device
*master
,
62 struct sti_compositor
*compo
= dev_get_drvdata(dev
);
63 struct drm_device
*drm_dev
= data
;
64 unsigned int i
, mixer_id
= 0, vid_id
= 0, crtc_id
= 0;
65 struct sti_private
*dev_priv
= drm_dev
->dev_private
;
66 struct drm_plane
*cursor
= NULL
;
67 struct drm_plane
*primary
= NULL
;
68 struct sti_compositor_subdev_descriptor
*desc
= compo
->data
.subdev_desc
;
69 unsigned int array_size
= compo
->data
.nb_subdev
;
71 dev_priv
->compo
= compo
;
73 /* Register mixer subdev and video subdev first */
74 for (i
= 0; i
< array_size
; i
++) {
75 switch (desc
[i
].type
) {
77 compo
->vid
[vid_id
++] =
78 sti_vid_create(compo
->dev
, desc
[i
].id
,
79 compo
->regs
+ desc
[i
].offset
);
81 case STI_MIXER_MAIN_SUBDEV
:
82 case STI_MIXER_AUX_SUBDEV
:
83 compo
->mixer
[mixer_id
++] =
84 sti_mixer_create(compo
->dev
, desc
[i
].id
,
85 compo
->regs
+ desc
[i
].offset
);
88 case STI_CURSOR_SUBDEV
:
89 /* Nothing to do, wait for the second round */
92 DRM_ERROR("Unknow subdev compoment type\n");
97 /* Register the other subdevs, create crtc and planes */
98 for (i
= 0; i
< array_size
; i
++) {
99 enum drm_plane_type plane_type
= DRM_PLANE_TYPE_OVERLAY
;
101 if (crtc_id
< mixer_id
)
102 plane_type
= DRM_PLANE_TYPE_PRIMARY
;
104 switch (desc
[i
].type
) {
105 case STI_MIXER_MAIN_SUBDEV
:
106 case STI_MIXER_AUX_SUBDEV
:
108 /* Nothing to do, already done at the first round */
110 case STI_CURSOR_SUBDEV
:
111 cursor
= sti_cursor_create(drm_dev
, compo
->dev
,
113 compo
->regs
+ desc
[i
].offset
,
116 DRM_ERROR("Can't create CURSOR plane\n");
121 primary
= sti_gdp_create(drm_dev
, compo
->dev
,
123 compo
->regs
+ desc
[i
].offset
,
127 DRM_ERROR("Can't create GDP plane\n");
132 DRM_ERROR("Unknown subdev compoment type\n");
136 /* The first planes are reserved for primary planes*/
137 if (crtc_id
< mixer_id
&& primary
) {
138 sti_crtc_init(drm_dev
, compo
->mixer
[crtc_id
],
146 drm_vblank_init(drm_dev
, crtc_id
);
147 /* Allow usage of vblank without having to call drm_irq_install */
148 drm_dev
->irq_enabled
= 1;
153 static void sti_compositor_unbind(struct device
*dev
, struct device
*master
,
159 static const struct component_ops sti_compositor_ops
= {
160 .bind
= sti_compositor_bind
,
161 .unbind
= sti_compositor_unbind
,
164 static const struct of_device_id compositor_of_match
[] = {
166 .compatible
= "st,stih416-compositor",
167 .data
= &stih416_compositor_data
,
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
;
185 compo
= devm_kzalloc(dev
, sizeof(*compo
), GFP_KERNEL
);
187 DRM_ERROR("Failed to allocate compositor context\n");
191 compo
->vtg_vblank_nb
.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(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(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_main
= of_vtg_find(vtg_np
);
251 vtg_np
= of_parse_phandle(pdev
->dev
.of_node
, "st,vtg", 1);
253 compo
->vtg_aux
= of_vtg_find(vtg_np
);
255 platform_set_drvdata(pdev
, compo
);
257 return component_add(&pdev
->dev
, &sti_compositor_ops
);
260 static int sti_compositor_remove(struct platform_device
*pdev
)
262 component_del(&pdev
->dev
, &sti_compositor_ops
);
266 struct platform_driver sti_compositor_driver
= {
268 .name
= "sti-compositor",
269 .of_match_table
= compositor_of_match
,
271 .probe
= sti_compositor_probe
,
272 .remove
= sti_compositor_remove
,
275 MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
276 MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
277 MODULE_LICENSE("GPL");