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