diff options
author | Benjamin Gaignard <benjamin.gaignard@linaro.org> | 2014-07-28 04:30:18 -0400 |
---|---|---|
committer | Benjamin Gaignard <benjamin.gaignard@linaro.org> | 2014-07-30 13:26:59 -0400 |
commit | e21e21939ce0031c11605cc4a7fed83c8ed42b52 (patch) | |
tree | 866c24d9e96f8f801c8fc1a5ec512a440a1ae349 | |
parent | cfd8d744fe0dc08faae4a35d333193dcca3ea891 (diff) |
drm: sti: add Mixer
Mixer hardware IP is responsible of mixing the different inputs layers.
Z-order is managed by the mixer.
We could 2 mixers: one for main path and one for auxillary path
Mixers are part of Compositor hardware block
Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
Reviewed-by: Rob Clark <robdclark@gmail.com>
-rw-r--r-- | drivers/gpu/drm/sti/Makefile | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_mixer.c | 243 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_mixer.h | 54 |
3 files changed, 299 insertions, 1 deletions
diff --git a/drivers/gpu/drm/sti/Makefile b/drivers/gpu/drm/sti/Makefile index 9b613d24877f..4a3a8168c30e 100644 --- a/drivers/gpu/drm/sti/Makefile +++ b/drivers/gpu/drm/sti/Makefile | |||
@@ -1,4 +1,5 @@ | |||
1 | sticompositor-y := \ | 1 | sticompositor-y := \ |
2 | sti_mixer.o \ | ||
2 | sti_gdp.o \ | 3 | sti_gdp.o \ |
3 | sti_vid.o | 4 | sti_vid.o |
4 | 5 | ||
@@ -12,4 +13,4 @@ obj-$(CONFIG_DRM_STI) = \ | |||
12 | stihdmi.o \ | 13 | stihdmi.o \ |
13 | sti_hda.o \ | 14 | sti_hda.o \ |
14 | sti_tvout.o \ | 15 | sti_tvout.o \ |
15 | sticompositor.o | 16 | sticompositor.o \ No newline at end of file |
diff --git a/drivers/gpu/drm/sti/sti_mixer.c b/drivers/gpu/drm/sti/sti_mixer.c new file mode 100644 index 000000000000..5fa6dc5800aa --- /dev/null +++ b/drivers/gpu/drm/sti/sti_mixer.c | |||
@@ -0,0 +1,243 @@ | |||
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_mixer.h" | ||
10 | #include "sti_vtg.h" | ||
11 | |||
12 | /* Identity: G=Y , B=Cb , R=Cr */ | ||
13 | static const u32 mixerColorSpaceMatIdentity[] = { | ||
14 | 0x10000000, 0x00000000, 0x10000000, 0x00001000, | ||
15 | 0x00000000, 0x00000000, 0x00000000, 0x00000000 | ||
16 | }; | ||
17 | |||
18 | /* regs offset */ | ||
19 | #define GAM_MIXER_CTL 0x00 | ||
20 | #define GAM_MIXER_BKC 0x04 | ||
21 | #define GAM_MIXER_BCO 0x0C | ||
22 | #define GAM_MIXER_BCS 0x10 | ||
23 | #define GAM_MIXER_AVO 0x28 | ||
24 | #define GAM_MIXER_AVS 0x2C | ||
25 | #define GAM_MIXER_CRB 0x34 | ||
26 | #define GAM_MIXER_ACT 0x38 | ||
27 | #define GAM_MIXER_MBP 0x3C | ||
28 | #define GAM_MIXER_MX0 0x80 | ||
29 | |||
30 | /* id for depth of CRB reg */ | ||
31 | #define GAM_DEPTH_VID0_ID 1 | ||
32 | #define GAM_DEPTH_VID1_ID 2 | ||
33 | #define GAM_DEPTH_GDP0_ID 3 | ||
34 | #define GAM_DEPTH_GDP1_ID 4 | ||
35 | #define GAM_DEPTH_GDP2_ID 5 | ||
36 | #define GAM_DEPTH_GDP3_ID 6 | ||
37 | #define GAM_DEPTH_MASK_ID 7 | ||
38 | |||
39 | /* mask in CTL reg */ | ||
40 | #define GAM_CTL_BACK_MASK BIT(0) | ||
41 | #define GAM_CTL_VID0_MASK BIT(1) | ||
42 | #define GAM_CTL_VID1_MASK BIT(2) | ||
43 | #define GAM_CTL_GDP0_MASK BIT(3) | ||
44 | #define GAM_CTL_GDP1_MASK BIT(4) | ||
45 | #define GAM_CTL_GDP2_MASK BIT(5) | ||
46 | #define GAM_CTL_GDP3_MASK BIT(6) | ||
47 | |||
48 | const char *sti_mixer_to_str(struct sti_mixer *mixer) | ||
49 | { | ||
50 | switch (mixer->id) { | ||
51 | case STI_MIXER_MAIN: | ||
52 | return "MAIN_MIXER"; | ||
53 | case STI_MIXER_AUX: | ||
54 | return "AUX_MIXER"; | ||
55 | default: | ||
56 | return "<UNKNOWN MIXER>"; | ||
57 | } | ||
58 | } | ||
59 | |||
60 | static inline u32 sti_mixer_reg_read(struct sti_mixer *mixer, u32 reg_id) | ||
61 | { | ||
62 | return readl(mixer->regs + reg_id); | ||
63 | } | ||
64 | |||
65 | static inline void sti_mixer_reg_write(struct sti_mixer *mixer, | ||
66 | u32 reg_id, u32 val) | ||
67 | { | ||
68 | writel(val, mixer->regs + reg_id); | ||
69 | } | ||
70 | |||
71 | void sti_mixer_set_background_status(struct sti_mixer *mixer, bool enable) | ||
72 | { | ||
73 | u32 val = sti_mixer_reg_read(mixer, GAM_MIXER_CTL); | ||
74 | |||
75 | val &= ~GAM_CTL_BACK_MASK; | ||
76 | val |= enable; | ||
77 | sti_mixer_reg_write(mixer, GAM_MIXER_CTL, val); | ||
78 | } | ||
79 | |||
80 | static void sti_mixer_set_background_color(struct sti_mixer *mixer, | ||
81 | u8 red, u8 green, u8 blue) | ||
82 | { | ||
83 | u32 val = (red << 16) | (green << 8) | blue; | ||
84 | |||
85 | sti_mixer_reg_write(mixer, GAM_MIXER_BKC, val); | ||
86 | } | ||
87 | |||
88 | static void sti_mixer_set_background_area(struct sti_mixer *mixer, | ||
89 | struct drm_display_mode *mode) | ||
90 | { | ||
91 | u32 ydo, xdo, yds, xds; | ||
92 | |||
93 | ydo = sti_vtg_get_line_number(*mode, 0); | ||
94 | yds = sti_vtg_get_line_number(*mode, mode->vdisplay - 1); | ||
95 | xdo = sti_vtg_get_pixel_number(*mode, 0); | ||
96 | xds = sti_vtg_get_pixel_number(*mode, mode->hdisplay - 1); | ||
97 | |||
98 | sti_mixer_reg_write(mixer, GAM_MIXER_BCO, ydo << 16 | xdo); | ||
99 | sti_mixer_reg_write(mixer, GAM_MIXER_BCS, yds << 16 | xds); | ||
100 | } | ||
101 | |||
102 | int sti_mixer_set_layer_depth(struct sti_mixer *mixer, struct sti_layer *layer) | ||
103 | { | ||
104 | int layer_id = 0, depth = layer->zorder; | ||
105 | u32 mask, val; | ||
106 | |||
107 | if (depth >= GAM_MIXER_NB_DEPTH_LEVEL) | ||
108 | return 1; | ||
109 | |||
110 | switch (layer->desc) { | ||
111 | case STI_GDP_0: | ||
112 | layer_id = GAM_DEPTH_GDP0_ID; | ||
113 | break; | ||
114 | case STI_GDP_1: | ||
115 | layer_id = GAM_DEPTH_GDP1_ID; | ||
116 | break; | ||
117 | case STI_GDP_2: | ||
118 | layer_id = GAM_DEPTH_GDP2_ID; | ||
119 | break; | ||
120 | case STI_GDP_3: | ||
121 | layer_id = GAM_DEPTH_GDP3_ID; | ||
122 | break; | ||
123 | case STI_VID_0: | ||
124 | layer_id = GAM_DEPTH_VID0_ID; | ||
125 | break; | ||
126 | case STI_VID_1: | ||
127 | layer_id = GAM_DEPTH_VID1_ID; | ||
128 | break; | ||
129 | default: | ||
130 | DRM_ERROR("Unknown layer %d\n", layer->desc); | ||
131 | return 1; | ||
132 | } | ||
133 | mask = GAM_DEPTH_MASK_ID << (3 * depth); | ||
134 | layer_id = layer_id << (3 * depth); | ||
135 | |||
136 | dev_dbg(mixer->dev, "GAM_MIXER_CRB val 0x%x mask 0x%x\n", | ||
137 | layer_id, mask); | ||
138 | |||
139 | val = sti_mixer_reg_read(mixer, GAM_MIXER_CRB); | ||
140 | val &= ~mask; | ||
141 | val |= layer_id; | ||
142 | sti_mixer_reg_write(mixer, GAM_MIXER_CRB, val); | ||
143 | |||
144 | dev_dbg(mixer->dev, "Read GAM_MIXER_CRB 0x%x\n", | ||
145 | sti_mixer_reg_read(mixer, GAM_MIXER_CRB)); | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | int sti_mixer_active_video_area(struct sti_mixer *mixer, | ||
150 | struct drm_display_mode *mode) | ||
151 | { | ||
152 | u32 ydo, xdo, yds, xds; | ||
153 | |||
154 | ydo = sti_vtg_get_line_number(*mode, 0); | ||
155 | yds = sti_vtg_get_line_number(*mode, mode->vdisplay - 1); | ||
156 | xdo = sti_vtg_get_pixel_number(*mode, 0); | ||
157 | xds = sti_vtg_get_pixel_number(*mode, mode->hdisplay - 1); | ||
158 | |||
159 | DRM_DEBUG_DRIVER("%s active video area xdo:%d ydo:%d xds:%d yds:%d\n", | ||
160 | sti_mixer_to_str(mixer), xdo, ydo, xds, yds); | ||
161 | sti_mixer_reg_write(mixer, GAM_MIXER_AVO, ydo << 16 | xdo); | ||
162 | sti_mixer_reg_write(mixer, GAM_MIXER_AVS, yds << 16 | xds); | ||
163 | |||
164 | sti_mixer_set_background_color(mixer, 0xFF, 0, 0); | ||
165 | |||
166 | sti_mixer_set_background_area(mixer, mode); | ||
167 | sti_mixer_set_background_status(mixer, true); | ||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | static u32 sti_mixer_get_layer_mask(struct sti_layer *layer) | ||
172 | { | ||
173 | switch (layer->desc) { | ||
174 | case STI_BACK: | ||
175 | return GAM_CTL_BACK_MASK; | ||
176 | case STI_GDP_0: | ||
177 | return GAM_CTL_GDP0_MASK; | ||
178 | case STI_GDP_1: | ||
179 | return GAM_CTL_GDP1_MASK; | ||
180 | case STI_GDP_2: | ||
181 | return GAM_CTL_GDP2_MASK; | ||
182 | case STI_GDP_3: | ||
183 | return GAM_CTL_GDP3_MASK; | ||
184 | case STI_VID_0: | ||
185 | return GAM_CTL_VID0_MASK; | ||
186 | case STI_VID_1: | ||
187 | return GAM_CTL_VID1_MASK; | ||
188 | default: | ||
189 | return 0; | ||
190 | } | ||
191 | } | ||
192 | |||
193 | int sti_mixer_set_layer_status(struct sti_mixer *mixer, | ||
194 | struct sti_layer *layer, bool status) | ||
195 | { | ||
196 | u32 mask, val; | ||
197 | |||
198 | mask = sti_mixer_get_layer_mask(layer); | ||
199 | if (!mask) { | ||
200 | DRM_ERROR("Can not find layer mask\n"); | ||
201 | return -EINVAL; | ||
202 | } | ||
203 | |||
204 | val = sti_mixer_reg_read(mixer, GAM_MIXER_CTL); | ||
205 | val &= ~mask; | ||
206 | val |= status ? mask : 0; | ||
207 | sti_mixer_reg_write(mixer, GAM_MIXER_CTL, val); | ||
208 | |||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | void sti_mixer_set_matrix(struct sti_mixer *mixer) | ||
213 | { | ||
214 | unsigned int i; | ||
215 | |||
216 | for (i = 0; i < ARRAY_SIZE(mixerColorSpaceMatIdentity); i++) | ||
217 | sti_mixer_reg_write(mixer, GAM_MIXER_MX0 + (i * 4), | ||
218 | mixerColorSpaceMatIdentity[i]); | ||
219 | } | ||
220 | |||
221 | struct sti_mixer *sti_mixer_create(struct device *dev, int id, | ||
222 | void __iomem *baseaddr) | ||
223 | { | ||
224 | struct sti_mixer *mixer = devm_kzalloc(dev, sizeof(*mixer), GFP_KERNEL); | ||
225 | struct device_node *np = dev->of_node; | ||
226 | |||
227 | dev_dbg(dev, "%s\n", __func__); | ||
228 | if (!mixer) { | ||
229 | DRM_ERROR("Failed to allocated memory for mixer\n"); | ||
230 | return NULL; | ||
231 | } | ||
232 | mixer->regs = baseaddr; | ||
233 | mixer->dev = dev; | ||
234 | mixer->id = id; | ||
235 | |||
236 | if (of_device_is_compatible(np, "st,stih416-compositor")) | ||
237 | sti_mixer_set_matrix(mixer); | ||
238 | |||
239 | DRM_DEBUG_DRIVER("%s created. Regs=%p\n", | ||
240 | sti_mixer_to_str(mixer), mixer->regs); | ||
241 | |||
242 | return mixer; | ||
243 | } | ||
diff --git a/drivers/gpu/drm/sti/sti_mixer.h b/drivers/gpu/drm/sti/sti_mixer.h new file mode 100644 index 000000000000..874372102e52 --- /dev/null +++ b/drivers/gpu/drm/sti/sti_mixer.h | |||
@@ -0,0 +1,54 @@ | |||
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_MIXER_H_ | ||
10 | #define _STI_MIXER_H_ | ||
11 | |||
12 | #include <drm/drmP.h> | ||
13 | |||
14 | #include "sti_layer.h" | ||
15 | |||
16 | #define to_sti_mixer(x) container_of(x, struct sti_mixer, drm_crtc) | ||
17 | |||
18 | /** | ||
19 | * STI Mixer subdevice structure | ||
20 | * | ||
21 | * @dev: driver device | ||
22 | * @regs: mixer registers | ||
23 | * @id: id of the mixer | ||
24 | * @drm_crtc: crtc object link to the mixer | ||
25 | * @pending_event: set if a flip event is pending on crtc | ||
26 | */ | ||
27 | struct sti_mixer { | ||
28 | struct device *dev; | ||
29 | void __iomem *regs; | ||
30 | int id; | ||
31 | struct drm_crtc drm_crtc; | ||
32 | struct drm_pending_vblank_event *pending_event; | ||
33 | }; | ||
34 | |||
35 | const char *sti_mixer_to_str(struct sti_mixer *mixer); | ||
36 | |||
37 | struct sti_mixer *sti_mixer_create(struct device *dev, int id, | ||
38 | void __iomem *baseaddr); | ||
39 | |||
40 | int sti_mixer_set_layer_status(struct sti_mixer *mixer, | ||
41 | struct sti_layer *layer, bool status); | ||
42 | int sti_mixer_set_layer_depth(struct sti_mixer *mixer, struct sti_layer *layer); | ||
43 | int sti_mixer_active_video_area(struct sti_mixer *mixer, | ||
44 | struct drm_display_mode *mode); | ||
45 | |||
46 | void sti_mixer_set_background_status(struct sti_mixer *mixer, bool enable); | ||
47 | |||
48 | /* depth in Cross-bar control = z order */ | ||
49 | #define GAM_MIXER_NB_DEPTH_LEVEL 7 | ||
50 | |||
51 | #define STI_MIXER_MAIN 0 | ||
52 | #define STI_MIXER_AUX 1 | ||
53 | |||
54 | #endif | ||