Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * linux/drivers/video/omap2/dss/display.c
0004  *
0005  * Copyright (C) 2009 Nokia Corporation
0006  * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
0007  *
0008  * Some code and ideas taken from drivers/video/omap/ driver
0009  * by Imre Deak.
0010  */
0011 
0012 #define DSS_SUBSYS_NAME "DISPLAY"
0013 
0014 #include <linux/kernel.h>
0015 #include <linux/module.h>
0016 #include <linux/jiffies.h>
0017 #include <linux/platform_device.h>
0018 #include <linux/of.h>
0019 
0020 #include <video/omapfb_dss.h>
0021 #include "dss.h"
0022 #include "dss_features.h"
0023 
0024 void omapdss_default_get_resolution(struct omap_dss_device *dssdev,
0025             u16 *xres, u16 *yres)
0026 {
0027     *xres = dssdev->panel.timings.x_res;
0028     *yres = dssdev->panel.timings.y_res;
0029 }
0030 EXPORT_SYMBOL(omapdss_default_get_resolution);
0031 
0032 int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev)
0033 {
0034     switch (dssdev->type) {
0035     case OMAP_DISPLAY_TYPE_DPI:
0036         if (dssdev->phy.dpi.data_lines == 24)
0037             return 24;
0038         else
0039             return 16;
0040 
0041     case OMAP_DISPLAY_TYPE_DBI:
0042         if (dssdev->ctrl.pixel_size == 24)
0043             return 24;
0044         else
0045             return 16;
0046     case OMAP_DISPLAY_TYPE_DSI:
0047         if (dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) > 16)
0048             return 24;
0049         else
0050             return 16;
0051     case OMAP_DISPLAY_TYPE_VENC:
0052     case OMAP_DISPLAY_TYPE_SDI:
0053     case OMAP_DISPLAY_TYPE_HDMI:
0054     case OMAP_DISPLAY_TYPE_DVI:
0055         return 24;
0056     default:
0057         BUG();
0058         return 0;
0059     }
0060 }
0061 EXPORT_SYMBOL(omapdss_default_get_recommended_bpp);
0062 
0063 void omapdss_default_get_timings(struct omap_dss_device *dssdev,
0064         struct omap_video_timings *timings)
0065 {
0066     *timings = dssdev->panel.timings;
0067 }
0068 EXPORT_SYMBOL(omapdss_default_get_timings);
0069 
0070 int dss_suspend_all_devices(void)
0071 {
0072     struct omap_dss_device *dssdev = NULL;
0073 
0074     for_each_dss_dev(dssdev) {
0075         if (!dssdev->driver)
0076             continue;
0077 
0078         if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
0079             dssdev->driver->disable(dssdev);
0080             dssdev->activate_after_resume = true;
0081         } else {
0082             dssdev->activate_after_resume = false;
0083         }
0084     }
0085 
0086     return 0;
0087 }
0088 
0089 int dss_resume_all_devices(void)
0090 {
0091     struct omap_dss_device *dssdev = NULL;
0092 
0093     for_each_dss_dev(dssdev) {
0094         if (!dssdev->driver)
0095             continue;
0096 
0097         if (dssdev->activate_after_resume) {
0098             dssdev->driver->enable(dssdev);
0099             dssdev->activate_after_resume = false;
0100         }
0101     }
0102 
0103     return 0;
0104 }
0105 
0106 void dss_disable_all_devices(void)
0107 {
0108     struct omap_dss_device *dssdev = NULL;
0109 
0110     for_each_dss_dev(dssdev) {
0111         if (!dssdev->driver)
0112             continue;
0113 
0114         if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
0115             dssdev->driver->disable(dssdev);
0116     }
0117 }
0118 
0119 static LIST_HEAD(panel_list);
0120 static DEFINE_MUTEX(panel_list_mutex);
0121 static int disp_num_counter;
0122 
0123 int omapdss_register_display(struct omap_dss_device *dssdev)
0124 {
0125     struct omap_dss_driver *drv = dssdev->driver;
0126     int id;
0127 
0128     /*
0129      * Note: this presumes all the displays are either using DT or non-DT,
0130      * which normally should be the case. This also presumes that all
0131      * displays either have an DT alias, or none has.
0132      */
0133 
0134     if (dssdev->dev->of_node) {
0135         id = of_alias_get_id(dssdev->dev->of_node, "display");
0136 
0137         if (id < 0)
0138             id = disp_num_counter++;
0139     } else {
0140         id = disp_num_counter++;
0141     }
0142 
0143     snprintf(dssdev->alias, sizeof(dssdev->alias), "display%d", id);
0144 
0145     /* Use 'label' property for name, if it exists */
0146     if (dssdev->dev->of_node)
0147         of_property_read_string(dssdev->dev->of_node, "label",
0148             &dssdev->name);
0149 
0150     if (dssdev->name == NULL)
0151         dssdev->name = dssdev->alias;
0152 
0153     if (drv && drv->get_resolution == NULL)
0154         drv->get_resolution = omapdss_default_get_resolution;
0155     if (drv && drv->get_recommended_bpp == NULL)
0156         drv->get_recommended_bpp = omapdss_default_get_recommended_bpp;
0157     if (drv && drv->get_timings == NULL)
0158         drv->get_timings = omapdss_default_get_timings;
0159 
0160     mutex_lock(&panel_list_mutex);
0161     list_add_tail(&dssdev->panel_list, &panel_list);
0162     mutex_unlock(&panel_list_mutex);
0163     return 0;
0164 }
0165 EXPORT_SYMBOL(omapdss_register_display);
0166 
0167 void omapdss_unregister_display(struct omap_dss_device *dssdev)
0168 {
0169     mutex_lock(&panel_list_mutex);
0170     list_del(&dssdev->panel_list);
0171     mutex_unlock(&panel_list_mutex);
0172 }
0173 EXPORT_SYMBOL(omapdss_unregister_display);
0174 
0175 struct omap_dss_device *omap_dss_get_device(struct omap_dss_device *dssdev)
0176 {
0177     if (!try_module_get(dssdev->owner))
0178         return NULL;
0179 
0180     if (get_device(dssdev->dev) == NULL) {
0181         module_put(dssdev->owner);
0182         return NULL;
0183     }
0184 
0185     return dssdev;
0186 }
0187 EXPORT_SYMBOL(omap_dss_get_device);
0188 
0189 void omap_dss_put_device(struct omap_dss_device *dssdev)
0190 {
0191     put_device(dssdev->dev);
0192     module_put(dssdev->owner);
0193 }
0194 EXPORT_SYMBOL(omap_dss_put_device);
0195 
0196 /*
0197  * ref count of the found device is incremented.
0198  * ref count of from-device is decremented.
0199  */
0200 struct omap_dss_device *omap_dss_get_next_device(struct omap_dss_device *from)
0201 {
0202     struct list_head *l;
0203     struct omap_dss_device *dssdev;
0204 
0205     mutex_lock(&panel_list_mutex);
0206 
0207     if (list_empty(&panel_list)) {
0208         dssdev = NULL;
0209         goto out;
0210     }
0211 
0212     if (from == NULL) {
0213         dssdev = list_first_entry(&panel_list, struct omap_dss_device,
0214                 panel_list);
0215         omap_dss_get_device(dssdev);
0216         goto out;
0217     }
0218 
0219     omap_dss_put_device(from);
0220 
0221     list_for_each(l, &panel_list) {
0222         dssdev = list_entry(l, struct omap_dss_device, panel_list);
0223         if (dssdev == from) {
0224             if (list_is_last(l, &panel_list)) {
0225                 dssdev = NULL;
0226                 goto out;
0227             }
0228 
0229             dssdev = list_entry(l->next, struct omap_dss_device,
0230                     panel_list);
0231             omap_dss_get_device(dssdev);
0232             goto out;
0233         }
0234     }
0235 
0236     WARN(1, "'from' dssdev not found\n");
0237 
0238     dssdev = NULL;
0239 out:
0240     mutex_unlock(&panel_list_mutex);
0241     return dssdev;
0242 }
0243 EXPORT_SYMBOL(omap_dss_get_next_device);
0244 
0245 struct omap_dss_device *omap_dss_find_device(void *data,
0246         int (*match)(struct omap_dss_device *dssdev, void *data))
0247 {
0248     struct omap_dss_device *dssdev = NULL;
0249 
0250     while ((dssdev = omap_dss_get_next_device(dssdev)) != NULL) {
0251         if (match(dssdev, data))
0252             return dssdev;
0253     }
0254 
0255     return NULL;
0256 }
0257 EXPORT_SYMBOL(omap_dss_find_device);
0258 
0259 void videomode_to_omap_video_timings(const struct videomode *vm,
0260         struct omap_video_timings *ovt)
0261 {
0262     memset(ovt, 0, sizeof(*ovt));
0263 
0264     ovt->pixelclock = vm->pixelclock;
0265     ovt->x_res = vm->hactive;
0266     ovt->hbp = vm->hback_porch;
0267     ovt->hfp = vm->hfront_porch;
0268     ovt->hsw = vm->hsync_len;
0269     ovt->y_res = vm->vactive;
0270     ovt->vbp = vm->vback_porch;
0271     ovt->vfp = vm->vfront_porch;
0272     ovt->vsw = vm->vsync_len;
0273 
0274     ovt->vsync_level = vm->flags & DISPLAY_FLAGS_VSYNC_HIGH ?
0275         OMAPDSS_SIG_ACTIVE_HIGH :
0276         OMAPDSS_SIG_ACTIVE_LOW;
0277     ovt->hsync_level = vm->flags & DISPLAY_FLAGS_HSYNC_HIGH ?
0278         OMAPDSS_SIG_ACTIVE_HIGH :
0279         OMAPDSS_SIG_ACTIVE_LOW;
0280     ovt->de_level = vm->flags & DISPLAY_FLAGS_DE_HIGH ?
0281         OMAPDSS_SIG_ACTIVE_HIGH :
0282         OMAPDSS_SIG_ACTIVE_LOW;
0283     ovt->data_pclk_edge = vm->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE ?
0284         OMAPDSS_DRIVE_SIG_RISING_EDGE :
0285         OMAPDSS_DRIVE_SIG_FALLING_EDGE;
0286 
0287     ovt->sync_pclk_edge = ovt->data_pclk_edge;
0288 }
0289 EXPORT_SYMBOL(videomode_to_omap_video_timings);
0290 
0291 void omap_video_timings_to_videomode(const struct omap_video_timings *ovt,
0292         struct videomode *vm)
0293 {
0294     memset(vm, 0, sizeof(*vm));
0295 
0296     vm->pixelclock = ovt->pixelclock;
0297 
0298     vm->hactive = ovt->x_res;
0299     vm->hback_porch = ovt->hbp;
0300     vm->hfront_porch = ovt->hfp;
0301     vm->hsync_len = ovt->hsw;
0302     vm->vactive = ovt->y_res;
0303     vm->vback_porch = ovt->vbp;
0304     vm->vfront_porch = ovt->vfp;
0305     vm->vsync_len = ovt->vsw;
0306 
0307     if (ovt->hsync_level == OMAPDSS_SIG_ACTIVE_HIGH)
0308         vm->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
0309     else
0310         vm->flags |= DISPLAY_FLAGS_HSYNC_LOW;
0311 
0312     if (ovt->vsync_level == OMAPDSS_SIG_ACTIVE_HIGH)
0313         vm->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
0314     else
0315         vm->flags |= DISPLAY_FLAGS_VSYNC_LOW;
0316 
0317     if (ovt->de_level == OMAPDSS_SIG_ACTIVE_HIGH)
0318         vm->flags |= DISPLAY_FLAGS_DE_HIGH;
0319     else
0320         vm->flags |= DISPLAY_FLAGS_DE_LOW;
0321 
0322     if (ovt->data_pclk_edge == OMAPDSS_DRIVE_SIG_RISING_EDGE)
0323         vm->flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE;
0324     else
0325         vm->flags |= DISPLAY_FLAGS_PIXDATA_NEGEDGE;
0326 }
0327 EXPORT_SYMBOL(omap_video_timings_to_videomode);