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