diff options
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/omap2/dss/apply.c | 215 |
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 */ | ||
170 | static 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 | |||
213 | static 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 | |||
249 | static 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 | } | ||
279 | static 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 | */ | ||
316 | static 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 | */ | ||
326 | static 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 | |||
169 | static bool need_isr(void) | 332 | static 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; |
1166 | err: | 1373 | err2: |
1374 | spin_unlock_irqrestore(&data_lock, flags); | ||
1375 | err1: | ||
1167 | mutex_unlock(&apply_lock); | 1376 | mutex_unlock(&apply_lock); |
1168 | return r; | 1377 | return r; |
1169 | } | 1378 | } |