328 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * linux/drivers/video/omap2/dss/display.c4 *5 * Copyright (C) 2009 Nokia Corporation6 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>7 *8 * Some code and ideas taken from drivers/video/omap/ driver9 * 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 24void 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}30EXPORT_SYMBOL(omapdss_default_get_resolution);31 32int 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 else39 return 16;40 41 case OMAP_DISPLAY_TYPE_DBI:42 if (dssdev->ctrl.pixel_size == 24)43 return 24;44 else45 return 16;46 case OMAP_DISPLAY_TYPE_DSI:47 if (dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) > 16)48 return 24;49 else50 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}61EXPORT_SYMBOL(omapdss_default_get_recommended_bpp);62 63void omapdss_default_get_timings(struct omap_dss_device *dssdev,64 struct omap_video_timings *timings)65{66 *timings = dssdev->panel.timings;67}68EXPORT_SYMBOL(omapdss_default_get_timings);69 70int 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 89int 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 106void 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 119static LIST_HEAD(panel_list);120static DEFINE_MUTEX(panel_list_mutex);121static int disp_num_counter;122 123int 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 all131 * 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}165EXPORT_SYMBOL(omapdss_register_display);166 167void 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}173EXPORT_SYMBOL(omapdss_unregister_display);174 175struct 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}187EXPORT_SYMBOL(omap_dss_get_device);188 189void omap_dss_put_device(struct omap_dss_device *dssdev)190{191 put_device(dssdev->dev);192 module_put(dssdev->owner);193}194EXPORT_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 */200struct 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;239out:240 mutex_unlock(&panel_list_mutex);241 return dssdev;242}243EXPORT_SYMBOL(omap_dss_get_next_device);244 245struct 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}257EXPORT_SYMBOL(omap_dss_find_device);258 259void 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}289EXPORT_SYMBOL(videomode_to_omap_video_timings);290 291void 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 else310 vm->flags |= DISPLAY_FLAGS_HSYNC_LOW;311 312 if (ovt->vsync_level == OMAPDSS_SIG_ACTIVE_HIGH)313 vm->flags |= DISPLAY_FLAGS_VSYNC_HIGH;314 else315 vm->flags |= DISPLAY_FLAGS_VSYNC_LOW;316 317 if (ovt->de_level == OMAPDSS_SIG_ACTIVE_HIGH)318 vm->flags |= DISPLAY_FLAGS_DE_HIGH;319 else320 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 else325 vm->flags |= DISPLAY_FLAGS_PIXDATA_NEGEDGE;326}327EXPORT_SYMBOL(omap_video_timings_to_videomode);328