aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/omap2/dss/apply.c215
1 files changed, 212 insertions, 3 deletions
diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c
index 242cb1c983c0..6eb48586501c 100644
--- a/drivers/video/omap2/dss/apply.c
+++ b/drivers/video/omap2/dss/apply.c
@@ -166,6 +166,169 @@ static bool mgr_manual_update(struct omap_overlay_manager *mgr)
166 return mgr->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; 166 return mgr->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
167} 167}
168 168
169/* Check if overlay parameters are compatible with display */
170static int dss_ovl_check(struct omap_overlay *ovl,
171 struct omap_overlay_info *info, struct omap_dss_device *dssdev)
172{
173 u16 outw, outh;
174 u16 dw, dh;
175
176 if (dssdev == NULL)
177 return 0;
178
179 dssdev->driver->get_resolution(dssdev, &dw, &dh);
180
181 if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
182 outw = info->width;
183 outh = info->height;
184 } else {
185 if (info->out_width == 0)
186 outw = info->width;
187 else
188 outw = info->out_width;
189
190 if (info->out_height == 0)
191 outh = info->height;
192 else
193 outh = info->out_height;
194 }
195
196 if (dw < info->pos_x + outw) {
197 DSSERR("overlay %d horizontally not inside the display area "
198 "(%d + %d >= %d)\n",
199 ovl->id, info->pos_x, outw, dw);
200 return -EINVAL;
201 }
202
203 if (dh < info->pos_y + outh) {
204 DSSERR("overlay %d vertically not inside the display area "
205 "(%d + %d >= %d)\n",
206 ovl->id, info->pos_y, outh, dh);
207 return -EINVAL;
208 }
209
210 return 0;
211}
212
213static int dss_mgr_check_zorder(struct omap_overlay_manager *mgr,
214 struct omap_overlay_info **overlay_infos)
215{
216 struct omap_overlay *ovl1, *ovl2;
217 struct ovl_priv_data *op1, *op2;
218 struct omap_overlay_info *info1, *info2;
219
220 list_for_each_entry(ovl1, &mgr->overlays, list) {
221 op1 = get_ovl_priv(ovl1);
222 info1 = overlay_infos[ovl1->id];
223
224 if (info1 == NULL)
225 continue;
226
227 list_for_each_entry(ovl2, &mgr->overlays, list) {
228 if (ovl1 == ovl2)
229 continue;
230
231 op2 = get_ovl_priv(ovl2);
232 info2 = overlay_infos[ovl2->id];
233
234 if (info2 == NULL)
235 continue;
236
237 if (info1->zorder == info2->zorder) {
238 DSSERR("overlays %d and %d have the same "
239 "zorder %d\n",
240 ovl1->id, ovl2->id, info1->zorder);
241 return -EINVAL;
242 }
243 }
244 }
245
246 return 0;
247}
248
249static int dss_mgr_check(struct omap_overlay_manager *mgr,
250 struct omap_dss_device *dssdev,
251 struct omap_overlay_manager_info *info,
252 struct omap_overlay_info **overlay_infos)
253{
254 struct omap_overlay *ovl;
255 int r;
256
257 if (dss_has_feature(FEAT_ALPHA_FREE_ZORDER)) {
258 r = dss_mgr_check_zorder(mgr, overlay_infos);
259 if (r)
260 return r;
261 }
262
263 list_for_each_entry(ovl, &mgr->overlays, list) {
264 struct omap_overlay_info *oi;
265 int r;
266
267 oi = overlay_infos[ovl->id];
268
269 if (oi == NULL)
270 continue;
271
272 r = dss_ovl_check(ovl, oi, dssdev);
273 if (r)
274 return r;
275 }
276
277 return 0;
278}
279static int dss_check_settings_low(struct omap_overlay_manager *mgr,
280 struct omap_dss_device *dssdev, bool applying)
281{
282 struct omap_overlay_info *oi;
283 struct omap_overlay_manager_info *mi;
284 struct omap_overlay *ovl;
285 struct omap_overlay_info *ois[MAX_DSS_OVERLAYS];
286 struct ovl_priv_data *op;
287 struct mgr_priv_data *mp;
288
289 mp = get_mgr_priv(mgr);
290
291 if (applying && mp->user_info_dirty)
292 mi = &mp->user_info;
293 else
294 mi = &mp->info;
295
296 /* collect the infos to be tested into the array */
297 list_for_each_entry(ovl, &mgr->overlays, list) {
298 op = get_ovl_priv(ovl);
299
300 if (!op->enabled)
301 oi = NULL;
302 else if (applying && op->user_info_dirty)
303 oi = &op->user_info;
304 else
305 oi = &op->info;
306
307 ois[ovl->id] = oi;
308 }
309
310 return dss_mgr_check(mgr, dssdev, mi, ois);
311}
312
313/*
314 * check manager and overlay settings using overlay_info from data->info
315 */
316static int dss_check_settings(struct omap_overlay_manager *mgr,
317 struct omap_dss_device *dssdev)
318{
319 return dss_check_settings_low(mgr, dssdev, false);
320}
321
322/*
323 * check manager and overlay settings using overlay_info from ovl->info if
324 * dirty and from data->info otherwise
325 */
326static int dss_check_settings_apply(struct omap_overlay_manager *mgr,
327 struct omap_dss_device *dssdev)
328{
329 return dss_check_settings_low(mgr, dssdev, true);
330}
331
169static bool need_isr(void) 332static bool need_isr(void)
170{ 333{
171 const int num_mgrs = dss_feat_get_num_mgrs(); 334 const int num_mgrs = dss_feat_get_num_mgrs();
@@ -517,6 +680,7 @@ static void dss_write_regs(void)
517 for (i = 0; i < num_mgrs; ++i) { 680 for (i = 0; i < num_mgrs; ++i) {
518 struct omap_overlay_manager *mgr; 681 struct omap_overlay_manager *mgr;
519 struct mgr_priv_data *mp; 682 struct mgr_priv_data *mp;
683 int r;
520 684
521 mgr = omap_dss_get_overlay_manager(i); 685 mgr = omap_dss_get_overlay_manager(i);
522 mp = get_mgr_priv(mgr); 686 mp = get_mgr_priv(mgr);
@@ -524,6 +688,13 @@ static void dss_write_regs(void)
524 if (!mp->enabled || mgr_manual_update(mgr) || mp->busy) 688 if (!mp->enabled || mgr_manual_update(mgr) || mp->busy)
525 continue; 689 continue;
526 690
691 r = dss_check_settings(mgr, mgr->device);
692 if (r) {
693 DSSERR("cannot write registers for manager %s: "
694 "illegal configuration\n", mgr->name);
695 continue;
696 }
697
527 dss_mgr_write_regs(mgr); 698 dss_mgr_write_regs(mgr);
528 699
529 if (need_go(mgr)) { 700 if (need_go(mgr)) {
@@ -541,11 +712,19 @@ void dss_mgr_start_update(struct omap_overlay_manager *mgr)
541{ 712{
542 struct mgr_priv_data *mp = get_mgr_priv(mgr); 713 struct mgr_priv_data *mp = get_mgr_priv(mgr);
543 unsigned long flags; 714 unsigned long flags;
715 int r;
544 716
545 spin_lock_irqsave(&data_lock, flags); 717 spin_lock_irqsave(&data_lock, flags);
546 718
547 WARN_ON(mp->updating); 719 WARN_ON(mp->updating);
548 720
721 r = dss_check_settings(mgr, mgr->device);
722 if (r) {
723 DSSERR("cannot start manual update: illegal configuration\n");
724 spin_unlock_irqrestore(&data_lock, flags);
725 return;
726 }
727
549 dss_mgr_write_regs(mgr); 728 dss_mgr_write_regs(mgr);
550 729
551 mp->updating = true; 730 mp->updating = true;
@@ -690,11 +869,19 @@ int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
690{ 869{
691 unsigned long flags; 870 unsigned long flags;
692 struct omap_overlay *ovl; 871 struct omap_overlay *ovl;
872 int r;
693 873
694 DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name); 874 DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
695 875
696 spin_lock_irqsave(&data_lock, flags); 876 spin_lock_irqsave(&data_lock, flags);
697 877
878 r = dss_check_settings_apply(mgr, mgr->device);
879 if (r) {
880 spin_unlock_irqrestore(&data_lock, flags);
881 DSSERR("failed to apply settings: illegal configuration.\n");
882 return r;
883 }
884
698 /* Configure overlays */ 885 /* Configure overlays */
699 list_for_each_entry(ovl, &mgr->overlays, list) 886 list_for_each_entry(ovl, &mgr->overlays, list)
700 omap_dss_mgr_apply_ovl(ovl); 887 omap_dss_mgr_apply_ovl(ovl);
@@ -784,6 +971,7 @@ void dss_mgr_enable(struct omap_overlay_manager *mgr)
784{ 971{
785 struct mgr_priv_data *mp = get_mgr_priv(mgr); 972 struct mgr_priv_data *mp = get_mgr_priv(mgr);
786 unsigned long flags; 973 unsigned long flags;
974 int r;
787 975
788 mutex_lock(&apply_lock); 976 mutex_lock(&apply_lock);
789 977
@@ -793,6 +981,16 @@ void dss_mgr_enable(struct omap_overlay_manager *mgr)
793 spin_lock_irqsave(&data_lock, flags); 981 spin_lock_irqsave(&data_lock, flags);
794 982
795 mp->enabled = true; 983 mp->enabled = true;
984 r = dss_check_settings(mgr, mgr->device);
985 mp->enabled = false;
986 if (r) {
987 DSSERR("failed to enable manager %d: check_settings failed\n",
988 mgr->id);
989 spin_unlock_irqrestore(&data_lock, flags);
990 goto out;
991 }
992
993 mp->enabled = true;
796 994
797 dss_mgr_setup_fifos(mgr); 995 dss_mgr_setup_fifos(mgr);
798 996
@@ -1142,16 +1340,25 @@ int dss_ovl_enable(struct omap_overlay *ovl)
1142 1340
1143 if (op->enabled) { 1341 if (op->enabled) {
1144 r = 0; 1342 r = 0;
1145 goto err; 1343 goto err1;
1146 } 1344 }
1147 1345
1148 if (ovl->manager == NULL || ovl->manager->device == NULL) { 1346 if (ovl->manager == NULL || ovl->manager->device == NULL) {
1149 r = -EINVAL; 1347 r = -EINVAL;
1150 goto err; 1348 goto err1;
1151 } 1349 }
1152 1350
1153 spin_lock_irqsave(&data_lock, flags); 1351 spin_lock_irqsave(&data_lock, flags);
1154 1352
1353 op->enabled = true;
1354 r = dss_check_settings(ovl->manager, ovl->manager->device);
1355 op->enabled = false;
1356 if (r) {
1357 DSSERR("failed to enable overlay %d: check_settings failed\n",
1358 ovl->id);
1359 goto err2;
1360 }
1361
1155 dss_apply_ovl_enable(ovl, true); 1362 dss_apply_ovl_enable(ovl, true);
1156 1363
1157 dss_ovl_setup_fifo(ovl); 1364 dss_ovl_setup_fifo(ovl);
@@ -1163,7 +1370,9 @@ int dss_ovl_enable(struct omap_overlay *ovl)
1163 mutex_unlock(&apply_lock); 1370 mutex_unlock(&apply_lock);
1164 1371
1165 return 0; 1372 return 0;
1166err: 1373err2:
1374 spin_unlock_irqrestore(&data_lock, flags);
1375err1:
1167 mutex_unlock(&apply_lock); 1376 mutex_unlock(&apply_lock);
1168 return r; 1377 return r;
1169} 1378}