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