1  // SPDX-License-Identifier: GPL-2.0-only
2  /*
3   * linux/drivers/video/omap2/dss/manager.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 "MANAGER"
13  
14  #include <linux/kernel.h>
15  #include <linux/slab.h>
16  #include <linux/module.h>
17  #include <linux/platform_device.h>
18  #include <linux/jiffies.h>
19  
20  #include <video/omapfb_dss.h>
21  
22  #include "dss.h"
23  #include "dss_features.h"
24  
25  static int num_managers;
26  static struct omap_overlay_manager *managers;
27  
dss_init_overlay_managers(void)28  int dss_init_overlay_managers(void)
29  {
30  	int i;
31  
32  	num_managers = dss_feat_get_num_mgrs();
33  
34  	managers = kcalloc(num_managers, sizeof(struct omap_overlay_manager),
35  			   GFP_KERNEL);
36  
37  	BUG_ON(managers == NULL);
38  
39  	for (i = 0; i < num_managers; ++i) {
40  		struct omap_overlay_manager *mgr = &managers[i];
41  
42  		switch (i) {
43  		case 0:
44  			mgr->name = "lcd";
45  			mgr->id = OMAP_DSS_CHANNEL_LCD;
46  			break;
47  		case 1:
48  			mgr->name = "tv";
49  			mgr->id = OMAP_DSS_CHANNEL_DIGIT;
50  			break;
51  		case 2:
52  			mgr->name = "lcd2";
53  			mgr->id = OMAP_DSS_CHANNEL_LCD2;
54  			break;
55  		case 3:
56  			mgr->name = "lcd3";
57  			mgr->id = OMAP_DSS_CHANNEL_LCD3;
58  			break;
59  		}
60  
61  		mgr->supported_displays =
62  			dss_feat_get_supported_displays(mgr->id);
63  		mgr->supported_outputs =
64  			dss_feat_get_supported_outputs(mgr->id);
65  
66  		INIT_LIST_HEAD(&mgr->overlays);
67  	}
68  
69  	return 0;
70  }
71  
dss_init_overlay_managers_sysfs(struct platform_device * pdev)72  int dss_init_overlay_managers_sysfs(struct platform_device *pdev)
73  {
74  	int i, r;
75  
76  	for (i = 0; i < num_managers; ++i) {
77  		struct omap_overlay_manager *mgr = &managers[i];
78  
79  		r = dss_manager_kobj_init(mgr, pdev);
80  		if (r)
81  			DSSERR("failed to create sysfs file\n");
82  	}
83  
84  	return 0;
85  }
86  
dss_uninit_overlay_managers(void)87  void dss_uninit_overlay_managers(void)
88  {
89  	kfree(managers);
90  	managers = NULL;
91  	num_managers = 0;
92  }
93  
dss_uninit_overlay_managers_sysfs(struct platform_device * pdev)94  void dss_uninit_overlay_managers_sysfs(struct platform_device *pdev)
95  {
96  	int i;
97  
98  	for (i = 0; i < num_managers; ++i) {
99  		struct omap_overlay_manager *mgr = &managers[i];
100  
101  		dss_manager_kobj_uninit(mgr);
102  	}
103  }
104  
omap_dss_get_num_overlay_managers(void)105  int omap_dss_get_num_overlay_managers(void)
106  {
107  	return num_managers;
108  }
109  EXPORT_SYMBOL(omap_dss_get_num_overlay_managers);
110  
omap_dss_get_overlay_manager(int num)111  struct omap_overlay_manager *omap_dss_get_overlay_manager(int num)
112  {
113  	if (num >= num_managers)
114  		return NULL;
115  
116  	return &managers[num];
117  }
118  EXPORT_SYMBOL(omap_dss_get_overlay_manager);
119  
dss_mgr_simple_check(struct omap_overlay_manager * mgr,const struct omap_overlay_manager_info * info)120  int dss_mgr_simple_check(struct omap_overlay_manager *mgr,
121  		const struct omap_overlay_manager_info *info)
122  {
123  	if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) {
124  		/*
125  		 * OMAP3 supports only graphics source transparency color key
126  		 * and alpha blending simultaneously. See TRM 15.4.2.4.2.2
127  		 * Alpha Mode.
128  		 */
129  		if (info->partial_alpha_enabled && info->trans_enabled
130  			&& info->trans_key_type != OMAP_DSS_COLOR_KEY_GFX_DST) {
131  			DSSERR("check_manager: illegal transparency key\n");
132  			return -EINVAL;
133  		}
134  	}
135  
136  	return 0;
137  }
138  
dss_mgr_check_zorder(struct omap_overlay_manager * mgr,struct omap_overlay_info ** overlay_infos)139  static int dss_mgr_check_zorder(struct omap_overlay_manager *mgr,
140  		struct omap_overlay_info **overlay_infos)
141  {
142  	struct omap_overlay *ovl1, *ovl2;
143  	struct omap_overlay_info *info1, *info2;
144  
145  	list_for_each_entry(ovl1, &mgr->overlays, list) {
146  		info1 = overlay_infos[ovl1->id];
147  
148  		if (info1 == NULL)
149  			continue;
150  
151  		list_for_each_entry(ovl2, &mgr->overlays, list) {
152  			if (ovl1 == ovl2)
153  				continue;
154  
155  			info2 = overlay_infos[ovl2->id];
156  
157  			if (info2 == NULL)
158  				continue;
159  
160  			if (info1->zorder == info2->zorder) {
161  				DSSERR("overlays %d and %d have the same "
162  						"zorder %d\n",
163  					ovl1->id, ovl2->id, info1->zorder);
164  				return -EINVAL;
165  			}
166  		}
167  	}
168  
169  	return 0;
170  }
171  
dss_mgr_check_timings(struct omap_overlay_manager * mgr,const struct omap_video_timings * timings)172  int dss_mgr_check_timings(struct omap_overlay_manager *mgr,
173  		const struct omap_video_timings *timings)
174  {
175  	if (!dispc_mgr_timings_ok(mgr->id, timings)) {
176  		DSSERR("check_manager: invalid timings\n");
177  		return -EINVAL;
178  	}
179  
180  	return 0;
181  }
182  
dss_mgr_check_lcd_config(struct omap_overlay_manager * mgr,const struct dss_lcd_mgr_config * config)183  static int dss_mgr_check_lcd_config(struct omap_overlay_manager *mgr,
184  		const struct dss_lcd_mgr_config *config)
185  {
186  	struct dispc_clock_info cinfo = config->clock_info;
187  	int dl = config->video_port_width;
188  	bool stallmode = config->stallmode;
189  	bool fifohandcheck = config->fifohandcheck;
190  
191  	if (cinfo.lck_div < 1 || cinfo.lck_div > 255)
192  		return -EINVAL;
193  
194  	if (cinfo.pck_div < 1 || cinfo.pck_div > 255)
195  		return -EINVAL;
196  
197  	if (dl != 12 && dl != 16 && dl != 18 && dl != 24)
198  		return -EINVAL;
199  
200  	/* fifohandcheck should be used only with stallmode */
201  	if (!stallmode && fifohandcheck)
202  		return -EINVAL;
203  
204  	/*
205  	 * io pad mode can be only checked by using dssdev connected to the
206  	 * manager. Ignore checking these for now, add checks when manager
207  	 * is capable of holding information related to the connected interface
208  	 */
209  
210  	return 0;
211  }
212  
dss_mgr_check(struct omap_overlay_manager * mgr,struct omap_overlay_manager_info * info,const struct omap_video_timings * mgr_timings,const struct dss_lcd_mgr_config * lcd_config,struct omap_overlay_info ** overlay_infos)213  int dss_mgr_check(struct omap_overlay_manager *mgr,
214  		struct omap_overlay_manager_info *info,
215  		const struct omap_video_timings *mgr_timings,
216  		const struct dss_lcd_mgr_config *lcd_config,
217  		struct omap_overlay_info **overlay_infos)
218  {
219  	struct omap_overlay *ovl;
220  	int r;
221  
222  	if (dss_has_feature(FEAT_ALPHA_FREE_ZORDER)) {
223  		r = dss_mgr_check_zorder(mgr, overlay_infos);
224  		if (r)
225  			return r;
226  	}
227  
228  	r = dss_mgr_check_timings(mgr, mgr_timings);
229  	if (r)
230  		return r;
231  
232  	r = dss_mgr_check_lcd_config(mgr, lcd_config);
233  	if (r)
234  		return r;
235  
236  	list_for_each_entry(ovl, &mgr->overlays, list) {
237  		struct omap_overlay_info *oi;
238  		int r;
239  
240  		oi = overlay_infos[ovl->id];
241  
242  		if (oi == NULL)
243  			continue;
244  
245  		r = dss_ovl_check(ovl, oi, mgr_timings);
246  		if (r)
247  			return r;
248  	}
249  
250  	return 0;
251  }
252