diff options
author | Benjamin Gaignard <benjamin.gaignard@linaro.org> | 2014-07-30 13:28:27 -0400 |
---|---|---|
committer | Benjamin Gaignard <benjamin.gaignard@linaro.org> | 2014-07-30 13:28:27 -0400 |
commit | d219673d8437ff1073c11d30ac496fa42b09662c (patch) | |
tree | 08bef22f55cfaeea4b3f3c12e3421547ed1f490f /drivers/gpu/drm | |
parent | e21e21939ce0031c11605cc4a7fed83c8ed42b52 (diff) |
drm: sti: add Compositor
Compositor control all the input sub-device (VID, GDP)
and the mixer(s).
It is the main entry point for composition.
Layer interface is used to control the abstracted layers.
Add debug in mixer and GDP.
Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
Reviewed-by: Rob Clark <robdclark@gmail.com>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r-- | drivers/gpu/drm/sti/Kconfig | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/Makefile | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_compositor.c | 236 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_compositor.h | 90 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_gdp.c | 33 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_layer.c | 197 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_mixer.c | 6 |
7 files changed, 566 insertions, 1 deletions
diff --git a/drivers/gpu/drm/sti/Kconfig b/drivers/gpu/drm/sti/Kconfig index a18df02dc95a..11d372c79bea 100644 --- a/drivers/gpu/drm/sti/Kconfig +++ b/drivers/gpu/drm/sti/Kconfig | |||
@@ -1,5 +1,6 @@ | |||
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_CMA_HELPER | ||
4 | help | 5 | help |
5 | Choose this option to enable DRM on STM stiH41x chipset | 6 | Choose this option to enable DRM on STM stiH41x chipset |
diff --git a/drivers/gpu/drm/sti/Makefile b/drivers/gpu/drm/sti/Makefile index 4a3a8168c30e..c5838f20f122 100644 --- a/drivers/gpu/drm/sti/Makefile +++ b/drivers/gpu/drm/sti/Makefile | |||
@@ -1,7 +1,9 @@ | |||
1 | sticompositor-y := \ | 1 | sticompositor-y := \ |
2 | sti_layer.o \ | ||
2 | sti_mixer.o \ | 3 | sti_mixer.o \ |
3 | sti_gdp.o \ | 4 | sti_gdp.o \ |
4 | sti_vid.o | 5 | sti_vid.o \ |
6 | sti_compositor.o | ||
5 | 7 | ||
6 | stihdmi-y := sti_hdmi.o \ | 8 | stihdmi-y := sti_hdmi.o \ |
7 | sti_hdmi_tx3g0c55phy.o \ | 9 | sti_hdmi_tx3g0c55phy.o \ |
diff --git a/drivers/gpu/drm/sti/sti_compositor.c b/drivers/gpu/drm/sti/sti_compositor.c new file mode 100644 index 000000000000..a4164cfa906d --- /dev/null +++ b/drivers/gpu/drm/sti/sti_compositor.c | |||
@@ -0,0 +1,236 @@ | |||
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/component.h> | ||
10 | #include <linux/module.h> | ||
11 | #include <linux/platform_device.h> | ||
12 | #include <linux/reset.h> | ||
13 | |||
14 | #include <drm/drmP.h> | ||
15 | |||
16 | #include "sti_compositor.h" | ||
17 | #include "sti_gdp.h" | ||
18 | #include "sti_vtg.h" | ||
19 | |||
20 | /* | ||
21 | * stiH407 compositor properties | ||
22 | */ | ||
23 | struct sti_compositor_data stih407_compositor_data = { | ||
24 | .nb_subdev = 6, | ||
25 | .subdev_desc = { | ||
26 | {STI_GPD_SUBDEV, (int)STI_GDP_0, 0x100}, | ||
27 | {STI_GPD_SUBDEV, (int)STI_GDP_1, 0x200}, | ||
28 | {STI_GPD_SUBDEV, (int)STI_GDP_2, 0x300}, | ||
29 | {STI_GPD_SUBDEV, (int)STI_GDP_3, 0x400}, | ||
30 | {STI_VID_SUBDEV, (int)STI_VID_0, 0x700}, | ||
31 | {STI_MIXER_MAIN_SUBDEV, STI_MIXER_MAIN, 0xC00} | ||
32 | }, | ||
33 | }; | ||
34 | |||
35 | /* | ||
36 | * stiH416 compositor properties | ||
37 | * Note: | ||
38 | * on stih416 MIXER_AUX has a different base address from MIXER_MAIN | ||
39 | * Moreover, GDPx is different for Main and Aux Mixer. So this subdev map does | ||
40 | * not fit for stiH416 if we want to enable the MIXER_AUX. | ||
41 | */ | ||
42 | struct sti_compositor_data stih416_compositor_data = { | ||
43 | .nb_subdev = 3, | ||
44 | .subdev_desc = { | ||
45 | {STI_GPD_SUBDEV, (int)STI_GDP_0, 0x100}, | ||
46 | {STI_GPD_SUBDEV, (int)STI_GDP_1, 0x200}, | ||
47 | {STI_MIXER_MAIN_SUBDEV, STI_MIXER_MAIN, 0xC00} | ||
48 | }, | ||
49 | }; | ||
50 | |||
51 | static int sti_compositor_init_subdev(struct sti_compositor *compo, | ||
52 | struct sti_compositor_subdev_descriptor *desc, | ||
53 | unsigned int array_size) | ||
54 | { | ||
55 | unsigned int i, mixer_id = 0, layer_id = 0; | ||
56 | |||
57 | for (i = 0; i < array_size; i++) { | ||
58 | switch (desc[i].type) { | ||
59 | case STI_MIXER_MAIN_SUBDEV: | ||
60 | case STI_MIXER_AUX_SUBDEV: | ||
61 | compo->mixer[mixer_id++] = | ||
62 | sti_mixer_create(compo->dev, desc[i].id, | ||
63 | compo->regs + desc[i].offset); | ||
64 | break; | ||
65 | case STI_GPD_SUBDEV: | ||
66 | case STI_VID_SUBDEV: | ||
67 | compo->layer[layer_id++] = | ||
68 | sti_layer_create(compo->dev, desc[i].id, | ||
69 | compo->regs + desc[i].offset); | ||
70 | break; | ||
71 | /* case STI_CURSOR_SUBDEV : TODO */ | ||
72 | default: | ||
73 | DRM_ERROR("Unknow subdev compoment type\n"); | ||
74 | return 1; | ||
75 | } | ||
76 | |||
77 | } | ||
78 | compo->nb_mixers = mixer_id; | ||
79 | compo->nb_layers = layer_id; | ||
80 | |||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | static int sti_compositor_bind(struct device *dev, struct device *master, | ||
85 | void *data) | ||
86 | { | ||
87 | struct sti_compositor *compo = dev_get_drvdata(dev); | ||
88 | struct drm_device *drm_dev = data; | ||
89 | unsigned int i, crtc = 0, plane = 0; | ||
90 | |||
91 | drm_vblank_init(drm_dev, crtc); | ||
92 | /* Allow usage of vblank without having to call drm_irq_install */ | ||
93 | drm_dev->irq_enabled = 1; | ||
94 | |||
95 | |||
96 | DRM_DEBUG_DRIVER("Initialized %d DRM CRTC(s) and %d DRM plane(s)\n", | ||
97 | crtc, plane); | ||
98 | DRM_DEBUG_DRIVER("DRM plane(s) for VID/VDP not created yet\n"); | ||
99 | |||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | static void sti_compositor_unbind(struct device *dev, struct device *master, | ||
104 | void *data) | ||
105 | { | ||
106 | /* do nothing */ | ||
107 | } | ||
108 | |||
109 | static const struct component_ops sti_compositor_ops = { | ||
110 | .bind = sti_compositor_bind, | ||
111 | .unbind = sti_compositor_unbind, | ||
112 | }; | ||
113 | |||
114 | static const struct of_device_id compositor_of_match[] = { | ||
115 | { | ||
116 | .compatible = "st,stih416-compositor", | ||
117 | .data = &stih416_compositor_data, | ||
118 | }, { | ||
119 | .compatible = "st,stih407-compositor", | ||
120 | .data = &stih407_compositor_data, | ||
121 | }, { | ||
122 | /* end node */ | ||
123 | } | ||
124 | }; | ||
125 | MODULE_DEVICE_TABLE(of, compositor_of_match); | ||
126 | |||
127 | static int sti_compositor_probe(struct platform_device *pdev) | ||
128 | { | ||
129 | struct device *dev = &pdev->dev; | ||
130 | struct device_node *np = dev->of_node; | ||
131 | struct device_node *vtg_np; | ||
132 | struct sti_compositor *compo; | ||
133 | struct resource *res; | ||
134 | int err; | ||
135 | |||
136 | compo = devm_kzalloc(dev, sizeof(*compo), GFP_KERNEL); | ||
137 | if (!compo) { | ||
138 | DRM_ERROR("Failed to allocate compositor context\n"); | ||
139 | return -ENOMEM; | ||
140 | } | ||
141 | compo->dev = dev; | ||
142 | |||
143 | /* populate data structure depending on compatibility */ | ||
144 | BUG_ON(!of_match_node(compositor_of_match, np)->data); | ||
145 | |||
146 | memcpy(&compo->data, of_match_node(compositor_of_match, np)->data, | ||
147 | sizeof(struct sti_compositor_data)); | ||
148 | |||
149 | /* Get Memory ressources */ | ||
150 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
151 | if (res == NULL) { | ||
152 | DRM_ERROR("Get memory resource failed\n"); | ||
153 | return -ENXIO; | ||
154 | } | ||
155 | compo->regs = devm_ioremap(dev, res->start, resource_size(res)); | ||
156 | if (compo->regs == NULL) { | ||
157 | DRM_ERROR("Register mapping failed\n"); | ||
158 | return -ENXIO; | ||
159 | } | ||
160 | |||
161 | /* Get clock resources */ | ||
162 | compo->clk_compo_main = devm_clk_get(dev, "compo_main"); | ||
163 | if (IS_ERR(compo->clk_compo_main)) { | ||
164 | DRM_ERROR("Cannot get compo_main clock\n"); | ||
165 | return PTR_ERR(compo->clk_compo_main); | ||
166 | } | ||
167 | |||
168 | compo->clk_compo_aux = devm_clk_get(dev, "compo_aux"); | ||
169 | if (IS_ERR(compo->clk_compo_aux)) { | ||
170 | DRM_ERROR("Cannot get compo_aux clock\n"); | ||
171 | return PTR_ERR(compo->clk_compo_aux); | ||
172 | } | ||
173 | |||
174 | compo->clk_pix_main = devm_clk_get(dev, "pix_main"); | ||
175 | if (IS_ERR(compo->clk_pix_main)) { | ||
176 | DRM_ERROR("Cannot get pix_main clock\n"); | ||
177 | return PTR_ERR(compo->clk_pix_main); | ||
178 | } | ||
179 | |||
180 | compo->clk_pix_aux = devm_clk_get(dev, "pix_aux"); | ||
181 | if (IS_ERR(compo->clk_pix_aux)) { | ||
182 | DRM_ERROR("Cannot get pix_aux clock\n"); | ||
183 | return PTR_ERR(compo->clk_pix_aux); | ||
184 | } | ||
185 | |||
186 | /* Get reset resources */ | ||
187 | compo->rst_main = devm_reset_control_get(dev, "compo-main"); | ||
188 | /* Take compo main out of reset */ | ||
189 | if (!IS_ERR(compo->rst_main)) | ||
190 | reset_control_deassert(compo->rst_main); | ||
191 | |||
192 | compo->rst_aux = devm_reset_control_get(dev, "compo-aux"); | ||
193 | /* Take compo aux out of reset */ | ||
194 | if (!IS_ERR(compo->rst_aux)) | ||
195 | reset_control_deassert(compo->rst_aux); | ||
196 | |||
197 | vtg_np = of_parse_phandle(pdev->dev.of_node, "st,vtg", 0); | ||
198 | if (vtg_np) | ||
199 | compo->vtg_main = of_vtg_find(vtg_np); | ||
200 | |||
201 | vtg_np = of_parse_phandle(pdev->dev.of_node, "st,vtg", 1); | ||
202 | if (vtg_np) | ||
203 | compo->vtg_aux = of_vtg_find(vtg_np); | ||
204 | |||
205 | /* Initialize compositor subdevices */ | ||
206 | err = sti_compositor_init_subdev(compo, compo->data.subdev_desc, | ||
207 | compo->data.nb_subdev); | ||
208 | if (err) | ||
209 | return err; | ||
210 | |||
211 | platform_set_drvdata(pdev, compo); | ||
212 | |||
213 | return component_add(&pdev->dev, &sti_compositor_ops); | ||
214 | } | ||
215 | |||
216 | static int sti_compositor_remove(struct platform_device *pdev) | ||
217 | { | ||
218 | component_del(&pdev->dev, &sti_compositor_ops); | ||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | static struct platform_driver sti_compositor_driver = { | ||
223 | .driver = { | ||
224 | .name = "sti-compositor", | ||
225 | .owner = THIS_MODULE, | ||
226 | .of_match_table = compositor_of_match, | ||
227 | }, | ||
228 | .probe = sti_compositor_probe, | ||
229 | .remove = sti_compositor_remove, | ||
230 | }; | ||
231 | |||
232 | module_platform_driver(sti_compositor_driver); | ||
233 | |||
234 | MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>"); | ||
235 | MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver"); | ||
236 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/gpu/drm/sti/sti_compositor.h b/drivers/gpu/drm/sti/sti_compositor.h new file mode 100644 index 000000000000..3ea19db72e0f --- /dev/null +++ b/drivers/gpu/drm/sti/sti_compositor.h | |||
@@ -0,0 +1,90 @@ | |||
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 | #ifndef _STI_COMPOSITOR_H_ | ||
10 | #define _STI_COMPOSITOR_H_ | ||
11 | |||
12 | #include <linux/clk.h> | ||
13 | #include <linux/kernel.h> | ||
14 | |||
15 | #include "sti_layer.h" | ||
16 | #include "sti_mixer.h" | ||
17 | |||
18 | #define WAIT_NEXT_VSYNC_MS 50 /*ms*/ | ||
19 | |||
20 | #define STI_MAX_LAYER 8 | ||
21 | #define STI_MAX_MIXER 2 | ||
22 | |||
23 | enum sti_compositor_subdev_type { | ||
24 | STI_MIXER_MAIN_SUBDEV, | ||
25 | STI_MIXER_AUX_SUBDEV, | ||
26 | STI_GPD_SUBDEV, | ||
27 | STI_VID_SUBDEV, | ||
28 | STI_CURSOR_SUBDEV, | ||
29 | }; | ||
30 | |||
31 | struct sti_compositor_subdev_descriptor { | ||
32 | enum sti_compositor_subdev_type type; | ||
33 | int id; | ||
34 | unsigned int offset; | ||
35 | }; | ||
36 | |||
37 | /** | ||
38 | * STI Compositor data structure | ||
39 | * | ||
40 | * @nb_subdev: number of subdevices supported by the compositor | ||
41 | * @subdev_desc: subdev list description | ||
42 | */ | ||
43 | #define MAX_SUBDEV 9 | ||
44 | struct sti_compositor_data { | ||
45 | unsigned int nb_subdev; | ||
46 | struct sti_compositor_subdev_descriptor subdev_desc[MAX_SUBDEV]; | ||
47 | }; | ||
48 | |||
49 | /** | ||
50 | * STI Compositor structure | ||
51 | * | ||
52 | * @dev: driver device | ||
53 | * @regs: registers (main) | ||
54 | * @data: device data | ||
55 | * @clk_compo_main: clock for main compo | ||
56 | * @clk_compo_aux: clock for aux compo | ||
57 | * @clk_pix_main: pixel clock for main path | ||
58 | * @clk_pix_aux: pixel clock for aux path | ||
59 | * @rst_main: reset control of the main path | ||
60 | * @rst_aux: reset control of the aux path | ||
61 | * @mixer: array of mixers | ||
62 | * @vtg_main: vtg for main data path | ||
63 | * @vtg_aux: vtg for auxillary data path | ||
64 | * @layer: array of layers | ||
65 | * @nb_mixers: number of mixers for this compositor | ||
66 | * @nb_layers: number of layers (GDP,VID,...) for this compositor | ||
67 | * @enable: true if compositor is enable else false | ||
68 | * @vtg_vblank_nb: callback for VTG VSYNC notification | ||
69 | */ | ||
70 | struct sti_compositor { | ||
71 | struct device *dev; | ||
72 | void __iomem *regs; | ||
73 | struct sti_compositor_data data; | ||
74 | struct clk *clk_compo_main; | ||
75 | struct clk *clk_compo_aux; | ||
76 | struct clk *clk_pix_main; | ||
77 | struct clk *clk_pix_aux; | ||
78 | struct reset_control *rst_main; | ||
79 | struct reset_control *rst_aux; | ||
80 | struct sti_mixer *mixer[STI_MAX_MIXER]; | ||
81 | struct sti_vtg *vtg_main; | ||
82 | struct sti_vtg *vtg_aux; | ||
83 | struct sti_layer *layer[STI_MAX_LAYER]; | ||
84 | int nb_mixers; | ||
85 | int nb_layers; | ||
86 | bool enable; | ||
87 | struct notifier_block vtg_vblank_nb; | ||
88 | }; | ||
89 | |||
90 | #endif | ||
diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c index 7f557676704d..4e30b74559f5 100644 --- a/drivers/gpu/drm/sti/sti_gdp.c +++ b/drivers/gpu/drm/sti/sti_gdp.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <linux/clk.h> | 9 | #include <linux/clk.h> |
10 | #include <linux/dma-mapping.h> | 10 | #include <linux/dma-mapping.h> |
11 | 11 | ||
12 | #include "sti_compositor.h" | ||
12 | #include "sti_gdp.h" | 13 | #include "sti_gdp.h" |
13 | #include "sti_layer.h" | 14 | #include "sti_layer.h" |
14 | #include "sti_vtg.h" | 15 | #include "sti_vtg.h" |
@@ -182,6 +183,10 @@ static struct sti_gdp_node_list *sti_gdp_get_free_nodes(struct sti_layer *layer) | |||
182 | (virt_nvn != gdp->node_list[i].top_field)) | 183 | (virt_nvn != gdp->node_list[i].top_field)) |
183 | return &gdp->node_list[i]; | 184 | return &gdp->node_list[i]; |
184 | 185 | ||
186 | /* in hazardious cases restart with the first node */ | ||
187 | DRM_ERROR("inconsistent NVN for %s: 0x%08X\n", | ||
188 | sti_layer_to_str(layer), hw_nvn); | ||
189 | |||
185 | end: | 190 | end: |
186 | return &gdp->node_list[0]; | 191 | return &gdp->node_list[0]; |
187 | } | 192 | } |
@@ -215,6 +220,9 @@ struct sti_gdp_node_list *sti_gdp_get_current_nodes(struct sti_layer *layer) | |||
215 | return &gdp->node_list[i]; | 220 | return &gdp->node_list[i]; |
216 | 221 | ||
217 | end: | 222 | end: |
223 | DRM_DEBUG_DRIVER("Warning, NVN 0x%08X for %s does not match any node\n", | ||
224 | hw_nvn, sti_layer_to_str(layer)); | ||
225 | |||
218 | return NULL; | 226 | return NULL; |
219 | } | 227 | } |
220 | 228 | ||
@@ -235,6 +243,7 @@ static int sti_gdp_prepare_layer(struct sti_layer *layer, bool first_prepare) | |||
235 | struct drm_display_mode *mode = layer->mode; | 243 | struct drm_display_mode *mode = layer->mode; |
236 | struct device *dev = layer->dev; | 244 | struct device *dev = layer->dev; |
237 | struct sti_gdp *gdp = to_sti_gdp(layer); | 245 | struct sti_gdp *gdp = to_sti_gdp(layer); |
246 | struct sti_compositor *compo = dev_get_drvdata(dev); | ||
238 | int format; | 247 | int format; |
239 | unsigned int depth, bpp; | 248 | unsigned int depth, bpp; |
240 | int rate = mode->clock * 1000; | 249 | int rate = mode->clock * 1000; |
@@ -245,6 +254,9 @@ static int sti_gdp_prepare_layer(struct sti_layer *layer, bool first_prepare) | |||
245 | top_field = list->top_field; | 254 | top_field = list->top_field; |
246 | btm_field = list->btm_field; | 255 | btm_field = list->btm_field; |
247 | 256 | ||
257 | dev_dbg(dev, "%s %s top_node:0x%p btm_node:0x%p\n", __func__, | ||
258 | sti_layer_to_str(layer), top_field, btm_field); | ||
259 | |||
248 | /* Build the top field from layer params */ | 260 | /* Build the top field from layer params */ |
249 | top_field->gam_gdp_agc = GAM_GDP_AGC_FULL_RANGE; | 261 | top_field->gam_gdp_agc = GAM_GDP_AGC_FULL_RANGE; |
250 | top_field->gam_gdp_ctl = WAIT_NEXT_VSYNC; | 262 | top_field->gam_gdp_ctl = WAIT_NEXT_VSYNC; |
@@ -289,6 +301,14 @@ static int sti_gdp_prepare_layer(struct sti_layer *layer, bool first_prepare) | |||
289 | layer->pitches[0]; | 301 | layer->pitches[0]; |
290 | 302 | ||
291 | if (first_prepare) { | 303 | if (first_prepare) { |
304 | /* Register gdp callback */ | ||
305 | if (sti_vtg_register_client(layer->mixer_id == STI_MIXER_MAIN ? | ||
306 | compo->vtg_main : compo->vtg_aux, | ||
307 | &gdp->vtg_field_nb, layer->mixer_id)) { | ||
308 | DRM_ERROR("Cannot register VTG notifier\n"); | ||
309 | return 1; | ||
310 | } | ||
311 | |||
292 | /* Set and enable gdp clock */ | 312 | /* Set and enable gdp clock */ |
293 | if (gdp->clk_pix) { | 313 | if (gdp->clk_pix) { |
294 | res = clk_set_rate(gdp->clk_pix, rate); | 314 | res = clk_set_rate(gdp->clk_pix, rate); |
@@ -333,6 +353,9 @@ static int sti_gdp_commit_layer(struct sti_layer *layer) | |||
333 | u32 dma_updated_btm = virt_to_dma(layer->dev, updated_btm_node); | 353 | u32 dma_updated_btm = virt_to_dma(layer->dev, updated_btm_node); |
334 | struct sti_gdp_node_list *curr_list = sti_gdp_get_current_nodes(layer); | 354 | struct sti_gdp_node_list *curr_list = sti_gdp_get_current_nodes(layer); |
335 | 355 | ||
356 | dev_dbg(layer->dev, "%s %s top/btm_node:0x%p/0x%p\n", __func__, | ||
357 | sti_layer_to_str(layer), | ||
358 | updated_top_node, updated_btm_node); | ||
336 | dev_dbg(layer->dev, "Current NVN:0x%X\n", | 359 | dev_dbg(layer->dev, "Current NVN:0x%X\n", |
337 | readl(layer->regs + GAM_GDP_NVN_OFFSET)); | 360 | readl(layer->regs + GAM_GDP_NVN_OFFSET)); |
338 | dev_dbg(layer->dev, "Posted buff: %lx current buff: %x\n", | 361 | dev_dbg(layer->dev, "Posted buff: %lx current buff: %x\n", |
@@ -342,6 +365,9 @@ static int sti_gdp_commit_layer(struct sti_layer *layer) | |||
342 | if (curr_list == NULL) { | 365 | if (curr_list == NULL) { |
343 | /* First update or invalid node should directly write in the | 366 | /* First update or invalid node should directly write in the |
344 | * hw register */ | 367 | * hw register */ |
368 | DRM_DEBUG_DRIVER("%s first update (or invalid node)", | ||
369 | sti_layer_to_str(layer)); | ||
370 | |||
345 | writel(gdp->is_curr_top == true ? | 371 | writel(gdp->is_curr_top == true ? |
346 | dma_updated_btm : dma_updated_top, | 372 | dma_updated_btm : dma_updated_top, |
347 | layer->regs + GAM_GDP_NVN_OFFSET); | 373 | layer->regs + GAM_GDP_NVN_OFFSET); |
@@ -380,6 +406,9 @@ static int sti_gdp_disable_layer(struct sti_layer *layer) | |||
380 | { | 406 | { |
381 | unsigned int i; | 407 | unsigned int i; |
382 | struct sti_gdp *gdp = to_sti_gdp(layer); | 408 | struct sti_gdp *gdp = to_sti_gdp(layer); |
409 | struct sti_compositor *compo = dev_get_drvdata(layer->dev); | ||
410 | |||
411 | DRM_DEBUG_DRIVER("%s\n", sti_layer_to_str(layer)); | ||
383 | 412 | ||
384 | /* Set the nodes as 'to be ignored on mixer' */ | 413 | /* Set the nodes as 'to be ignored on mixer' */ |
385 | for (i = 0; i < GDP_NODE_NB_BANK; i++) { | 414 | for (i = 0; i < GDP_NODE_NB_BANK; i++) { |
@@ -387,6 +416,10 @@ static int sti_gdp_disable_layer(struct sti_layer *layer) | |||
387 | gdp->node_list[i].btm_field->gam_gdp_ppt |= GAM_GDP_PPT_IGNORE; | 416 | gdp->node_list[i].btm_field->gam_gdp_ppt |= GAM_GDP_PPT_IGNORE; |
388 | } | 417 | } |
389 | 418 | ||
419 | if (sti_vtg_unregister_client(layer->mixer_id == STI_MIXER_MAIN ? | ||
420 | compo->vtg_main : compo->vtg_aux, &gdp->vtg_field_nb)) | ||
421 | DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n"); | ||
422 | |||
390 | if (gdp->clk_pix) | 423 | if (gdp->clk_pix) |
391 | clk_disable_unprepare(gdp->clk_pix); | 424 | clk_disable_unprepare(gdp->clk_pix); |
392 | 425 | ||
diff --git a/drivers/gpu/drm/sti/sti_layer.c b/drivers/gpu/drm/sti/sti_layer.c new file mode 100644 index 000000000000..06a587c4f1bb --- /dev/null +++ b/drivers/gpu/drm/sti/sti_layer.c | |||
@@ -0,0 +1,197 @@ | |||
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 <drm/drmP.h> | ||
10 | #include <drm/drm_gem_cma_helper.h> | ||
11 | #include <drm/drm_fb_cma_helper.h> | ||
12 | |||
13 | #include "sti_compositor.h" | ||
14 | #include "sti_gdp.h" | ||
15 | #include "sti_layer.h" | ||
16 | #include "sti_vid.h" | ||
17 | |||
18 | const char *sti_layer_to_str(struct sti_layer *layer) | ||
19 | { | ||
20 | switch (layer->desc) { | ||
21 | case STI_GDP_0: | ||
22 | return "GDP0"; | ||
23 | case STI_GDP_1: | ||
24 | return "GDP1"; | ||
25 | case STI_GDP_2: | ||
26 | return "GDP2"; | ||
27 | case STI_GDP_3: | ||
28 | return "GDP3"; | ||
29 | case STI_VID_0: | ||
30 | return "VID0"; | ||
31 | case STI_VID_1: | ||
32 | return "VID1"; | ||
33 | case STI_CURSOR: | ||
34 | return "CURSOR"; | ||
35 | default: | ||
36 | return "<UNKNOWN LAYER>"; | ||
37 | } | ||
38 | } | ||
39 | |||
40 | struct sti_layer *sti_layer_create(struct device *dev, int desc, | ||
41 | void __iomem *baseaddr) | ||
42 | { | ||
43 | |||
44 | struct sti_layer *layer = NULL; | ||
45 | |||
46 | switch (desc & STI_LAYER_TYPE_MASK) { | ||
47 | case STI_GDP: | ||
48 | layer = sti_gdp_create(dev, desc); | ||
49 | break; | ||
50 | case STI_VID: | ||
51 | layer = sti_vid_create(dev); | ||
52 | break; | ||
53 | } | ||
54 | |||
55 | if (!layer) { | ||
56 | DRM_ERROR("Failed to create layer\n"); | ||
57 | return NULL; | ||
58 | } | ||
59 | |||
60 | layer->desc = desc; | ||
61 | layer->dev = dev; | ||
62 | layer->regs = baseaddr; | ||
63 | |||
64 | layer->ops->init(layer); | ||
65 | |||
66 | DRM_DEBUG_DRIVER("%s created\n", sti_layer_to_str(layer)); | ||
67 | |||
68 | return layer; | ||
69 | } | ||
70 | |||
71 | int sti_layer_prepare(struct sti_layer *layer, struct drm_framebuffer *fb, | ||
72 | struct drm_display_mode *mode, int mixer_id, | ||
73 | int dest_x, int dest_y, int dest_w, int dest_h, | ||
74 | int src_x, int src_y, int src_w, int src_h) | ||
75 | { | ||
76 | int ret; | ||
77 | unsigned int i; | ||
78 | struct drm_gem_cma_object *cma_obj; | ||
79 | |||
80 | if (!layer || !fb || !mode) { | ||
81 | DRM_ERROR("Null fb, layer or mode\n"); | ||
82 | return 1; | ||
83 | } | ||
84 | |||
85 | cma_obj = drm_fb_cma_get_gem_obj(fb, 0); | ||
86 | if (!cma_obj) { | ||
87 | DRM_ERROR("Can't get CMA GEM object for fb\n"); | ||
88 | return 1; | ||
89 | } | ||
90 | |||
91 | layer->fb = fb; | ||
92 | layer->mode = mode; | ||
93 | layer->mixer_id = mixer_id; | ||
94 | layer->dst_x = dest_x; | ||
95 | layer->dst_y = dest_y; | ||
96 | layer->dst_w = clamp_val(dest_w, 0, mode->crtc_hdisplay - dest_x); | ||
97 | layer->dst_h = clamp_val(dest_h, 0, mode->crtc_vdisplay - dest_y); | ||
98 | layer->src_x = src_x; | ||
99 | layer->src_y = src_y; | ||
100 | layer->src_w = src_w; | ||
101 | layer->src_h = src_h; | ||
102 | layer->format = fb->pixel_format; | ||
103 | layer->paddr = cma_obj->paddr; | ||
104 | for (i = 0; i < 4; i++) { | ||
105 | layer->pitches[i] = fb->pitches[i]; | ||
106 | layer->offsets[i] = fb->offsets[i]; | ||
107 | } | ||
108 | |||
109 | DRM_DEBUG_DRIVER("%s is associated with mixer_id %d\n", | ||
110 | sti_layer_to_str(layer), | ||
111 | layer->mixer_id); | ||
112 | DRM_DEBUG_DRIVER("%s dst=(%dx%d)@(%d,%d) - src=(%dx%d)@(%d,%d)\n", | ||
113 | sti_layer_to_str(layer), | ||
114 | layer->dst_w, layer->dst_h, layer->dst_x, layer->dst_y, | ||
115 | layer->src_w, layer->src_h, layer->src_x, | ||
116 | layer->src_y); | ||
117 | |||
118 | DRM_DEBUG_DRIVER("drm FB:%d format:%.4s phys@:0x%lx\n", fb->base.id, | ||
119 | (char *)&layer->format, (unsigned long)layer->paddr); | ||
120 | |||
121 | if (!layer->ops->prepare) | ||
122 | goto err_no_prepare; | ||
123 | |||
124 | ret = layer->ops->prepare(layer, !layer->enabled); | ||
125 | if (!ret) | ||
126 | layer->enabled = true; | ||
127 | |||
128 | return ret; | ||
129 | |||
130 | err_no_prepare: | ||
131 | DRM_ERROR("Cannot prepare\n"); | ||
132 | return 1; | ||
133 | } | ||
134 | |||
135 | int sti_layer_commit(struct sti_layer *layer) | ||
136 | { | ||
137 | if (!layer) | ||
138 | return 1; | ||
139 | |||
140 | if (!layer->ops->commit) | ||
141 | goto err_no_commit; | ||
142 | |||
143 | return layer->ops->commit(layer); | ||
144 | |||
145 | err_no_commit: | ||
146 | DRM_ERROR("Cannot commit\n"); | ||
147 | return 1; | ||
148 | } | ||
149 | |||
150 | int sti_layer_disable(struct sti_layer *layer) | ||
151 | { | ||
152 | int ret; | ||
153 | |||
154 | DRM_DEBUG_DRIVER("%s\n", sti_layer_to_str(layer)); | ||
155 | if (!layer) | ||
156 | return 1; | ||
157 | |||
158 | if (!layer->enabled) | ||
159 | return 0; | ||
160 | |||
161 | if (!layer->ops->disable) | ||
162 | goto err_no_disable; | ||
163 | |||
164 | ret = layer->ops->disable(layer); | ||
165 | if (!ret) | ||
166 | layer->enabled = false; | ||
167 | else | ||
168 | DRM_ERROR("Disable failed\n"); | ||
169 | |||
170 | return ret; | ||
171 | |||
172 | err_no_disable: | ||
173 | DRM_ERROR("Cannot disable\n"); | ||
174 | return 1; | ||
175 | } | ||
176 | |||
177 | const uint32_t *sti_layer_get_formats(struct sti_layer *layer) | ||
178 | { | ||
179 | if (!layer) | ||
180 | return NULL; | ||
181 | |||
182 | if (!layer->ops->get_formats) | ||
183 | return NULL; | ||
184 | |||
185 | return layer->ops->get_formats(layer); | ||
186 | } | ||
187 | |||
188 | unsigned int sti_layer_get_nb_formats(struct sti_layer *layer) | ||
189 | { | ||
190 | if (!layer) | ||
191 | return 0; | ||
192 | |||
193 | if (!layer->ops->get_nb_formats) | ||
194 | return 0; | ||
195 | |||
196 | return layer->ops->get_nb_formats(layer); | ||
197 | } | ||
diff --git a/drivers/gpu/drm/sti/sti_mixer.c b/drivers/gpu/drm/sti/sti_mixer.c index 5fa6dc5800aa..79f369db9fb6 100644 --- a/drivers/gpu/drm/sti/sti_mixer.c +++ b/drivers/gpu/drm/sti/sti_mixer.c | |||
@@ -6,6 +6,7 @@ | |||
6 | * License terms: GNU General Public License (GPL), version 2 | 6 | * License terms: GNU General Public License (GPL), version 2 |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include "sti_compositor.h" | ||
9 | #include "sti_mixer.h" | 10 | #include "sti_mixer.h" |
10 | #include "sti_vtg.h" | 11 | #include "sti_vtg.h" |
11 | 12 | ||
@@ -133,6 +134,8 @@ int sti_mixer_set_layer_depth(struct sti_mixer *mixer, struct sti_layer *layer) | |||
133 | mask = GAM_DEPTH_MASK_ID << (3 * depth); | 134 | mask = GAM_DEPTH_MASK_ID << (3 * depth); |
134 | layer_id = layer_id << (3 * depth); | 135 | layer_id = layer_id << (3 * depth); |
135 | 136 | ||
137 | DRM_DEBUG_DRIVER("%s %s depth=%d\n", sti_mixer_to_str(mixer), | ||
138 | sti_layer_to_str(layer), depth); | ||
136 | dev_dbg(mixer->dev, "GAM_MIXER_CRB val 0x%x mask 0x%x\n", | 139 | dev_dbg(mixer->dev, "GAM_MIXER_CRB val 0x%x mask 0x%x\n", |
137 | layer_id, mask); | 140 | layer_id, mask); |
138 | 141 | ||
@@ -195,6 +198,9 @@ int sti_mixer_set_layer_status(struct sti_mixer *mixer, | |||
195 | { | 198 | { |
196 | u32 mask, val; | 199 | u32 mask, val; |
197 | 200 | ||
201 | DRM_DEBUG_DRIVER("%s %s %s\n", status ? "enable" : "disable", | ||
202 | sti_mixer_to_str(mixer), sti_layer_to_str(layer)); | ||
203 | |||
198 | mask = sti_mixer_get_layer_mask(layer); | 204 | mask = sti_mixer_get_layer_mask(layer); |
199 | if (!mask) { | 205 | if (!mask) { |
200 | DRM_ERROR("Can not find layer mask\n"); | 206 | DRM_ERROR("Can not find layer mask\n"); |