162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (C) 2013, NVIDIA Corporation. All rights reserved. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 562306a36Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 662306a36Sopenharmony_ci * to deal in the Software without restriction, including without limitation 762306a36Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sub license, 862306a36Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 962306a36Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * The above copyright notice and this permission notice (including the 1262306a36Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 1362306a36Sopenharmony_ci * of the Software. 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1662306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1762306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 1862306a36Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1962306a36Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2062306a36Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 2162306a36Sopenharmony_ci * DEALINGS IN THE SOFTWARE. 2262306a36Sopenharmony_ci */ 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#ifndef __DRM_PANEL_H__ 2562306a36Sopenharmony_ci#define __DRM_PANEL_H__ 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include <linux/err.h> 2862306a36Sopenharmony_ci#include <linux/errno.h> 2962306a36Sopenharmony_ci#include <linux/list.h> 3062306a36Sopenharmony_ci#include <linux/mutex.h> 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistruct backlight_device; 3362306a36Sopenharmony_cistruct dentry; 3462306a36Sopenharmony_cistruct device_node; 3562306a36Sopenharmony_cistruct drm_connector; 3662306a36Sopenharmony_cistruct drm_device; 3762306a36Sopenharmony_cistruct drm_panel_follower; 3862306a36Sopenharmony_cistruct drm_panel; 3962306a36Sopenharmony_cistruct display_timing; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cienum drm_panel_orientation; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/** 4462306a36Sopenharmony_ci * struct drm_panel_funcs - perform operations on a given panel 4562306a36Sopenharmony_ci * 4662306a36Sopenharmony_ci * The .prepare() function is typically called before the display controller 4762306a36Sopenharmony_ci * starts to transmit video data. Panel drivers can use this to turn the panel 4862306a36Sopenharmony_ci * on and wait for it to become ready. If additional configuration is required 4962306a36Sopenharmony_ci * (via a control bus such as I2C, SPI or DSI for example) this is a good time 5062306a36Sopenharmony_ci * to do that. 5162306a36Sopenharmony_ci * 5262306a36Sopenharmony_ci * After the display controller has started transmitting video data, it's safe 5362306a36Sopenharmony_ci * to call the .enable() function. This will typically enable the backlight to 5462306a36Sopenharmony_ci * make the image on screen visible. Some panels require a certain amount of 5562306a36Sopenharmony_ci * time or frames before the image is displayed. This function is responsible 5662306a36Sopenharmony_ci * for taking this into account before enabling the backlight to avoid visual 5762306a36Sopenharmony_ci * glitches. 5862306a36Sopenharmony_ci * 5962306a36Sopenharmony_ci * Before stopping video transmission from the display controller it can be 6062306a36Sopenharmony_ci * necessary to turn off the panel to avoid visual glitches. This is done in 6162306a36Sopenharmony_ci * the .disable() function. Analogously to .enable() this typically involves 6262306a36Sopenharmony_ci * turning off the backlight and waiting for some time to make sure no image 6362306a36Sopenharmony_ci * is visible on the panel. It is then safe for the display controller to 6462306a36Sopenharmony_ci * cease transmission of video data. 6562306a36Sopenharmony_ci * 6662306a36Sopenharmony_ci * To save power when no video data is transmitted, a driver can power down 6762306a36Sopenharmony_ci * the panel. This is the job of the .unprepare() function. 6862306a36Sopenharmony_ci * 6962306a36Sopenharmony_ci * Backlight can be handled automatically if configured using 7062306a36Sopenharmony_ci * drm_panel_of_backlight() or drm_panel_dp_aux_backlight(). Then the driver 7162306a36Sopenharmony_ci * does not need to implement the functionality to enable/disable backlight. 7262306a36Sopenharmony_ci */ 7362306a36Sopenharmony_cistruct drm_panel_funcs { 7462306a36Sopenharmony_ci /** 7562306a36Sopenharmony_ci * @prepare: 7662306a36Sopenharmony_ci * 7762306a36Sopenharmony_ci * Turn on panel and perform set up. 7862306a36Sopenharmony_ci * 7962306a36Sopenharmony_ci * This function is optional. 8062306a36Sopenharmony_ci */ 8162306a36Sopenharmony_ci int (*prepare)(struct drm_panel *panel); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci /** 8462306a36Sopenharmony_ci * @enable: 8562306a36Sopenharmony_ci * 8662306a36Sopenharmony_ci * Enable panel (turn on back light, etc.). 8762306a36Sopenharmony_ci * 8862306a36Sopenharmony_ci * This function is optional. 8962306a36Sopenharmony_ci */ 9062306a36Sopenharmony_ci int (*enable)(struct drm_panel *panel); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci /** 9362306a36Sopenharmony_ci * @disable: 9462306a36Sopenharmony_ci * 9562306a36Sopenharmony_ci * Disable panel (turn off back light, etc.). 9662306a36Sopenharmony_ci * 9762306a36Sopenharmony_ci * This function is optional. 9862306a36Sopenharmony_ci */ 9962306a36Sopenharmony_ci int (*disable)(struct drm_panel *panel); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci /** 10262306a36Sopenharmony_ci * @unprepare: 10362306a36Sopenharmony_ci * 10462306a36Sopenharmony_ci * Turn off panel. 10562306a36Sopenharmony_ci * 10662306a36Sopenharmony_ci * This function is optional. 10762306a36Sopenharmony_ci */ 10862306a36Sopenharmony_ci int (*unprepare)(struct drm_panel *panel); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci /** 11162306a36Sopenharmony_ci * @get_modes: 11262306a36Sopenharmony_ci * 11362306a36Sopenharmony_ci * Add modes to the connector that the panel is attached to 11462306a36Sopenharmony_ci * and returns the number of modes added. 11562306a36Sopenharmony_ci * 11662306a36Sopenharmony_ci * This function is mandatory. 11762306a36Sopenharmony_ci */ 11862306a36Sopenharmony_ci int (*get_modes)(struct drm_panel *panel, 11962306a36Sopenharmony_ci struct drm_connector *connector); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci /** 12262306a36Sopenharmony_ci * @get_orientation: 12362306a36Sopenharmony_ci * 12462306a36Sopenharmony_ci * Return the panel orientation set by device tree or EDID. 12562306a36Sopenharmony_ci * 12662306a36Sopenharmony_ci * This function is optional. 12762306a36Sopenharmony_ci */ 12862306a36Sopenharmony_ci enum drm_panel_orientation (*get_orientation)(struct drm_panel *panel); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci /** 13162306a36Sopenharmony_ci * @get_timings: 13262306a36Sopenharmony_ci * 13362306a36Sopenharmony_ci * Copy display timings into the provided array and return 13462306a36Sopenharmony_ci * the number of display timings available. 13562306a36Sopenharmony_ci * 13662306a36Sopenharmony_ci * This function is optional. 13762306a36Sopenharmony_ci */ 13862306a36Sopenharmony_ci int (*get_timings)(struct drm_panel *panel, unsigned int num_timings, 13962306a36Sopenharmony_ci struct display_timing *timings); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci /** 14262306a36Sopenharmony_ci * @debugfs_init: 14362306a36Sopenharmony_ci * 14462306a36Sopenharmony_ci * Allows panels to create panels-specific debugfs files. 14562306a36Sopenharmony_ci */ 14662306a36Sopenharmony_ci void (*debugfs_init)(struct drm_panel *panel, struct dentry *root); 14762306a36Sopenharmony_ci}; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cistruct drm_panel_follower_funcs { 15062306a36Sopenharmony_ci /** 15162306a36Sopenharmony_ci * @panel_prepared: 15262306a36Sopenharmony_ci * 15362306a36Sopenharmony_ci * Called after the panel has been powered on. 15462306a36Sopenharmony_ci */ 15562306a36Sopenharmony_ci int (*panel_prepared)(struct drm_panel_follower *follower); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci /** 15862306a36Sopenharmony_ci * @panel_unpreparing: 15962306a36Sopenharmony_ci * 16062306a36Sopenharmony_ci * Called before the panel is powered off. 16162306a36Sopenharmony_ci */ 16262306a36Sopenharmony_ci int (*panel_unpreparing)(struct drm_panel_follower *follower); 16362306a36Sopenharmony_ci}; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistruct drm_panel_follower { 16662306a36Sopenharmony_ci /** 16762306a36Sopenharmony_ci * @funcs: 16862306a36Sopenharmony_ci * 16962306a36Sopenharmony_ci * Dependent device callbacks; should be initted by the caller. 17062306a36Sopenharmony_ci */ 17162306a36Sopenharmony_ci const struct drm_panel_follower_funcs *funcs; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci /** 17462306a36Sopenharmony_ci * @list 17562306a36Sopenharmony_ci * 17662306a36Sopenharmony_ci * Used for linking into panel's list; set by drm_panel_add_follower(). 17762306a36Sopenharmony_ci */ 17862306a36Sopenharmony_ci struct list_head list; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci /** 18162306a36Sopenharmony_ci * @panel 18262306a36Sopenharmony_ci * 18362306a36Sopenharmony_ci * The panel we're dependent on; set by drm_panel_add_follower(). 18462306a36Sopenharmony_ci */ 18562306a36Sopenharmony_ci struct drm_panel *panel; 18662306a36Sopenharmony_ci}; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci/** 18962306a36Sopenharmony_ci * struct drm_panel - DRM panel object 19062306a36Sopenharmony_ci */ 19162306a36Sopenharmony_cistruct drm_panel { 19262306a36Sopenharmony_ci /** 19362306a36Sopenharmony_ci * @dev: 19462306a36Sopenharmony_ci * 19562306a36Sopenharmony_ci * Parent device of the panel. 19662306a36Sopenharmony_ci */ 19762306a36Sopenharmony_ci struct device *dev; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci /** 20062306a36Sopenharmony_ci * @backlight: 20162306a36Sopenharmony_ci * 20262306a36Sopenharmony_ci * Backlight device, used to turn on backlight after the call 20362306a36Sopenharmony_ci * to enable(), and to turn off backlight before the call to 20462306a36Sopenharmony_ci * disable(). 20562306a36Sopenharmony_ci * backlight is set by drm_panel_of_backlight() or 20662306a36Sopenharmony_ci * drm_panel_dp_aux_backlight() and drivers shall not assign it. 20762306a36Sopenharmony_ci */ 20862306a36Sopenharmony_ci struct backlight_device *backlight; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci /** 21162306a36Sopenharmony_ci * @funcs: 21262306a36Sopenharmony_ci * 21362306a36Sopenharmony_ci * Operations that can be performed on the panel. 21462306a36Sopenharmony_ci */ 21562306a36Sopenharmony_ci const struct drm_panel_funcs *funcs; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci /** 21862306a36Sopenharmony_ci * @connector_type: 21962306a36Sopenharmony_ci * 22062306a36Sopenharmony_ci * Type of the panel as a DRM_MODE_CONNECTOR_* value. This is used to 22162306a36Sopenharmony_ci * initialise the drm_connector corresponding to the panel with the 22262306a36Sopenharmony_ci * correct connector type. 22362306a36Sopenharmony_ci */ 22462306a36Sopenharmony_ci int connector_type; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci /** 22762306a36Sopenharmony_ci * @list: 22862306a36Sopenharmony_ci * 22962306a36Sopenharmony_ci * Panel entry in registry. 23062306a36Sopenharmony_ci */ 23162306a36Sopenharmony_ci struct list_head list; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci /** 23462306a36Sopenharmony_ci * @followers: 23562306a36Sopenharmony_ci * 23662306a36Sopenharmony_ci * A list of struct drm_panel_follower dependent on this panel. 23762306a36Sopenharmony_ci */ 23862306a36Sopenharmony_ci struct list_head followers; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci /** 24162306a36Sopenharmony_ci * @follower_lock: 24262306a36Sopenharmony_ci * 24362306a36Sopenharmony_ci * Lock for followers list. 24462306a36Sopenharmony_ci */ 24562306a36Sopenharmony_ci struct mutex follower_lock; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci /** 24862306a36Sopenharmony_ci * @prepare_prev_first: 24962306a36Sopenharmony_ci * 25062306a36Sopenharmony_ci * The previous controller should be prepared first, before the prepare 25162306a36Sopenharmony_ci * for the panel is called. This is largely required for DSI panels 25262306a36Sopenharmony_ci * where the DSI host controller should be initialised to LP-11 before 25362306a36Sopenharmony_ci * the panel is powered up. 25462306a36Sopenharmony_ci */ 25562306a36Sopenharmony_ci bool prepare_prev_first; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci /** 25862306a36Sopenharmony_ci * @prepared: 25962306a36Sopenharmony_ci * 26062306a36Sopenharmony_ci * If true then the panel has been prepared. 26162306a36Sopenharmony_ci */ 26262306a36Sopenharmony_ci bool prepared; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci /** 26562306a36Sopenharmony_ci * @enabled: 26662306a36Sopenharmony_ci * 26762306a36Sopenharmony_ci * If true then the panel has been enabled. 26862306a36Sopenharmony_ci */ 26962306a36Sopenharmony_ci bool enabled; 27062306a36Sopenharmony_ci}; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_civoid drm_panel_init(struct drm_panel *panel, struct device *dev, 27362306a36Sopenharmony_ci const struct drm_panel_funcs *funcs, 27462306a36Sopenharmony_ci int connector_type); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_civoid drm_panel_add(struct drm_panel *panel); 27762306a36Sopenharmony_civoid drm_panel_remove(struct drm_panel *panel); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ciint drm_panel_prepare(struct drm_panel *panel); 28062306a36Sopenharmony_ciint drm_panel_unprepare(struct drm_panel *panel); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ciint drm_panel_enable(struct drm_panel *panel); 28362306a36Sopenharmony_ciint drm_panel_disable(struct drm_panel *panel); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ciint drm_panel_get_modes(struct drm_panel *panel, struct drm_connector *connector); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci#if defined(CONFIG_OF) && defined(CONFIG_DRM_PANEL) 28862306a36Sopenharmony_cistruct drm_panel *of_drm_find_panel(const struct device_node *np); 28962306a36Sopenharmony_ciint of_drm_get_panel_orientation(const struct device_node *np, 29062306a36Sopenharmony_ci enum drm_panel_orientation *orientation); 29162306a36Sopenharmony_ci#else 29262306a36Sopenharmony_cistatic inline struct drm_panel *of_drm_find_panel(const struct device_node *np) 29362306a36Sopenharmony_ci{ 29462306a36Sopenharmony_ci return ERR_PTR(-ENODEV); 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cistatic inline int of_drm_get_panel_orientation(const struct device_node *np, 29862306a36Sopenharmony_ci enum drm_panel_orientation *orientation) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci return -ENODEV; 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci#endif 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci#if defined(CONFIG_DRM_PANEL) 30562306a36Sopenharmony_cibool drm_is_panel_follower(struct device *dev); 30662306a36Sopenharmony_ciint drm_panel_add_follower(struct device *follower_dev, 30762306a36Sopenharmony_ci struct drm_panel_follower *follower); 30862306a36Sopenharmony_civoid drm_panel_remove_follower(struct drm_panel_follower *follower); 30962306a36Sopenharmony_ciint devm_drm_panel_add_follower(struct device *follower_dev, 31062306a36Sopenharmony_ci struct drm_panel_follower *follower); 31162306a36Sopenharmony_ci#else 31262306a36Sopenharmony_cistatic inline bool drm_is_panel_follower(struct device *dev) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci return false; 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_cistatic inline int drm_panel_add_follower(struct device *follower_dev, 31862306a36Sopenharmony_ci struct drm_panel_follower *follower) 31962306a36Sopenharmony_ci{ 32062306a36Sopenharmony_ci return -ENODEV; 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic inline void drm_panel_remove_follower(struct drm_panel_follower *follower) { } 32462306a36Sopenharmony_cistatic inline int devm_drm_panel_add_follower(struct device *follower_dev, 32562306a36Sopenharmony_ci struct drm_panel_follower *follower) 32662306a36Sopenharmony_ci{ 32762306a36Sopenharmony_ci return -ENODEV; 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_ci#endif 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_DRM_PANEL) && (IS_BUILTIN(CONFIG_BACKLIGHT_CLASS_DEVICE) || \ 33262306a36Sopenharmony_ci (IS_MODULE(CONFIG_DRM) && IS_MODULE(CONFIG_BACKLIGHT_CLASS_DEVICE))) 33362306a36Sopenharmony_ciint drm_panel_of_backlight(struct drm_panel *panel); 33462306a36Sopenharmony_ci#else 33562306a36Sopenharmony_cistatic inline int drm_panel_of_backlight(struct drm_panel *panel) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci return 0; 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci#endif 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci#endif 342