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 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 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 87 void dss_uninit_overlay_managers(void) 88 { 89 kfree(managers); 90 managers = NULL; 91 num_managers = 0; 92 } 93 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 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 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 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 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 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 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 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