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