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