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/omapdss.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 = kzalloc(sizeof(struct omap_overlay_manager) * num_managers, 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->caps = 0; 73 mgr->supported_displays = 74 dss_feat_get_supported_displays(mgr->id); 75 mgr->supported_outputs = 76 dss_feat_get_supported_outputs(mgr->id); 77 78 INIT_LIST_HEAD(&mgr->overlays); 79 } 80 81 return 0; 82 } 83 84 int dss_init_overlay_managers_sysfs(struct platform_device *pdev) 85 { 86 int i, r; 87 88 for (i = 0; i < num_managers; ++i) { 89 struct omap_overlay_manager *mgr = &managers[i]; 90 91 r = dss_manager_kobj_init(mgr, pdev); 92 if (r) 93 DSSERR("failed to create sysfs file\n"); 94 } 95 96 return 0; 97 } 98 99 void dss_uninit_overlay_managers(void) 100 { 101 kfree(managers); 102 managers = NULL; 103 num_managers = 0; 104 } 105 106 void dss_uninit_overlay_managers_sysfs(struct platform_device *pdev) 107 { 108 int i; 109 110 for (i = 0; i < num_managers; ++i) { 111 struct omap_overlay_manager *mgr = &managers[i]; 112 113 dss_manager_kobj_uninit(mgr); 114 } 115 } 116 117 int omap_dss_get_num_overlay_managers(void) 118 { 119 return num_managers; 120 } 121 EXPORT_SYMBOL(omap_dss_get_num_overlay_managers); 122 123 struct omap_overlay_manager *omap_dss_get_overlay_manager(int num) 124 { 125 if (num >= num_managers) 126 return NULL; 127 128 return &managers[num]; 129 } 130 EXPORT_SYMBOL(omap_dss_get_overlay_manager); 131 132 int dss_mgr_simple_check(struct omap_overlay_manager *mgr, 133 const struct omap_overlay_manager_info *info) 134 { 135 if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) { 136 /* 137 * OMAP3 supports only graphics source transparency color key 138 * and alpha blending simultaneously. See TRM 15.4.2.4.2.2 139 * Alpha Mode. 140 */ 141 if (info->partial_alpha_enabled && info->trans_enabled 142 && info->trans_key_type != OMAP_DSS_COLOR_KEY_GFX_DST) { 143 DSSERR("check_manager: illegal transparency key\n"); 144 return -EINVAL; 145 } 146 } 147 148 return 0; 149 } 150 151 static int dss_mgr_check_zorder(struct omap_overlay_manager *mgr, 152 struct omap_overlay_info **overlay_infos) 153 { 154 struct omap_overlay *ovl1, *ovl2; 155 struct omap_overlay_info *info1, *info2; 156 157 list_for_each_entry(ovl1, &mgr->overlays, list) { 158 info1 = overlay_infos[ovl1->id]; 159 160 if (info1 == NULL) 161 continue; 162 163 list_for_each_entry(ovl2, &mgr->overlays, list) { 164 if (ovl1 == ovl2) 165 continue; 166 167 info2 = overlay_infos[ovl2->id]; 168 169 if (info2 == NULL) 170 continue; 171 172 if (info1->zorder == info2->zorder) { 173 DSSERR("overlays %d and %d have the same " 174 "zorder %d\n", 175 ovl1->id, ovl2->id, info1->zorder); 176 return -EINVAL; 177 } 178 } 179 } 180 181 return 0; 182 } 183 184 int dss_mgr_check_timings(struct omap_overlay_manager *mgr, 185 const struct omap_video_timings *timings) 186 { 187 if (!dispc_mgr_timings_ok(mgr->id, timings)) { 188 DSSERR("check_manager: invalid timings\n"); 189 return -EINVAL; 190 } 191 192 return 0; 193 } 194 195 static int dss_mgr_check_lcd_config(struct omap_overlay_manager *mgr, 196 const struct dss_lcd_mgr_config *config) 197 { 198 struct dispc_clock_info cinfo = config->clock_info; 199 int dl = config->video_port_width; 200 bool stallmode = config->stallmode; 201 bool fifohandcheck = config->fifohandcheck; 202 203 if (cinfo.lck_div < 1 || cinfo.lck_div > 255) 204 return -EINVAL; 205 206 if (cinfo.pck_div < 1 || cinfo.pck_div > 255) 207 return -EINVAL; 208 209 if (dl != 12 && dl != 16 && dl != 18 && dl != 24) 210 return -EINVAL; 211 212 /* fifohandcheck should be used only with stallmode */ 213 if (!stallmode && fifohandcheck) 214 return -EINVAL; 215 216 /* 217 * io pad mode can be only checked by using dssdev connected to the 218 * manager. Ignore checking these for now, add checks when manager 219 * is capable of holding information related to the connected interface 220 */ 221 222 return 0; 223 } 224 225 int dss_mgr_check(struct omap_overlay_manager *mgr, 226 struct omap_overlay_manager_info *info, 227 const struct omap_video_timings *mgr_timings, 228 const struct dss_lcd_mgr_config *lcd_config, 229 struct omap_overlay_info **overlay_infos) 230 { 231 struct omap_overlay *ovl; 232 int r; 233 234 if (dss_has_feature(FEAT_ALPHA_FREE_ZORDER)) { 235 r = dss_mgr_check_zorder(mgr, overlay_infos); 236 if (r) 237 return r; 238 } 239 240 r = dss_mgr_check_timings(mgr, mgr_timings); 241 if (r) 242 return r; 243 244 r = dss_mgr_check_lcd_config(mgr, lcd_config); 245 if (r) 246 return r; 247 248 list_for_each_entry(ovl, &mgr->overlays, list) { 249 struct omap_overlay_info *oi; 250 int r; 251 252 oi = overlay_infos[ovl->id]; 253 254 if (oi == NULL) 255 continue; 256 257 r = dss_ovl_check(ovl, oi, mgr_timings); 258 if (r) 259 return r; 260 } 261 262 return 0; 263 } 264