diff options
author | Benjamin Gaignard <benjamin.gaignard@linaro.org> | 2014-07-31 03:39:11 -0400 |
---|---|---|
committer | Benjamin Gaignard <benjamin.gaignard@linaro.org> | 2014-07-31 03:39:11 -0400 |
commit | 9bbf86fe874cce0169f0e1152d96f0591e680874 (patch) | |
tree | 844f5e119ffd0b9d690dde389aa89ddda0b171e2 /drivers/gpu/drm/sti | |
parent | d219673d8437ff1073c11d30ac496fa42b09662c (diff) |
drm: sti: Add DRM driver itself
Make the link between all the hardware drivers and DRM/KMS interface.
Create the driver itself and make it register all the sub-components.
Use GEM CMA helpers for buffer allocation.
Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
Reviewed-by: Rob Clark <robdclark@gmail.com>
Diffstat (limited to 'drivers/gpu/drm/sti')
-rw-r--r-- | drivers/gpu/drm/sti/Kconfig | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/Makefile | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_compositor.c | 45 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_drm_crtc.c | 423 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_drm_crtc.h | 22 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_drm_drv.c | 241 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_drm_drv.h | 29 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_drm_plane.c | 195 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_drm_plane.h | 18 |
9 files changed, 985 insertions, 3 deletions
diff --git a/drivers/gpu/drm/sti/Kconfig b/drivers/gpu/drm/sti/Kconfig index 11d372c79bea..2d9d4252d598 100644 --- a/drivers/gpu/drm/sti/Kconfig +++ b/drivers/gpu/drm/sti/Kconfig | |||
@@ -1,6 +1,14 @@ | |||
1 | config DRM_STI | 1 | config DRM_STI |
2 | tristate "DRM Support for STMicroelectronics SoC stiH41x Series" | 2 | tristate "DRM Support for STMicroelectronics SoC stiH41x Series" |
3 | depends on DRM && (SOC_STIH415 || SOC_STIH416 || ARCH_MULTIPLATFORM) | 3 | depends on DRM && (SOC_STIH415 || SOC_STIH416 || ARCH_MULTIPLATFORM) |
4 | select DRM_KMS_HELPER | ||
5 | select DRM_GEM_CMA_HELPER | ||
4 | select DRM_KMS_CMA_HELPER | 6 | select DRM_KMS_CMA_HELPER |
5 | help | 7 | help |
6 | Choose this option to enable DRM on STM stiH41x chipset | 8 | Choose this option to enable DRM on STM stiH41x chipset |
9 | |||
10 | config DRM_STI_FBDEV | ||
11 | bool "DRM frame buffer device for STMicroelectronics SoC stiH41x Serie" | ||
12 | depends on DRM_STI | ||
13 | help | ||
14 | Choose this option to enable FBDEV on top of DRM for STM stiH41x chipset | ||
diff --git a/drivers/gpu/drm/sti/Makefile b/drivers/gpu/drm/sti/Makefile index c5838f20f122..04ac2ceef27f 100644 --- a/drivers/gpu/drm/sti/Makefile +++ b/drivers/gpu/drm/sti/Makefile | |||
@@ -3,7 +3,9 @@ sticompositor-y := \ | |||
3 | sti_mixer.o \ | 3 | sti_mixer.o \ |
4 | sti_gdp.o \ | 4 | sti_gdp.o \ |
5 | sti_vid.o \ | 5 | sti_vid.o \ |
6 | sti_compositor.o | 6 | sti_compositor.o \ |
7 | sti_drm_crtc.o \ | ||
8 | sti_drm_plane.o | ||
7 | 9 | ||
8 | stihdmi-y := sti_hdmi.o \ | 10 | stihdmi-y := sti_hdmi.o \ |
9 | sti_hdmi_tx3g0c55phy.o \ | 11 | sti_hdmi_tx3g0c55phy.o \ |
@@ -15,4 +17,5 @@ obj-$(CONFIG_DRM_STI) = \ | |||
15 | stihdmi.o \ | 17 | stihdmi.o \ |
16 | sti_hda.o \ | 18 | sti_hda.o \ |
17 | sti_tvout.o \ | 19 | sti_tvout.o \ |
18 | sticompositor.o \ No newline at end of file | 20 | sticompositor.o \ |
21 | sti_drm_drv.o \ No newline at end of file | ||
diff --git a/drivers/gpu/drm/sti/sti_compositor.c b/drivers/gpu/drm/sti/sti_compositor.c index a4164cfa906d..770a725efa20 100644 --- a/drivers/gpu/drm/sti/sti_compositor.c +++ b/drivers/gpu/drm/sti/sti_compositor.c | |||
@@ -14,6 +14,9 @@ | |||
14 | #include <drm/drmP.h> | 14 | #include <drm/drmP.h> |
15 | 15 | ||
16 | #include "sti_compositor.h" | 16 | #include "sti_compositor.h" |
17 | #include "sti_drm_crtc.h" | ||
18 | #include "sti_drm_drv.h" | ||
19 | #include "sti_drm_plane.h" | ||
17 | #include "sti_gdp.h" | 20 | #include "sti_gdp.h" |
18 | #include "sti_vtg.h" | 21 | #include "sti_vtg.h" |
19 | 22 | ||
@@ -87,12 +90,51 @@ static int sti_compositor_bind(struct device *dev, struct device *master, | |||
87 | struct sti_compositor *compo = dev_get_drvdata(dev); | 90 | struct sti_compositor *compo = dev_get_drvdata(dev); |
88 | struct drm_device *drm_dev = data; | 91 | struct drm_device *drm_dev = data; |
89 | unsigned int i, crtc = 0, plane = 0; | 92 | unsigned int i, crtc = 0, plane = 0; |
93 | struct sti_drm_private *dev_priv = drm_dev->dev_private; | ||
94 | struct drm_plane *cursor = NULL; | ||
95 | struct drm_plane *primary = NULL; | ||
96 | |||
97 | dev_priv->compo = compo; | ||
98 | |||
99 | for (i = 0; i < compo->nb_layers; i++) { | ||
100 | if (compo->layer[i]) { | ||
101 | enum sti_layer_desc desc = compo->layer[i]->desc; | ||
102 | enum sti_layer_type type = desc & STI_LAYER_TYPE_MASK; | ||
103 | enum drm_plane_type plane_type = DRM_PLANE_TYPE_OVERLAY; | ||
104 | |||
105 | if (compo->mixer[crtc]) | ||
106 | plane_type = DRM_PLANE_TYPE_PRIMARY; | ||
107 | |||
108 | switch (type) { | ||
109 | case STI_CUR: | ||
110 | cursor = sti_drm_plane_init(drm_dev, | ||
111 | compo->layer[i], | ||
112 | (1 << crtc) - 1, | ||
113 | DRM_PLANE_TYPE_CURSOR); | ||
114 | break; | ||
115 | case STI_GDP: | ||
116 | case STI_VID: | ||
117 | primary = sti_drm_plane_init(drm_dev, | ||
118 | compo->layer[i], | ||
119 | (1 << crtc) - 1, plane_type); | ||
120 | plane++; | ||
121 | break; | ||
122 | } | ||
123 | |||
124 | /* The first planes are reserved for primary planes*/ | ||
125 | if (compo->mixer[crtc]) { | ||
126 | sti_drm_crtc_init(drm_dev, compo->mixer[crtc], | ||
127 | primary, cursor); | ||
128 | crtc++; | ||
129 | cursor = NULL; | ||
130 | } | ||
131 | } | ||
132 | } | ||
90 | 133 | ||
91 | drm_vblank_init(drm_dev, crtc); | 134 | drm_vblank_init(drm_dev, crtc); |
92 | /* Allow usage of vblank without having to call drm_irq_install */ | 135 | /* Allow usage of vblank without having to call drm_irq_install */ |
93 | drm_dev->irq_enabled = 1; | 136 | drm_dev->irq_enabled = 1; |
94 | 137 | ||
95 | |||
96 | DRM_DEBUG_DRIVER("Initialized %d DRM CRTC(s) and %d DRM plane(s)\n", | 138 | DRM_DEBUG_DRIVER("Initialized %d DRM CRTC(s) and %d DRM plane(s)\n", |
97 | crtc, plane); | 139 | crtc, plane); |
98 | DRM_DEBUG_DRIVER("DRM plane(s) for VID/VDP not created yet\n"); | 140 | DRM_DEBUG_DRIVER("DRM plane(s) for VID/VDP not created yet\n"); |
@@ -139,6 +181,7 @@ static int sti_compositor_probe(struct platform_device *pdev) | |||
139 | return -ENOMEM; | 181 | return -ENOMEM; |
140 | } | 182 | } |
141 | compo->dev = dev; | 183 | compo->dev = dev; |
184 | compo->vtg_vblank_nb.notifier_call = sti_drm_crtc_vblank_cb; | ||
142 | 185 | ||
143 | /* populate data structure depending on compatibility */ | 186 | /* populate data structure depending on compatibility */ |
144 | BUG_ON(!of_match_node(compositor_of_match, np)->data); | 187 | BUG_ON(!of_match_node(compositor_of_match, np)->data); |
diff --git a/drivers/gpu/drm/sti/sti_drm_crtc.c b/drivers/gpu/drm/sti/sti_drm_crtc.c new file mode 100644 index 000000000000..6eba648cf7b3 --- /dev/null +++ b/drivers/gpu/drm/sti/sti_drm_crtc.c | |||
@@ -0,0 +1,423 @@ | |||
1 | /* | ||
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 | ||
7 | */ | ||
8 | |||
9 | #include <linux/clk.h> | ||
10 | |||
11 | #include <drm/drmP.h> | ||
12 | #include <drm/drm_crtc_helper.h> | ||
13 | |||
14 | #include "sti_compositor.h" | ||
15 | #include "sti_drm_drv.h" | ||
16 | #include "sti_drm_crtc.h" | ||
17 | #include "sti_vtg.h" | ||
18 | |||
19 | static void sti_drm_crtc_dpms(struct drm_crtc *crtc, int mode) | ||
20 | { | ||
21 | DRM_DEBUG_KMS("\n"); | ||
22 | } | ||
23 | |||
24 | static void sti_drm_crtc_prepare(struct drm_crtc *crtc) | ||
25 | { | ||
26 | struct sti_mixer *mixer = to_sti_mixer(crtc); | ||
27 | struct device *dev = mixer->dev; | ||
28 | struct sti_compositor *compo = dev_get_drvdata(dev); | ||
29 | |||
30 | compo->enable = true; | ||
31 | |||
32 | /* Prepare and enable the compo IP clock */ | ||
33 | if (mixer->id == STI_MIXER_MAIN) { | ||
34 | if (clk_prepare_enable(compo->clk_compo_main)) | ||
35 | DRM_INFO("Failed to prepare/enable compo_main clk\n"); | ||
36 | } else { | ||
37 | if (clk_prepare_enable(compo->clk_compo_aux)) | ||
38 | DRM_INFO("Failed to prepare/enable compo_aux clk\n"); | ||
39 | } | ||
40 | } | ||
41 | |||
42 | static void sti_drm_crtc_commit(struct drm_crtc *crtc) | ||
43 | { | ||
44 | struct sti_mixer *mixer = to_sti_mixer(crtc); | ||
45 | struct device *dev = mixer->dev; | ||
46 | struct sti_compositor *compo = dev_get_drvdata(dev); | ||
47 | struct sti_layer *layer; | ||
48 | |||
49 | if ((!mixer || !compo)) { | ||
50 | DRM_ERROR("Can not find mixer or compositor)\n"); | ||
51 | return; | ||
52 | } | ||
53 | |||
54 | /* get GDP which is reserved to the CRTC FB */ | ||
55 | layer = to_sti_layer(crtc->primary); | ||
56 | if (layer) | ||
57 | sti_layer_commit(layer); | ||
58 | else | ||
59 | DRM_ERROR("Can not find CRTC dedicated plane (GDP0)\n"); | ||
60 | |||
61 | /* Enable layer on mixer */ | ||
62 | if (sti_mixer_set_layer_status(mixer, layer, true)) | ||
63 | DRM_ERROR("Can not enable layer at mixer\n"); | ||
64 | } | ||
65 | |||
66 | static bool sti_drm_crtc_mode_fixup(struct drm_crtc *crtc, | ||
67 | const struct drm_display_mode *mode, | ||
68 | struct drm_display_mode *adjusted_mode) | ||
69 | { | ||
70 | /* accept the provided drm_display_mode, do not fix it up */ | ||
71 | return true; | ||
72 | } | ||
73 | |||
74 | static int | ||
75 | sti_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, | ||
76 | struct drm_display_mode *adjusted_mode, int x, int y, | ||
77 | struct drm_framebuffer *old_fb) | ||
78 | { | ||
79 | struct sti_mixer *mixer = to_sti_mixer(crtc); | ||
80 | struct device *dev = mixer->dev; | ||
81 | struct sti_compositor *compo = dev_get_drvdata(dev); | ||
82 | struct sti_layer *layer; | ||
83 | struct clk *clk; | ||
84 | int rate = mode->clock * 1000; | ||
85 | int res; | ||
86 | unsigned int w, h; | ||
87 | |||
88 | DRM_DEBUG_KMS("CRTC:%d (%s) fb:%d mode:%d (%s)\n", | ||
89 | crtc->base.id, sti_mixer_to_str(mixer), | ||
90 | crtc->primary->fb->base.id, mode->base.id, mode->name); | ||
91 | |||
92 | DRM_DEBUG_KMS("%d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n", | ||
93 | mode->vrefresh, mode->clock, | ||
94 | mode->hdisplay, | ||
95 | mode->hsync_start, mode->hsync_end, | ||
96 | mode->htotal, | ||
97 | mode->vdisplay, | ||
98 | mode->vsync_start, mode->vsync_end, | ||
99 | mode->vtotal, mode->type, mode->flags); | ||
100 | |||
101 | /* Set rate and prepare/enable pixel clock */ | ||
102 | if (mixer->id == STI_MIXER_MAIN) | ||
103 | clk = compo->clk_pix_main; | ||
104 | else | ||
105 | clk = compo->clk_pix_aux; | ||
106 | |||
107 | res = clk_set_rate(clk, rate); | ||
108 | if (res < 0) { | ||
109 | DRM_ERROR("Cannot set rate (%dHz) for pix clk\n", rate); | ||
110 | return -EINVAL; | ||
111 | } | ||
112 | if (clk_prepare_enable(clk)) { | ||
113 | DRM_ERROR("Failed to prepare/enable pix clk\n"); | ||
114 | return -EINVAL; | ||
115 | } | ||
116 | |||
117 | sti_vtg_set_config(mixer->id == STI_MIXER_MAIN ? | ||
118 | compo->vtg_main : compo->vtg_aux, &crtc->mode); | ||
119 | |||
120 | /* a GDP is reserved to the CRTC FB */ | ||
121 | layer = to_sti_layer(crtc->primary); | ||
122 | if (!layer) { | ||
123 | DRM_ERROR("Can not find GDP0)\n"); | ||
124 | return -EINVAL; | ||
125 | } | ||
126 | |||
127 | /* copy the mode data adjusted by mode_fixup() into crtc->mode | ||
128 | * so that hardware can be set to proper mode | ||
129 | */ | ||
130 | memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode)); | ||
131 | |||
132 | res = sti_mixer_set_layer_depth(mixer, layer); | ||
133 | if (res) { | ||
134 | DRM_ERROR("Can not set layer depth\n"); | ||
135 | return -EINVAL; | ||
136 | } | ||
137 | res = sti_mixer_active_video_area(mixer, &crtc->mode); | ||
138 | if (res) { | ||
139 | DRM_ERROR("Can not set active video area\n"); | ||
140 | return -EINVAL; | ||
141 | } | ||
142 | |||
143 | w = crtc->primary->fb->width - x; | ||
144 | h = crtc->primary->fb->height - y; | ||
145 | |||
146 | return sti_layer_prepare(layer, crtc->primary->fb, &crtc->mode, | ||
147 | mixer->id, 0, 0, w, h, x, y, w, h); | ||
148 | } | ||
149 | |||
150 | static int sti_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, | ||
151 | struct drm_framebuffer *old_fb) | ||
152 | { | ||
153 | struct sti_mixer *mixer = to_sti_mixer(crtc); | ||
154 | struct device *dev = mixer->dev; | ||
155 | struct sti_compositor *compo = dev_get_drvdata(dev); | ||
156 | struct sti_layer *layer; | ||
157 | unsigned int w, h; | ||
158 | int ret; | ||
159 | |||
160 | DRM_DEBUG_KMS("CRTC:%d (%s) fb:%d (%d,%d)\n", | ||
161 | crtc->base.id, sti_mixer_to_str(mixer), | ||
162 | crtc->primary->fb->base.id, x, y); | ||
163 | |||
164 | /* GDP is reserved to the CRTC FB */ | ||
165 | layer = to_sti_layer(crtc->primary); | ||
166 | if (!layer) { | ||
167 | DRM_ERROR("Can not find GDP0)\n"); | ||
168 | ret = -EINVAL; | ||
169 | goto out; | ||
170 | } | ||
171 | |||
172 | w = crtc->primary->fb->width - crtc->x; | ||
173 | h = crtc->primary->fb->height - crtc->y; | ||
174 | |||
175 | ret = sti_layer_prepare(layer, crtc->primary->fb, &crtc->mode, | ||
176 | mixer->id, 0, 0, w, h, | ||
177 | crtc->x, crtc->y, w, h); | ||
178 | if (ret) { | ||
179 | DRM_ERROR("Can not prepare layer\n"); | ||
180 | goto out; | ||
181 | } | ||
182 | |||
183 | sti_drm_crtc_commit(crtc); | ||
184 | out: | ||
185 | return ret; | ||
186 | } | ||
187 | |||
188 | static void sti_drm_crtc_load_lut(struct drm_crtc *crtc) | ||
189 | { | ||
190 | /* do nothing */ | ||
191 | } | ||
192 | |||
193 | static void sti_drm_crtc_disable(struct drm_crtc *crtc) | ||
194 | { | ||
195 | struct sti_mixer *mixer = to_sti_mixer(crtc); | ||
196 | struct device *dev = mixer->dev; | ||
197 | struct sti_compositor *compo = dev_get_drvdata(dev); | ||
198 | struct sti_layer *layer; | ||
199 | |||
200 | if (!compo->enable) | ||
201 | return; | ||
202 | |||
203 | DRM_DEBUG_KMS("CRTC:%d (%s)\n", crtc->base.id, sti_mixer_to_str(mixer)); | ||
204 | |||
205 | /* Disable Background */ | ||
206 | sti_mixer_set_background_status(mixer, false); | ||
207 | |||
208 | /* Disable GDP */ | ||
209 | layer = to_sti_layer(crtc->primary); | ||
210 | if (!layer) { | ||
211 | DRM_ERROR("Cannot find GDP0\n"); | ||
212 | return; | ||
213 | } | ||
214 | |||
215 | /* Disable layer at mixer level */ | ||
216 | if (sti_mixer_set_layer_status(mixer, layer, false)) | ||
217 | DRM_ERROR("Can not disable %s layer at mixer\n", | ||
218 | sti_layer_to_str(layer)); | ||
219 | |||
220 | /* Wait a while to be sure that a Vsync event is received */ | ||
221 | msleep(WAIT_NEXT_VSYNC_MS); | ||
222 | |||
223 | /* Then disable layer itself */ | ||
224 | sti_layer_disable(layer); | ||
225 | |||
226 | drm_vblank_off(crtc->dev, mixer->id); | ||
227 | |||
228 | /* Disable pixel clock and compo IP clocks */ | ||
229 | if (mixer->id == STI_MIXER_MAIN) { | ||
230 | clk_disable_unprepare(compo->clk_pix_main); | ||
231 | clk_disable_unprepare(compo->clk_compo_main); | ||
232 | } else { | ||
233 | clk_disable_unprepare(compo->clk_pix_aux); | ||
234 | clk_disable_unprepare(compo->clk_compo_aux); | ||
235 | } | ||
236 | |||
237 | compo->enable = false; | ||
238 | } | ||
239 | |||
240 | static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = { | ||
241 | .dpms = sti_drm_crtc_dpms, | ||
242 | .prepare = sti_drm_crtc_prepare, | ||
243 | .commit = sti_drm_crtc_commit, | ||
244 | .mode_fixup = sti_drm_crtc_mode_fixup, | ||
245 | .mode_set = sti_drm_crtc_mode_set, | ||
246 | .mode_set_base = sti_drm_crtc_mode_set_base, | ||
247 | .load_lut = sti_drm_crtc_load_lut, | ||
248 | .disable = sti_drm_crtc_disable, | ||
249 | }; | ||
250 | |||
251 | static int sti_drm_crtc_page_flip(struct drm_crtc *crtc, | ||
252 | struct drm_framebuffer *fb, | ||
253 | struct drm_pending_vblank_event *event, | ||
254 | uint32_t page_flip_flags) | ||
255 | { | ||
256 | struct drm_device *drm_dev = crtc->dev; | ||
257 | struct drm_framebuffer *old_fb; | ||
258 | struct sti_mixer *mixer = to_sti_mixer(crtc); | ||
259 | unsigned long flags; | ||
260 | int ret; | ||
261 | |||
262 | DRM_DEBUG_KMS("fb %d --> fb %d\n", | ||
263 | crtc->primary->fb->base.id, fb->base.id); | ||
264 | |||
265 | mutex_lock(&drm_dev->struct_mutex); | ||
266 | |||
267 | old_fb = crtc->primary->fb; | ||
268 | crtc->primary->fb = fb; | ||
269 | ret = sti_drm_crtc_mode_set_base(crtc, crtc->x, crtc->y, old_fb); | ||
270 | if (ret) { | ||
271 | DRM_ERROR("failed\n"); | ||
272 | crtc->primary->fb = old_fb; | ||
273 | goto out; | ||
274 | } | ||
275 | |||
276 | if (event) { | ||
277 | event->pipe = mixer->id; | ||
278 | |||
279 | ret = drm_vblank_get(drm_dev, event->pipe); | ||
280 | if (ret) { | ||
281 | DRM_ERROR("Cannot get vblank\n"); | ||
282 | goto out; | ||
283 | } | ||
284 | |||
285 | spin_lock_irqsave(&drm_dev->event_lock, flags); | ||
286 | if (mixer->pending_event) { | ||
287 | drm_vblank_put(drm_dev, event->pipe); | ||
288 | ret = -EBUSY; | ||
289 | } else { | ||
290 | mixer->pending_event = event; | ||
291 | } | ||
292 | spin_unlock_irqrestore(&drm_dev->event_lock, flags); | ||
293 | } | ||
294 | out: | ||
295 | mutex_unlock(&drm_dev->struct_mutex); | ||
296 | return ret; | ||
297 | } | ||
298 | |||
299 | static void sti_drm_crtc_destroy(struct drm_crtc *crtc) | ||
300 | { | ||
301 | DRM_DEBUG_KMS("\n"); | ||
302 | drm_crtc_cleanup(crtc); | ||
303 | } | ||
304 | |||
305 | static int sti_drm_crtc_set_property(struct drm_crtc *crtc, | ||
306 | struct drm_property *property, | ||
307 | uint64_t val) | ||
308 | { | ||
309 | DRM_DEBUG_KMS("\n"); | ||
310 | return 0; | ||
311 | } | ||
312 | |||
313 | int sti_drm_crtc_vblank_cb(struct notifier_block *nb, | ||
314 | unsigned long event, void *data) | ||
315 | { | ||
316 | struct drm_device *drm_dev; | ||
317 | struct sti_compositor *compo = | ||
318 | container_of(nb, struct sti_compositor, vtg_vblank_nb); | ||
319 | int *crtc = data; | ||
320 | unsigned long flags; | ||
321 | struct sti_drm_private *priv; | ||
322 | |||
323 | drm_dev = compo->mixer[*crtc]->drm_crtc.dev; | ||
324 | priv = drm_dev->dev_private; | ||
325 | |||
326 | if ((event != VTG_TOP_FIELD_EVENT) && | ||
327 | (event != VTG_BOTTOM_FIELD_EVENT)) { | ||
328 | DRM_ERROR("unknown event: %lu\n", event); | ||
329 | return -EINVAL; | ||
330 | } | ||
331 | |||
332 | drm_handle_vblank(drm_dev, *crtc); | ||
333 | |||
334 | spin_lock_irqsave(&drm_dev->event_lock, flags); | ||
335 | if (compo->mixer[*crtc]->pending_event) { | ||
336 | drm_send_vblank_event(drm_dev, -1, | ||
337 | compo->mixer[*crtc]->pending_event); | ||
338 | drm_vblank_put(drm_dev, *crtc); | ||
339 | compo->mixer[*crtc]->pending_event = NULL; | ||
340 | } | ||
341 | spin_unlock_irqrestore(&drm_dev->event_lock, flags); | ||
342 | |||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | int sti_drm_crtc_enable_vblank(struct drm_device *dev, int crtc) | ||
347 | { | ||
348 | struct sti_drm_private *dev_priv = dev->dev_private; | ||
349 | struct sti_compositor *compo = dev_priv->compo; | ||
350 | struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb; | ||
351 | |||
352 | if (sti_vtg_register_client(crtc == STI_MIXER_MAIN ? | ||
353 | compo->vtg_main : compo->vtg_aux, | ||
354 | vtg_vblank_nb, crtc)) { | ||
355 | DRM_ERROR("Cannot register VTG notifier\n"); | ||
356 | return -EINVAL; | ||
357 | } | ||
358 | |||
359 | return 0; | ||
360 | } | ||
361 | EXPORT_SYMBOL(sti_drm_crtc_enable_vblank); | ||
362 | |||
363 | void sti_drm_crtc_disable_vblank(struct drm_device *dev, int crtc) | ||
364 | { | ||
365 | struct sti_drm_private *priv = dev->dev_private; | ||
366 | struct sti_compositor *compo = priv->compo; | ||
367 | struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb; | ||
368 | unsigned long flags; | ||
369 | |||
370 | DRM_DEBUG_DRIVER("\n"); | ||
371 | |||
372 | if (sti_vtg_unregister_client(crtc == STI_MIXER_MAIN ? | ||
373 | compo->vtg_main : compo->vtg_aux, vtg_vblank_nb)) | ||
374 | DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n"); | ||
375 | |||
376 | /* free the resources of the pending requests */ | ||
377 | spin_lock_irqsave(&dev->event_lock, flags); | ||
378 | if (compo->mixer[crtc]->pending_event) { | ||
379 | drm_vblank_put(dev, crtc); | ||
380 | compo->mixer[crtc]->pending_event = NULL; | ||
381 | } | ||
382 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
383 | |||
384 | } | ||
385 | EXPORT_SYMBOL(sti_drm_crtc_disable_vblank); | ||
386 | |||
387 | static struct drm_crtc_funcs sti_crtc_funcs = { | ||
388 | .set_config = drm_crtc_helper_set_config, | ||
389 | .page_flip = sti_drm_crtc_page_flip, | ||
390 | .destroy = sti_drm_crtc_destroy, | ||
391 | .set_property = sti_drm_crtc_set_property, | ||
392 | }; | ||
393 | |||
394 | bool sti_drm_crtc_is_main(struct drm_crtc *crtc) | ||
395 | { | ||
396 | struct sti_mixer *mixer = to_sti_mixer(crtc); | ||
397 | |||
398 | if (mixer->id == STI_MIXER_MAIN) | ||
399 | return true; | ||
400 | |||
401 | return false; | ||
402 | } | ||
403 | |||
404 | int sti_drm_crtc_init(struct drm_device *drm_dev, struct sti_mixer *mixer, | ||
405 | struct drm_plane *primary, struct drm_plane *cursor) | ||
406 | { | ||
407 | struct drm_crtc *crtc = &mixer->drm_crtc; | ||
408 | int res; | ||
409 | |||
410 | res = drm_crtc_init_with_planes(drm_dev, crtc, primary, cursor, | ||
411 | &sti_crtc_funcs); | ||
412 | if (res) { | ||
413 | DRM_ERROR("Can not initialze CRTC\n"); | ||
414 | return -EINVAL; | ||
415 | } | ||
416 | |||
417 | drm_crtc_helper_add(crtc, &sti_crtc_helper_funcs); | ||
418 | |||
419 | DRM_DEBUG_DRIVER("drm CRTC:%d mapped to %s\n", | ||
420 | crtc->base.id, sti_mixer_to_str(mixer)); | ||
421 | |||
422 | return 0; | ||
423 | } | ||
diff --git a/drivers/gpu/drm/sti/sti_drm_crtc.h b/drivers/gpu/drm/sti/sti_drm_crtc.h new file mode 100644 index 000000000000..caca8b14f017 --- /dev/null +++ b/drivers/gpu/drm/sti/sti_drm_crtc.h | |||
@@ -0,0 +1,22 @@ | |||
1 | /* | ||
2 | * Copyright (C) STMicroelectronics SA 2014 | ||
3 | * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics. | ||
4 | * License terms: GNU General Public License (GPL), version 2 | ||
5 | */ | ||
6 | |||
7 | #ifndef _STI_DRM_CRTC_H_ | ||
8 | #define _STI_DRM_CRTC_H_ | ||
9 | |||
10 | #include <drm/drmP.h> | ||
11 | |||
12 | struct sti_mixer; | ||
13 | |||
14 | int sti_drm_crtc_init(struct drm_device *drm_dev, struct sti_mixer *mixer, | ||
15 | struct drm_plane *primary, struct drm_plane *cursor); | ||
16 | int sti_drm_crtc_enable_vblank(struct drm_device *dev, int crtc); | ||
17 | void sti_drm_crtc_disable_vblank(struct drm_device *dev, int crtc); | ||
18 | int sti_drm_crtc_vblank_cb(struct notifier_block *nb, | ||
19 | unsigned long event, void *data); | ||
20 | bool sti_drm_crtc_is_main(struct drm_crtc *drm_crtc); | ||
21 | |||
22 | #endif | ||
diff --git a/drivers/gpu/drm/sti/sti_drm_drv.c b/drivers/gpu/drm/sti/sti_drm_drv.c new file mode 100644 index 000000000000..a7cc24917a96 --- /dev/null +++ b/drivers/gpu/drm/sti/sti_drm_drv.c | |||
@@ -0,0 +1,241 @@ | |||
1 | /* | ||
2 | * Copyright (C) STMicroelectronics SA 2014 | ||
3 | * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics. | ||
4 | * License terms: GNU General Public License (GPL), version 2 | ||
5 | */ | ||
6 | |||
7 | #include <drm/drmP.h> | ||
8 | |||
9 | #include <linux/component.h> | ||
10 | #include <linux/debugfs.h> | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/of_platform.h> | ||
14 | |||
15 | #include <drm/drm_crtc_helper.h> | ||
16 | #include <drm/drm_gem_cma_helper.h> | ||
17 | #include <drm/drm_fb_cma_helper.h> | ||
18 | |||
19 | #include "sti_drm_drv.h" | ||
20 | #include "sti_drm_crtc.h" | ||
21 | |||
22 | #define DRIVER_NAME "sti" | ||
23 | #define DRIVER_DESC "STMicroelectronics SoC DRM" | ||
24 | #define DRIVER_DATE "20140601" | ||
25 | #define DRIVER_MAJOR 1 | ||
26 | #define DRIVER_MINOR 0 | ||
27 | |||
28 | #define STI_MAX_FB_HEIGHT 4096 | ||
29 | #define STI_MAX_FB_WIDTH 4096 | ||
30 | |||
31 | static struct drm_mode_config_funcs sti_drm_mode_config_funcs = { | ||
32 | .fb_create = drm_fb_cma_create, | ||
33 | }; | ||
34 | |||
35 | static void sti_drm_mode_config_init(struct drm_device *dev) | ||
36 | { | ||
37 | dev->mode_config.min_width = 0; | ||
38 | dev->mode_config.min_height = 0; | ||
39 | |||
40 | /* | ||
41 | * set max width and height as default value. | ||
42 | * this value would be used to check framebuffer size limitation | ||
43 | * at drm_mode_addfb(). | ||
44 | */ | ||
45 | dev->mode_config.max_width = STI_MAX_FB_HEIGHT; | ||
46 | dev->mode_config.max_height = STI_MAX_FB_WIDTH; | ||
47 | |||
48 | dev->mode_config.funcs = &sti_drm_mode_config_funcs; | ||
49 | } | ||
50 | |||
51 | static int sti_drm_load(struct drm_device *dev, unsigned long flags) | ||
52 | { | ||
53 | struct sti_drm_private *private; | ||
54 | int ret; | ||
55 | |||
56 | private = kzalloc(sizeof(struct sti_drm_private), GFP_KERNEL); | ||
57 | if (!private) { | ||
58 | DRM_ERROR("Failed to allocate private\n"); | ||
59 | return -ENOMEM; | ||
60 | } | ||
61 | dev->dev_private = (void *)private; | ||
62 | private->drm_dev = dev; | ||
63 | |||
64 | drm_mode_config_init(dev); | ||
65 | drm_kms_helper_poll_init(dev); | ||
66 | |||
67 | sti_drm_mode_config_init(dev); | ||
68 | |||
69 | ret = component_bind_all(dev->dev, dev); | ||
70 | if (ret) | ||
71 | return ret; | ||
72 | |||
73 | drm_helper_disable_unused_functions(dev); | ||
74 | |||
75 | #ifdef CONFIG_DRM_STI_FBDEV | ||
76 | drm_fbdev_cma_init(dev, 32, | ||
77 | dev->mode_config.num_crtc, | ||
78 | dev->mode_config.num_connector); | ||
79 | #endif | ||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | static const struct file_operations sti_drm_driver_fops = { | ||
84 | .owner = THIS_MODULE, | ||
85 | .open = drm_open, | ||
86 | .mmap = drm_gem_cma_mmap, | ||
87 | .poll = drm_poll, | ||
88 | .read = drm_read, | ||
89 | .unlocked_ioctl = drm_ioctl, | ||
90 | #ifdef CONFIG_COMPAT | ||
91 | .compat_ioctl = drm_compat_ioctl, | ||
92 | #endif | ||
93 | .release = drm_release, | ||
94 | }; | ||
95 | |||
96 | static struct dma_buf *sti_drm_gem_prime_export(struct drm_device *dev, | ||
97 | struct drm_gem_object *obj, | ||
98 | int flags) | ||
99 | { | ||
100 | /* we want to be able to write in mmapped buffer */ | ||
101 | flags |= O_RDWR; | ||
102 | return drm_gem_prime_export(dev, obj, flags); | ||
103 | } | ||
104 | |||
105 | static struct drm_driver sti_drm_driver = { | ||
106 | .driver_features = DRIVER_HAVE_IRQ | DRIVER_MODESET | | ||
107 | DRIVER_GEM | DRIVER_PRIME, | ||
108 | .load = sti_drm_load, | ||
109 | .gem_free_object = drm_gem_cma_free_object, | ||
110 | .gem_vm_ops = &drm_gem_cma_vm_ops, | ||
111 | .dumb_create = drm_gem_cma_dumb_create, | ||
112 | .dumb_map_offset = drm_gem_cma_dumb_map_offset, | ||
113 | .dumb_destroy = drm_gem_dumb_destroy, | ||
114 | .fops = &sti_drm_driver_fops, | ||
115 | |||
116 | .get_vblank_counter = drm_vblank_count, | ||
117 | .enable_vblank = sti_drm_crtc_enable_vblank, | ||
118 | .disable_vblank = sti_drm_crtc_disable_vblank, | ||
119 | |||
120 | .prime_handle_to_fd = drm_gem_prime_handle_to_fd, | ||
121 | .prime_fd_to_handle = drm_gem_prime_fd_to_handle, | ||
122 | .gem_prime_export = sti_drm_gem_prime_export, | ||
123 | .gem_prime_import = drm_gem_prime_import, | ||
124 | .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, | ||
125 | .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, | ||
126 | .gem_prime_vmap = drm_gem_cma_prime_vmap, | ||
127 | .gem_prime_vunmap = drm_gem_cma_prime_vunmap, | ||
128 | .gem_prime_mmap = drm_gem_cma_prime_mmap, | ||
129 | |||
130 | .name = DRIVER_NAME, | ||
131 | .desc = DRIVER_DESC, | ||
132 | .date = DRIVER_DATE, | ||
133 | .major = DRIVER_MAJOR, | ||
134 | .minor = DRIVER_MINOR, | ||
135 | }; | ||
136 | |||
137 | static int compare_of(struct device *dev, void *data) | ||
138 | { | ||
139 | return dev->of_node == data; | ||
140 | } | ||
141 | |||
142 | static int sti_drm_bind(struct device *dev) | ||
143 | { | ||
144 | return drm_platform_init(&sti_drm_driver, to_platform_device(dev)); | ||
145 | } | ||
146 | |||
147 | static void sti_drm_unbind(struct device *dev) | ||
148 | { | ||
149 | drm_put_dev(dev_get_drvdata(dev)); | ||
150 | } | ||
151 | |||
152 | static const struct component_master_ops sti_drm_ops = { | ||
153 | .bind = sti_drm_bind, | ||
154 | .unbind = sti_drm_unbind, | ||
155 | }; | ||
156 | |||
157 | static int sti_drm_master_probe(struct platform_device *pdev) | ||
158 | { | ||
159 | struct device *dev = &pdev->dev; | ||
160 | struct device_node *node = dev->parent->of_node; | ||
161 | struct device_node *child_np; | ||
162 | struct component_match *match = NULL; | ||
163 | |||
164 | dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); | ||
165 | |||
166 | child_np = of_get_next_available_child(node, NULL); | ||
167 | |||
168 | while (child_np) { | ||
169 | component_match_add(dev, &match, compare_of, child_np); | ||
170 | of_node_put(child_np); | ||
171 | child_np = of_get_next_available_child(node, child_np); | ||
172 | } | ||
173 | |||
174 | return component_master_add_with_match(dev, &sti_drm_ops, match); | ||
175 | } | ||
176 | |||
177 | static int sti_drm_master_remove(struct platform_device *pdev) | ||
178 | { | ||
179 | component_master_del(&pdev->dev, &sti_drm_ops); | ||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | static struct platform_driver sti_drm_master_driver = { | ||
184 | .probe = sti_drm_master_probe, | ||
185 | .remove = sti_drm_master_remove, | ||
186 | .driver = { | ||
187 | .owner = THIS_MODULE, | ||
188 | .name = DRIVER_NAME "__master", | ||
189 | }, | ||
190 | }; | ||
191 | |||
192 | static int sti_drm_platform_probe(struct platform_device *pdev) | ||
193 | { | ||
194 | struct device *dev = &pdev->dev; | ||
195 | struct device_node *node = dev->of_node; | ||
196 | struct platform_device *master; | ||
197 | |||
198 | of_platform_populate(node, NULL, NULL, dev); | ||
199 | |||
200 | platform_driver_register(&sti_drm_master_driver); | ||
201 | master = platform_device_register_resndata(dev, | ||
202 | DRIVER_NAME "__master", -1, | ||
203 | NULL, 0, NULL, 0); | ||
204 | if (!master) | ||
205 | return -EINVAL; | ||
206 | |||
207 | platform_set_drvdata(pdev, master); | ||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | static int sti_drm_platform_remove(struct platform_device *pdev) | ||
212 | { | ||
213 | struct platform_device *master = platform_get_drvdata(pdev); | ||
214 | |||
215 | of_platform_depopulate(&pdev->dev); | ||
216 | platform_device_unregister(master); | ||
217 | platform_driver_unregister(&sti_drm_master_driver); | ||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | static const struct of_device_id sti_drm_dt_ids[] = { | ||
222 | { .compatible = "st,sti-display-subsystem", }, | ||
223 | { /* end node */ }, | ||
224 | }; | ||
225 | MODULE_DEVICE_TABLE(of, sti_drm_dt_ids); | ||
226 | |||
227 | static struct platform_driver sti_drm_platform_driver = { | ||
228 | .probe = sti_drm_platform_probe, | ||
229 | .remove = sti_drm_platform_remove, | ||
230 | .driver = { | ||
231 | .owner = THIS_MODULE, | ||
232 | .name = DRIVER_NAME, | ||
233 | .of_match_table = sti_drm_dt_ids, | ||
234 | }, | ||
235 | }; | ||
236 | |||
237 | module_platform_driver(sti_drm_platform_driver); | ||
238 | |||
239 | MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>"); | ||
240 | MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver"); | ||
241 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/gpu/drm/sti/sti_drm_drv.h b/drivers/gpu/drm/sti/sti_drm_drv.h new file mode 100644 index 000000000000..ec5e2eb8dff9 --- /dev/null +++ b/drivers/gpu/drm/sti/sti_drm_drv.h | |||
@@ -0,0 +1,29 @@ | |||
1 | /* | ||
2 | * Copyright (C) STMicroelectronics SA 2014 | ||
3 | * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics. | ||
4 | * License terms: GNU General Public License (GPL), version 2 | ||
5 | */ | ||
6 | |||
7 | #ifndef _STI_DRM_DRV_H_ | ||
8 | #define _STI_DRM_DRV_H_ | ||
9 | |||
10 | #include <drm/drmP.h> | ||
11 | |||
12 | struct sti_compositor; | ||
13 | struct sti_tvout; | ||
14 | |||
15 | /** | ||
16 | * STI drm private structure | ||
17 | * This structure is stored as private in the drm_device | ||
18 | * | ||
19 | * @compo: compositor | ||
20 | * @plane_zorder_property: z-order property for CRTC planes | ||
21 | * @drm_dev: drm device | ||
22 | */ | ||
23 | struct sti_drm_private { | ||
24 | struct sti_compositor *compo; | ||
25 | struct drm_property *plane_zorder_property; | ||
26 | struct drm_device *drm_dev; | ||
27 | }; | ||
28 | |||
29 | #endif | ||
diff --git a/drivers/gpu/drm/sti/sti_drm_plane.c b/drivers/gpu/drm/sti/sti_drm_plane.c new file mode 100644 index 000000000000..f4118d4cac22 --- /dev/null +++ b/drivers/gpu/drm/sti/sti_drm_plane.c | |||
@@ -0,0 +1,195 @@ | |||
1 | /* | ||
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 | ||
7 | */ | ||
8 | |||
9 | #include "sti_compositor.h" | ||
10 | #include "sti_drm_drv.h" | ||
11 | #include "sti_drm_plane.h" | ||
12 | #include "sti_vtg.h" | ||
13 | |||
14 | enum sti_layer_desc sti_layer_default_zorder[] = { | ||
15 | STI_GDP_0, | ||
16 | STI_VID_0, | ||
17 | STI_GDP_1, | ||
18 | STI_VID_1, | ||
19 | STI_GDP_2, | ||
20 | STI_GDP_3, | ||
21 | }; | ||
22 | |||
23 | /* (Background) < GDP0 < VID0 < GDP1 < VID1 < GDP2 < GDP3 < (ForeGround) */ | ||
24 | |||
25 | static int | ||
26 | sti_drm_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, | ||
27 | struct drm_framebuffer *fb, int crtc_x, int crtc_y, | ||
28 | unsigned int crtc_w, unsigned int crtc_h, | ||
29 | uint32_t src_x, uint32_t src_y, | ||
30 | uint32_t src_w, uint32_t src_h) | ||
31 | { | ||
32 | struct sti_layer *layer = to_sti_layer(plane); | ||
33 | struct sti_mixer *mixer = to_sti_mixer(crtc); | ||
34 | int res; | ||
35 | |||
36 | DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s) drm fb:%d\n", | ||
37 | crtc->base.id, sti_mixer_to_str(mixer), | ||
38 | plane->base.id, sti_layer_to_str(layer), fb->base.id); | ||
39 | DRM_DEBUG_KMS("(%dx%d)@(%d,%d)\n", crtc_w, crtc_h, crtc_x, crtc_y); | ||
40 | |||
41 | res = sti_mixer_set_layer_depth(mixer, layer); | ||
42 | if (res) { | ||
43 | DRM_ERROR("Can not set layer depth\n"); | ||
44 | return res; | ||
45 | } | ||
46 | |||
47 | /* src_x are in 16.16 format. */ | ||
48 | res = sti_layer_prepare(layer, fb, &crtc->mode, mixer->id, | ||
49 | crtc_x, crtc_y, crtc_w, crtc_h, | ||
50 | src_x >> 16, src_y >> 16, | ||
51 | src_w >> 16, src_h >> 16); | ||
52 | if (res) { | ||
53 | DRM_ERROR("Layer prepare failed\n"); | ||
54 | return res; | ||
55 | } | ||
56 | |||
57 | res = sti_layer_commit(layer); | ||
58 | if (res) { | ||
59 | DRM_ERROR("Layer commit failed\n"); | ||
60 | return res; | ||
61 | } | ||
62 | |||
63 | res = sti_mixer_set_layer_status(mixer, layer, true); | ||
64 | if (res) { | ||
65 | DRM_ERROR("Can not enable layer at mixer\n"); | ||
66 | return res; | ||
67 | } | ||
68 | |||
69 | return 0; | ||
70 | } | ||
71 | |||
72 | static int sti_drm_disable_plane(struct drm_plane *plane) | ||
73 | { | ||
74 | struct sti_layer *layer; | ||
75 | struct sti_mixer *mixer; | ||
76 | int lay_res, mix_res; | ||
77 | |||
78 | if (!plane->crtc) { | ||
79 | DRM_DEBUG_DRIVER("drm plane:%d not enabled\n", plane->base.id); | ||
80 | return 0; | ||
81 | } | ||
82 | layer = to_sti_layer(plane); | ||
83 | mixer = to_sti_mixer(plane->crtc); | ||
84 | |||
85 | DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n", | ||
86 | plane->crtc->base.id, sti_mixer_to_str(mixer), | ||
87 | plane->base.id, sti_layer_to_str(layer)); | ||
88 | |||
89 | /* Disable layer at mixer level */ | ||
90 | mix_res = sti_mixer_set_layer_status(mixer, layer, false); | ||
91 | if (mix_res) | ||
92 | DRM_ERROR("Can not disable layer at mixer\n"); | ||
93 | |||
94 | /* Wait a while to be sure that a Vsync event is received */ | ||
95 | msleep(WAIT_NEXT_VSYNC_MS); | ||
96 | |||
97 | /* Then disable layer itself */ | ||
98 | lay_res = sti_layer_disable(layer); | ||
99 | if (lay_res) | ||
100 | DRM_ERROR("Layer disable failed\n"); | ||
101 | |||
102 | if (lay_res || mix_res) | ||
103 | return -EINVAL; | ||
104 | |||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | static void sti_drm_plane_destroy(struct drm_plane *plane) | ||
109 | { | ||
110 | DRM_DEBUG_DRIVER("\n"); | ||
111 | |||
112 | sti_drm_disable_plane(plane); | ||
113 | drm_plane_cleanup(plane); | ||
114 | } | ||
115 | |||
116 | static int sti_drm_plane_set_property(struct drm_plane *plane, | ||
117 | struct drm_property *property, | ||
118 | uint64_t val) | ||
119 | { | ||
120 | struct drm_device *dev = plane->dev; | ||
121 | struct sti_drm_private *private = dev->dev_private; | ||
122 | struct sti_layer *layer = to_sti_layer(plane); | ||
123 | |||
124 | DRM_DEBUG_DRIVER("\n"); | ||
125 | |||
126 | if (property == private->plane_zorder_property) { | ||
127 | layer->zorder = val; | ||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | return -EINVAL; | ||
132 | } | ||
133 | |||
134 | static struct drm_plane_funcs sti_drm_plane_funcs = { | ||
135 | .update_plane = sti_drm_update_plane, | ||
136 | .disable_plane = sti_drm_disable_plane, | ||
137 | .destroy = sti_drm_plane_destroy, | ||
138 | .set_property = sti_drm_plane_set_property, | ||
139 | }; | ||
140 | |||
141 | static void sti_drm_plane_attach_zorder_property(struct drm_plane *plane, | ||
142 | uint64_t default_val) | ||
143 | { | ||
144 | struct drm_device *dev = plane->dev; | ||
145 | struct sti_drm_private *private = dev->dev_private; | ||
146 | struct drm_property *prop; | ||
147 | struct sti_layer *layer = to_sti_layer(plane); | ||
148 | |||
149 | prop = private->plane_zorder_property; | ||
150 | if (!prop) { | ||
151 | prop = drm_property_create_range(dev, 0, "zpos", 0, | ||
152 | GAM_MIXER_NB_DEPTH_LEVEL - 1); | ||
153 | if (!prop) | ||
154 | return; | ||
155 | |||
156 | private->plane_zorder_property = prop; | ||
157 | } | ||
158 | |||
159 | drm_object_attach_property(&plane->base, prop, default_val); | ||
160 | layer->zorder = default_val; | ||
161 | } | ||
162 | |||
163 | struct drm_plane *sti_drm_plane_init(struct drm_device *dev, | ||
164 | struct sti_layer *layer, | ||
165 | unsigned int possible_crtcs, | ||
166 | enum drm_plane_type type) | ||
167 | { | ||
168 | int err, i; | ||
169 | uint64_t default_zorder = 0; | ||
170 | |||
171 | err = drm_universal_plane_init(dev, &layer->plane, possible_crtcs, | ||
172 | &sti_drm_plane_funcs, | ||
173 | sti_layer_get_formats(layer), | ||
174 | sti_layer_get_nb_formats(layer), type); | ||
175 | if (err) { | ||
176 | DRM_ERROR("Failed to initialize plane\n"); | ||
177 | return NULL; | ||
178 | } | ||
179 | |||
180 | for (i = 0; i < ARRAY_SIZE(sti_layer_default_zorder); i++) | ||
181 | if (sti_layer_default_zorder[i] == layer->desc) | ||
182 | break; | ||
183 | |||
184 | default_zorder = i; | ||
185 | |||
186 | if (type == DRM_PLANE_TYPE_OVERLAY) | ||
187 | sti_drm_plane_attach_zorder_property(&layer->plane, | ||
188 | default_zorder); | ||
189 | |||
190 | DRM_DEBUG_DRIVER("drm plane:%d mapped to %s with zorder:%llu\n", | ||
191 | layer->plane.base.id, | ||
192 | sti_layer_to_str(layer), default_zorder); | ||
193 | |||
194 | return &layer->plane; | ||
195 | } | ||
diff --git a/drivers/gpu/drm/sti/sti_drm_plane.h b/drivers/gpu/drm/sti/sti_drm_plane.h new file mode 100644 index 000000000000..4f191839f2a7 --- /dev/null +++ b/drivers/gpu/drm/sti/sti_drm_plane.h | |||
@@ -0,0 +1,18 @@ | |||
1 | /* | ||
2 | * Copyright (C) STMicroelectronics SA 2014 | ||
3 | * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics. | ||
4 | * License terms: GNU General Public License (GPL), version 2 | ||
5 | */ | ||
6 | |||
7 | #ifndef _STI_DRM_PLANE_H_ | ||
8 | #define _STI_DRM_PLANE_H_ | ||
9 | |||
10 | #include <drm/drmP.h> | ||
11 | |||
12 | struct sti_layer; | ||
13 | |||
14 | struct drm_plane *sti_drm_plane_init(struct drm_device *dev, | ||
15 | struct sti_layer *layer, | ||
16 | unsigned int possible_crtcs, | ||
17 | enum drm_plane_type type); | ||
18 | #endif | ||