xref: /linux/drivers/video/fbdev/omap2/omapfb/dss/overlay.c (revision 746680ec6696585e30db3e18c93a63df9cbec39c)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * linux/drivers/video/omap2/dss/overlay.c
4  *
5  * Copyright (C) 2009 Nokia Corporation
6  * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
7  *
8  * Some code and ideas taken from drivers/video/omap/ driver
9  * by Imre Deak.
10  */
11 
12 #define DSS_SUBSYS_NAME "OVERLAY"
13 
14 #include <linux/kernel.h>
15 #include <linux/module.h>
16 #include <linux/err.h>
17 #include <linux/export.h>
18 #include <linux/sysfs.h>
19 #include <linux/platform_device.h>
20 #include <linux/delay.h>
21 #include <linux/slab.h>
22 
23 #include <video/omapfb_dss.h>
24 
25 #include "dss.h"
26 #include "dss_features.h"
27 
28 static int num_overlays;
29 static struct omap_overlay *overlays;
30 
31 int omap_dss_get_num_overlays(void)
32 {
33 	return num_overlays;
34 }
35 EXPORT_SYMBOL(omap_dss_get_num_overlays);
36 
37 struct omap_overlay *omap_dss_get_overlay(int num)
38 {
39 	if (num >= num_overlays)
40 		return NULL;
41 
42 	return &overlays[num];
43 }
44 EXPORT_SYMBOL(omap_dss_get_overlay);
45 
46 void dss_init_overlays(struct platform_device *pdev)
47 {
48 	int i, r;
49 
50 	num_overlays = dss_feat_get_num_ovls();
51 
52 	overlays = kcalloc(num_overlays, sizeof(struct omap_overlay),
53 			   GFP_KERNEL);
54 
55 	BUG_ON(overlays == NULL);
56 
57 	for (i = 0; i < num_overlays; ++i) {
58 		struct omap_overlay *ovl = &overlays[i];
59 
60 		switch (i) {
61 		case 0:
62 			ovl->name = "gfx";
63 			ovl->id = OMAP_DSS_GFX;
64 			break;
65 		case 1:
66 			ovl->name = "vid1";
67 			ovl->id = OMAP_DSS_VIDEO1;
68 			break;
69 		case 2:
70 			ovl->name = "vid2";
71 			ovl->id = OMAP_DSS_VIDEO2;
72 			break;
73 		case 3:
74 			ovl->name = "vid3";
75 			ovl->id = OMAP_DSS_VIDEO3;
76 			break;
77 		}
78 
79 		ovl->caps = dss_feat_get_overlay_caps(ovl->id);
80 		ovl->supported_modes =
81 			dss_feat_get_supported_color_modes(ovl->id);
82 
83 		r = dss_overlay_kobj_init(ovl, pdev);
84 		if (r)
85 			DSSERR("failed to create sysfs file\n");
86 	}
87 }
88 
89 void dss_uninit_overlays(struct platform_device *pdev)
90 {
91 	int i;
92 
93 	for (i = 0; i < num_overlays; ++i) {
94 		struct omap_overlay *ovl = &overlays[i];
95 		dss_overlay_kobj_uninit(ovl);
96 	}
97 
98 	kfree(overlays);
99 	overlays = NULL;
100 	num_overlays = 0;
101 }
102 
103 int dss_ovl_simple_check(struct omap_overlay *ovl,
104 		const struct omap_overlay_info *info)
105 {
106 	if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
107 		if (info->out_width != 0 && info->width != info->out_width) {
108 			DSSERR("check_overlay: overlay %d doesn't support "
109 					"scaling\n", ovl->id);
110 			return -EINVAL;
111 		}
112 
113 		if (info->out_height != 0 && info->height != info->out_height) {
114 			DSSERR("check_overlay: overlay %d doesn't support "
115 					"scaling\n", ovl->id);
116 			return -EINVAL;
117 		}
118 	}
119 
120 	if ((ovl->supported_modes & info->color_mode) == 0) {
121 		DSSERR("check_overlay: overlay %d doesn't support mode %d\n",
122 				ovl->id, info->color_mode);
123 		return -EINVAL;
124 	}
125 
126 	if (info->zorder >= omap_dss_get_num_overlays()) {
127 		DSSERR("check_overlay: zorder %d too high\n", info->zorder);
128 		return -EINVAL;
129 	}
130 
131 	if (dss_feat_rotation_type_supported(info->rotation_type) == 0) {
132 		DSSERR("check_overlay: rotation type %d not supported\n",
133 				info->rotation_type);
134 		return -EINVAL;
135 	}
136 
137 	return 0;
138 }
139 
140 int dss_ovl_check(struct omap_overlay *ovl, struct omap_overlay_info *info,
141 		const struct omap_video_timings *mgr_timings)
142 {
143 	u16 outw, outh;
144 	u16 dw, dh;
145 
146 	dw = mgr_timings->x_res;
147 	dh = mgr_timings->y_res;
148 
149 	if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
150 		outw = info->width;
151 		outh = info->height;
152 	} else {
153 		if (info->out_width == 0)
154 			outw = info->width;
155 		else
156 			outw = info->out_width;
157 
158 		if (info->out_height == 0)
159 			outh = info->height;
160 		else
161 			outh = info->out_height;
162 	}
163 
164 	if (dw < info->pos_x + outw) {
165 		DSSERR("overlay %d horizontally not inside the display area "
166 				"(%d + %d >= %d)\n",
167 				ovl->id, info->pos_x, outw, dw);
168 		return -EINVAL;
169 	}
170 
171 	if (dh < info->pos_y + outh) {
172 		DSSERR("overlay %d vertically not inside the display area "
173 				"(%d + %d >= %d)\n",
174 				ovl->id, info->pos_y, outh, dh);
175 		return -EINVAL;
176 	}
177 
178 	return 0;
179 }
180 
181 /*
182  * Checks if replication logic should be used. Only use when overlay is in
183  * RGB12U or RGB16 mode, and video port width interface is 18bpp or 24bpp
184  */
185 bool dss_ovl_use_replication(struct dss_lcd_mgr_config config,
186 		enum omap_color_mode mode)
187 {
188 	if (mode != OMAP_DSS_COLOR_RGB12U && mode != OMAP_DSS_COLOR_RGB16)
189 		return false;
190 
191 	return config.video_port_width > 16;
192 }
193