1 /* 2 * linux/drivers/video/omap2/dss/display.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 "DISPLAY" 24 25 #include <linux/kernel.h> 26 #include <linux/module.h> 27 #include <linux/jiffies.h> 28 #include <linux/platform_device.h> 29 #include <linux/of.h> 30 31 #include <video/omapfb_dss.h> 32 #include "dss.h" 33 #include "dss_features.h" 34 35 void omapdss_default_get_resolution(struct omap_dss_device *dssdev, 36 u16 *xres, u16 *yres) 37 { 38 *xres = dssdev->panel.timings.x_res; 39 *yres = dssdev->panel.timings.y_res; 40 } 41 EXPORT_SYMBOL(omapdss_default_get_resolution); 42 43 int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev) 44 { 45 switch (dssdev->type) { 46 case OMAP_DISPLAY_TYPE_DPI: 47 if (dssdev->phy.dpi.data_lines == 24) 48 return 24; 49 else 50 return 16; 51 52 case OMAP_DISPLAY_TYPE_DBI: 53 if (dssdev->ctrl.pixel_size == 24) 54 return 24; 55 else 56 return 16; 57 case OMAP_DISPLAY_TYPE_DSI: 58 if (dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) > 16) 59 return 24; 60 else 61 return 16; 62 case OMAP_DISPLAY_TYPE_VENC: 63 case OMAP_DISPLAY_TYPE_SDI: 64 case OMAP_DISPLAY_TYPE_HDMI: 65 case OMAP_DISPLAY_TYPE_DVI: 66 return 24; 67 default: 68 BUG(); 69 return 0; 70 } 71 } 72 EXPORT_SYMBOL(omapdss_default_get_recommended_bpp); 73 74 void omapdss_default_get_timings(struct omap_dss_device *dssdev, 75 struct omap_video_timings *timings) 76 { 77 *timings = dssdev->panel.timings; 78 } 79 EXPORT_SYMBOL(omapdss_default_get_timings); 80 81 int dss_suspend_all_devices(void) 82 { 83 struct omap_dss_device *dssdev = NULL; 84 85 for_each_dss_dev(dssdev) { 86 if (!dssdev->driver) 87 continue; 88 89 if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { 90 dssdev->driver->disable(dssdev); 91 dssdev->activate_after_resume = true; 92 } else { 93 dssdev->activate_after_resume = false; 94 } 95 } 96 97 return 0; 98 } 99 100 int dss_resume_all_devices(void) 101 { 102 struct omap_dss_device *dssdev = NULL; 103 104 for_each_dss_dev(dssdev) { 105 if (!dssdev->driver) 106 continue; 107 108 if (dssdev->activate_after_resume) { 109 dssdev->driver->enable(dssdev); 110 dssdev->activate_after_resume = false; 111 } 112 } 113 114 return 0; 115 } 116 117 void dss_disable_all_devices(void) 118 { 119 struct omap_dss_device *dssdev = NULL; 120 121 for_each_dss_dev(dssdev) { 122 if (!dssdev->driver) 123 continue; 124 125 if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) 126 dssdev->driver->disable(dssdev); 127 } 128 } 129 130 static LIST_HEAD(panel_list); 131 static DEFINE_MUTEX(panel_list_mutex); 132 static int disp_num_counter; 133 134 int omapdss_register_display(struct omap_dss_device *dssdev) 135 { 136 struct omap_dss_driver *drv = dssdev->driver; 137 int id; 138 139 /* 140 * Note: this presumes all the displays are either using DT or non-DT, 141 * which normally should be the case. This also presumes that all 142 * displays either have an DT alias, or none has. 143 */ 144 145 if (dssdev->dev->of_node) { 146 id = of_alias_get_id(dssdev->dev->of_node, "display"); 147 148 if (id < 0) 149 id = disp_num_counter++; 150 } else { 151 id = disp_num_counter++; 152 } 153 154 snprintf(dssdev->alias, sizeof(dssdev->alias), "display%d", id); 155 156 /* Use 'label' property for name, if it exists */ 157 if (dssdev->dev->of_node) 158 of_property_read_string(dssdev->dev->of_node, "label", 159 &dssdev->name); 160 161 if (dssdev->name == NULL) 162 dssdev->name = dssdev->alias; 163 164 if (drv && drv->get_resolution == NULL) 165 drv->get_resolution = omapdss_default_get_resolution; 166 if (drv && drv->get_recommended_bpp == NULL) 167 drv->get_recommended_bpp = omapdss_default_get_recommended_bpp; 168 if (drv && drv->get_timings == NULL) 169 drv->get_timings = omapdss_default_get_timings; 170 171 mutex_lock(&panel_list_mutex); 172 list_add_tail(&dssdev->panel_list, &panel_list); 173 mutex_unlock(&panel_list_mutex); 174 return 0; 175 } 176 EXPORT_SYMBOL(omapdss_register_display); 177 178 void omapdss_unregister_display(struct omap_dss_device *dssdev) 179 { 180 mutex_lock(&panel_list_mutex); 181 list_del(&dssdev->panel_list); 182 mutex_unlock(&panel_list_mutex); 183 } 184 EXPORT_SYMBOL(omapdss_unregister_display); 185 186 struct omap_dss_device *omap_dss_get_device(struct omap_dss_device *dssdev) 187 { 188 if (!try_module_get(dssdev->owner)) 189 return NULL; 190 191 if (get_device(dssdev->dev) == NULL) { 192 module_put(dssdev->owner); 193 return NULL; 194 } 195 196 return dssdev; 197 } 198 EXPORT_SYMBOL(omap_dss_get_device); 199 200 void omap_dss_put_device(struct omap_dss_device *dssdev) 201 { 202 put_device(dssdev->dev); 203 module_put(dssdev->owner); 204 } 205 EXPORT_SYMBOL(omap_dss_put_device); 206 207 /* 208 * ref count of the found device is incremented. 209 * ref count of from-device is decremented. 210 */ 211 struct omap_dss_device *omap_dss_get_next_device(struct omap_dss_device *from) 212 { 213 struct list_head *l; 214 struct omap_dss_device *dssdev; 215 216 mutex_lock(&panel_list_mutex); 217 218 if (list_empty(&panel_list)) { 219 dssdev = NULL; 220 goto out; 221 } 222 223 if (from == NULL) { 224 dssdev = list_first_entry(&panel_list, struct omap_dss_device, 225 panel_list); 226 omap_dss_get_device(dssdev); 227 goto out; 228 } 229 230 omap_dss_put_device(from); 231 232 list_for_each(l, &panel_list) { 233 dssdev = list_entry(l, struct omap_dss_device, panel_list); 234 if (dssdev == from) { 235 if (list_is_last(l, &panel_list)) { 236 dssdev = NULL; 237 goto out; 238 } 239 240 dssdev = list_entry(l->next, struct omap_dss_device, 241 panel_list); 242 omap_dss_get_device(dssdev); 243 goto out; 244 } 245 } 246 247 WARN(1, "'from' dssdev not found\n"); 248 249 dssdev = NULL; 250 out: 251 mutex_unlock(&panel_list_mutex); 252 return dssdev; 253 } 254 EXPORT_SYMBOL(omap_dss_get_next_device); 255 256 struct omap_dss_device *omap_dss_find_device(void *data, 257 int (*match)(struct omap_dss_device *dssdev, void *data)) 258 { 259 struct omap_dss_device *dssdev = NULL; 260 261 while ((dssdev = omap_dss_get_next_device(dssdev)) != NULL) { 262 if (match(dssdev, data)) 263 return dssdev; 264 } 265 266 return NULL; 267 } 268 EXPORT_SYMBOL(omap_dss_find_device); 269 270 void videomode_to_omap_video_timings(const struct videomode *vm, 271 struct omap_video_timings *ovt) 272 { 273 memset(ovt, 0, sizeof(*ovt)); 274 275 ovt->pixelclock = vm->pixelclock; 276 ovt->x_res = vm->hactive; 277 ovt->hbp = vm->hback_porch; 278 ovt->hfp = vm->hfront_porch; 279 ovt->hsw = vm->hsync_len; 280 ovt->y_res = vm->vactive; 281 ovt->vbp = vm->vback_porch; 282 ovt->vfp = vm->vfront_porch; 283 ovt->vsw = vm->vsync_len; 284 285 ovt->vsync_level = vm->flags & DISPLAY_FLAGS_VSYNC_HIGH ? 286 OMAPDSS_SIG_ACTIVE_HIGH : 287 OMAPDSS_SIG_ACTIVE_LOW; 288 ovt->hsync_level = vm->flags & DISPLAY_FLAGS_HSYNC_HIGH ? 289 OMAPDSS_SIG_ACTIVE_HIGH : 290 OMAPDSS_SIG_ACTIVE_LOW; 291 ovt->de_level = vm->flags & DISPLAY_FLAGS_DE_HIGH ? 292 OMAPDSS_SIG_ACTIVE_HIGH : 293 OMAPDSS_SIG_ACTIVE_LOW; 294 ovt->data_pclk_edge = vm->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE ? 295 OMAPDSS_DRIVE_SIG_RISING_EDGE : 296 OMAPDSS_DRIVE_SIG_FALLING_EDGE; 297 298 ovt->sync_pclk_edge = ovt->data_pclk_edge; 299 } 300 EXPORT_SYMBOL(videomode_to_omap_video_timings); 301 302 void omap_video_timings_to_videomode(const struct omap_video_timings *ovt, 303 struct videomode *vm) 304 { 305 memset(vm, 0, sizeof(*vm)); 306 307 vm->pixelclock = ovt->pixelclock; 308 309 vm->hactive = ovt->x_res; 310 vm->hback_porch = ovt->hbp; 311 vm->hfront_porch = ovt->hfp; 312 vm->hsync_len = ovt->hsw; 313 vm->vactive = ovt->y_res; 314 vm->vback_porch = ovt->vbp; 315 vm->vfront_porch = ovt->vfp; 316 vm->vsync_len = ovt->vsw; 317 318 if (ovt->hsync_level == OMAPDSS_SIG_ACTIVE_HIGH) 319 vm->flags |= DISPLAY_FLAGS_HSYNC_HIGH; 320 else 321 vm->flags |= DISPLAY_FLAGS_HSYNC_LOW; 322 323 if (ovt->vsync_level == OMAPDSS_SIG_ACTIVE_HIGH) 324 vm->flags |= DISPLAY_FLAGS_VSYNC_HIGH; 325 else 326 vm->flags |= DISPLAY_FLAGS_VSYNC_LOW; 327 328 if (ovt->de_level == OMAPDSS_SIG_ACTIVE_HIGH) 329 vm->flags |= DISPLAY_FLAGS_DE_HIGH; 330 else 331 vm->flags |= DISPLAY_FLAGS_DE_LOW; 332 333 if (ovt->data_pclk_edge == OMAPDSS_DRIVE_SIG_RISING_EDGE) 334 vm->flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE; 335 else 336 vm->flags |= DISPLAY_FLAGS_PIXDATA_NEGEDGE; 337 } 338 EXPORT_SYMBOL(omap_video_timings_to_videomode); 339