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