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#include <linux/debugfs.h>
2562306a36Sopenharmony_ci#include <linux/delay.h>
2662306a36Sopenharmony_ci#include <linux/gpio/consumer.h>
2762306a36Sopenharmony_ci#include <linux/iopoll.h>
2862306a36Sopenharmony_ci#include <linux/module.h>
2962306a36Sopenharmony_ci#include <linux/of_platform.h>
3062306a36Sopenharmony_ci#include <linux/platform_device.h>
3162306a36Sopenharmony_ci#include <linux/pm_runtime.h>
3262306a36Sopenharmony_ci#include <linux/regulator/consumer.h>
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#include <video/display_timing.h>
3562306a36Sopenharmony_ci#include <video/of_display_timing.h>
3662306a36Sopenharmony_ci#include <video/videomode.h>
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#include <drm/display/drm_dp_aux_bus.h>
3962306a36Sopenharmony_ci#include <drm/display/drm_dp_helper.h>
4062306a36Sopenharmony_ci#include <drm/drm_crtc.h>
4162306a36Sopenharmony_ci#include <drm/drm_device.h>
4262306a36Sopenharmony_ci#include <drm/drm_edid.h>
4362306a36Sopenharmony_ci#include <drm/drm_panel.h>
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci/**
4662306a36Sopenharmony_ci * struct panel_delay - Describes delays for a simple panel.
4762306a36Sopenharmony_ci */
4862306a36Sopenharmony_cistruct panel_delay {
4962306a36Sopenharmony_ci	/**
5062306a36Sopenharmony_ci	 * @hpd_reliable: Time for HPD to be reliable
5162306a36Sopenharmony_ci	 *
5262306a36Sopenharmony_ci	 * The time (in milliseconds) that it takes after powering the panel
5362306a36Sopenharmony_ci	 * before the HPD signal is reliable. Ideally this is 0 but some panels,
5462306a36Sopenharmony_ci	 * board designs, or bad pulldown configs can cause a glitch here.
5562306a36Sopenharmony_ci	 *
5662306a36Sopenharmony_ci	 * NOTE: on some old panel data this number appears to be much too big.
5762306a36Sopenharmony_ci	 * Presumably some old panels simply didn't have HPD hooked up and put
5862306a36Sopenharmony_ci	 * the hpd_absent here because this field predates the
5962306a36Sopenharmony_ci	 * hpd_absent. While that works, it's non-ideal.
6062306a36Sopenharmony_ci	 */
6162306a36Sopenharmony_ci	unsigned int hpd_reliable;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	/**
6462306a36Sopenharmony_ci	 * @hpd_absent: Time to wait if HPD isn't hooked up.
6562306a36Sopenharmony_ci	 *
6662306a36Sopenharmony_ci	 * Add this to the prepare delay if we know Hot Plug Detect isn't used.
6762306a36Sopenharmony_ci	 *
6862306a36Sopenharmony_ci	 * This is T3-max on eDP timing diagrams or the delay from power on
6962306a36Sopenharmony_ci	 * until HPD is guaranteed to be asserted.
7062306a36Sopenharmony_ci	 */
7162306a36Sopenharmony_ci	unsigned int hpd_absent;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	/**
7462306a36Sopenharmony_ci	 * @prepare_to_enable: Time between prepare and enable.
7562306a36Sopenharmony_ci	 *
7662306a36Sopenharmony_ci	 * The minimum time, in milliseconds, that needs to have passed
7762306a36Sopenharmony_ci	 * between when prepare finished and enable may begin. If at
7862306a36Sopenharmony_ci	 * enable time less time has passed since prepare finished,
7962306a36Sopenharmony_ci	 * the driver waits for the remaining time.
8062306a36Sopenharmony_ci	 *
8162306a36Sopenharmony_ci	 * If a fixed enable delay is also specified, we'll start
8262306a36Sopenharmony_ci	 * counting before delaying for the fixed delay.
8362306a36Sopenharmony_ci	 *
8462306a36Sopenharmony_ci	 * If a fixed prepare delay is also specified, we won't start
8562306a36Sopenharmony_ci	 * counting until after the fixed delay. We can't overlap this
8662306a36Sopenharmony_ci	 * fixed delay with the min time because the fixed delay
8762306a36Sopenharmony_ci	 * doesn't happen at the end of the function if a HPD GPIO was
8862306a36Sopenharmony_ci	 * specified.
8962306a36Sopenharmony_ci	 *
9062306a36Sopenharmony_ci	 * In other words:
9162306a36Sopenharmony_ci	 *   prepare()
9262306a36Sopenharmony_ci	 *     ...
9362306a36Sopenharmony_ci	 *     // do fixed prepare delay
9462306a36Sopenharmony_ci	 *     // wait for HPD GPIO if applicable
9562306a36Sopenharmony_ci	 *     // start counting for prepare_to_enable
9662306a36Sopenharmony_ci	 *
9762306a36Sopenharmony_ci	 *   enable()
9862306a36Sopenharmony_ci	 *     // do fixed enable delay
9962306a36Sopenharmony_ci	 *     // enforce prepare_to_enable min time
10062306a36Sopenharmony_ci	 *
10162306a36Sopenharmony_ci	 * This is not specified in a standard way on eDP timing diagrams.
10262306a36Sopenharmony_ci	 * It is effectively the time from HPD going high till you can
10362306a36Sopenharmony_ci	 * turn on the backlight.
10462306a36Sopenharmony_ci	 */
10562306a36Sopenharmony_ci	unsigned int prepare_to_enable;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	/**
10862306a36Sopenharmony_ci	 * @enable: Time for the panel to display a valid frame.
10962306a36Sopenharmony_ci	 *
11062306a36Sopenharmony_ci	 * The time (in milliseconds) that it takes for the panel to
11162306a36Sopenharmony_ci	 * display the first valid frame after starting to receive
11262306a36Sopenharmony_ci	 * video data.
11362306a36Sopenharmony_ci	 *
11462306a36Sopenharmony_ci	 * This is (T6-min + max(T7-max, T8-min)) on eDP timing diagrams or
11562306a36Sopenharmony_ci	 * the delay after link training finishes until we can turn the
11662306a36Sopenharmony_ci	 * backlight on and see valid data.
11762306a36Sopenharmony_ci	 */
11862306a36Sopenharmony_ci	unsigned int enable;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	/**
12162306a36Sopenharmony_ci	 * @disable: Time for the panel to turn the display off.
12262306a36Sopenharmony_ci	 *
12362306a36Sopenharmony_ci	 * The time (in milliseconds) that it takes for the panel to
12462306a36Sopenharmony_ci	 * turn the display off (no content is visible).
12562306a36Sopenharmony_ci	 *
12662306a36Sopenharmony_ci	 * This is T9-min (delay from backlight off to end of valid video
12762306a36Sopenharmony_ci	 * data) on eDP timing diagrams. It is not common to set.
12862306a36Sopenharmony_ci	 */
12962306a36Sopenharmony_ci	unsigned int disable;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	/**
13262306a36Sopenharmony_ci	 * @unprepare: Time to power down completely.
13362306a36Sopenharmony_ci	 *
13462306a36Sopenharmony_ci	 * The time (in milliseconds) that it takes for the panel
13562306a36Sopenharmony_ci	 * to power itself down completely.
13662306a36Sopenharmony_ci	 *
13762306a36Sopenharmony_ci	 * This time is used to prevent a future "prepare" from
13862306a36Sopenharmony_ci	 * starting until at least this many milliseconds has passed.
13962306a36Sopenharmony_ci	 * If at prepare time less time has passed since unprepare
14062306a36Sopenharmony_ci	 * finished, the driver waits for the remaining time.
14162306a36Sopenharmony_ci	 *
14262306a36Sopenharmony_ci	 * This is T12-min on eDP timing diagrams.
14362306a36Sopenharmony_ci	 */
14462306a36Sopenharmony_ci	unsigned int unprepare;
14562306a36Sopenharmony_ci};
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci/**
14862306a36Sopenharmony_ci * struct panel_desc - Describes a simple panel.
14962306a36Sopenharmony_ci */
15062306a36Sopenharmony_cistruct panel_desc {
15162306a36Sopenharmony_ci	/**
15262306a36Sopenharmony_ci	 * @modes: Pointer to array of fixed modes appropriate for this panel.
15362306a36Sopenharmony_ci	 *
15462306a36Sopenharmony_ci	 * If only one mode then this can just be the address of the mode.
15562306a36Sopenharmony_ci	 * NOTE: cannot be used with "timings" and also if this is specified
15662306a36Sopenharmony_ci	 * then you cannot override the mode in the device tree.
15762306a36Sopenharmony_ci	 */
15862306a36Sopenharmony_ci	const struct drm_display_mode *modes;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	/** @num_modes: Number of elements in modes array. */
16162306a36Sopenharmony_ci	unsigned int num_modes;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	/**
16462306a36Sopenharmony_ci	 * @timings: Pointer to array of display timings
16562306a36Sopenharmony_ci	 *
16662306a36Sopenharmony_ci	 * NOTE: cannot be used with "modes" and also these will be used to
16762306a36Sopenharmony_ci	 * validate a device tree override if one is present.
16862306a36Sopenharmony_ci	 */
16962306a36Sopenharmony_ci	const struct display_timing *timings;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	/** @num_timings: Number of elements in timings array. */
17262306a36Sopenharmony_ci	unsigned int num_timings;
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	/** @bpc: Bits per color. */
17562306a36Sopenharmony_ci	unsigned int bpc;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	/** @size: Structure containing the physical size of this panel. */
17862306a36Sopenharmony_ci	struct {
17962306a36Sopenharmony_ci		/**
18062306a36Sopenharmony_ci		 * @size.width: Width (in mm) of the active display area.
18162306a36Sopenharmony_ci		 */
18262306a36Sopenharmony_ci		unsigned int width;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci		/**
18562306a36Sopenharmony_ci		 * @size.height: Height (in mm) of the active display area.
18662306a36Sopenharmony_ci		 */
18762306a36Sopenharmony_ci		unsigned int height;
18862306a36Sopenharmony_ci	} size;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	/** @delay: Structure containing various delay values for this panel. */
19162306a36Sopenharmony_ci	struct panel_delay delay;
19262306a36Sopenharmony_ci};
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci/**
19562306a36Sopenharmony_ci * struct edp_panel_entry - Maps panel ID to delay / panel name.
19662306a36Sopenharmony_ci */
19762306a36Sopenharmony_cistruct edp_panel_entry {
19862306a36Sopenharmony_ci	/** @panel_id: 32-bit ID for panel, encoded with drm_edid_encode_panel_id(). */
19962306a36Sopenharmony_ci	u32 panel_id;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	/** @delay: The power sequencing delays needed for this panel. */
20262306a36Sopenharmony_ci	const struct panel_delay *delay;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	/** @name: Name of this panel (for printing to logs). */
20562306a36Sopenharmony_ci	const char *name;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	/** @override_edid_mode: Override the mode obtained by edid. */
20862306a36Sopenharmony_ci	const struct drm_display_mode *override_edid_mode;
20962306a36Sopenharmony_ci};
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_cistruct panel_edp {
21262306a36Sopenharmony_ci	struct drm_panel base;
21362306a36Sopenharmony_ci	bool enabled;
21462306a36Sopenharmony_ci	bool no_hpd;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	bool prepared;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	ktime_t prepared_time;
21962306a36Sopenharmony_ci	ktime_t unprepared_time;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	const struct panel_desc *desc;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	struct regulator *supply;
22462306a36Sopenharmony_ci	struct i2c_adapter *ddc;
22562306a36Sopenharmony_ci	struct drm_dp_aux *aux;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	struct gpio_desc *enable_gpio;
22862306a36Sopenharmony_ci	struct gpio_desc *hpd_gpio;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	const struct edp_panel_entry *detected_panel;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	struct edid *edid;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	struct drm_display_mode override_mode;
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	enum drm_panel_orientation orientation;
23762306a36Sopenharmony_ci};
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistatic inline struct panel_edp *to_panel_edp(struct drm_panel *panel)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	return container_of(panel, struct panel_edp, base);
24262306a36Sopenharmony_ci}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_cistatic unsigned int panel_edp_get_timings_modes(struct panel_edp *panel,
24562306a36Sopenharmony_ci						struct drm_connector *connector)
24662306a36Sopenharmony_ci{
24762306a36Sopenharmony_ci	struct drm_display_mode *mode;
24862306a36Sopenharmony_ci	unsigned int i, num = 0;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	for (i = 0; i < panel->desc->num_timings; i++) {
25162306a36Sopenharmony_ci		const struct display_timing *dt = &panel->desc->timings[i];
25262306a36Sopenharmony_ci		struct videomode vm;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci		videomode_from_timing(dt, &vm);
25562306a36Sopenharmony_ci		mode = drm_mode_create(connector->dev);
25662306a36Sopenharmony_ci		if (!mode) {
25762306a36Sopenharmony_ci			dev_err(panel->base.dev, "failed to add mode %ux%u\n",
25862306a36Sopenharmony_ci				dt->hactive.typ, dt->vactive.typ);
25962306a36Sopenharmony_ci			continue;
26062306a36Sopenharmony_ci		}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci		drm_display_mode_from_videomode(&vm, mode);
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci		mode->type |= DRM_MODE_TYPE_DRIVER;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci		if (panel->desc->num_timings == 1)
26762306a36Sopenharmony_ci			mode->type |= DRM_MODE_TYPE_PREFERRED;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci		drm_mode_probed_add(connector, mode);
27062306a36Sopenharmony_ci		num++;
27162306a36Sopenharmony_ci	}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	return num;
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cistatic unsigned int panel_edp_get_display_modes(struct panel_edp *panel,
27762306a36Sopenharmony_ci						struct drm_connector *connector)
27862306a36Sopenharmony_ci{
27962306a36Sopenharmony_ci	struct drm_display_mode *mode;
28062306a36Sopenharmony_ci	unsigned int i, num = 0;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	for (i = 0; i < panel->desc->num_modes; i++) {
28362306a36Sopenharmony_ci		const struct drm_display_mode *m = &panel->desc->modes[i];
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci		mode = drm_mode_duplicate(connector->dev, m);
28662306a36Sopenharmony_ci		if (!mode) {
28762306a36Sopenharmony_ci			dev_err(panel->base.dev, "failed to add mode %ux%u@%u\n",
28862306a36Sopenharmony_ci				m->hdisplay, m->vdisplay,
28962306a36Sopenharmony_ci				drm_mode_vrefresh(m));
29062306a36Sopenharmony_ci			continue;
29162306a36Sopenharmony_ci		}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci		mode->type |= DRM_MODE_TYPE_DRIVER;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci		if (panel->desc->num_modes == 1)
29662306a36Sopenharmony_ci			mode->type |= DRM_MODE_TYPE_PREFERRED;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci		drm_mode_set_name(mode);
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci		drm_mode_probed_add(connector, mode);
30162306a36Sopenharmony_ci		num++;
30262306a36Sopenharmony_ci	}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	return num;
30562306a36Sopenharmony_ci}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_cistatic int panel_edp_override_edid_mode(struct panel_edp *panel,
30862306a36Sopenharmony_ci					struct drm_connector *connector,
30962306a36Sopenharmony_ci					const struct drm_display_mode *override_mode)
31062306a36Sopenharmony_ci{
31162306a36Sopenharmony_ci	struct drm_display_mode *mode;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	mode = drm_mode_duplicate(connector->dev, override_mode);
31462306a36Sopenharmony_ci	if (!mode) {
31562306a36Sopenharmony_ci		dev_err(panel->base.dev, "failed to add additional mode\n");
31662306a36Sopenharmony_ci		return 0;
31762306a36Sopenharmony_ci	}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
32062306a36Sopenharmony_ci	drm_mode_set_name(mode);
32162306a36Sopenharmony_ci	drm_mode_probed_add(connector, mode);
32262306a36Sopenharmony_ci	return 1;
32362306a36Sopenharmony_ci}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_cistatic int panel_edp_get_non_edid_modes(struct panel_edp *panel,
32662306a36Sopenharmony_ci					struct drm_connector *connector)
32762306a36Sopenharmony_ci{
32862306a36Sopenharmony_ci	struct drm_display_mode *mode;
32962306a36Sopenharmony_ci	bool has_override = panel->override_mode.type;
33062306a36Sopenharmony_ci	unsigned int num = 0;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	if (!panel->desc)
33362306a36Sopenharmony_ci		return 0;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	if (has_override) {
33662306a36Sopenharmony_ci		mode = drm_mode_duplicate(connector->dev,
33762306a36Sopenharmony_ci					  &panel->override_mode);
33862306a36Sopenharmony_ci		if (mode) {
33962306a36Sopenharmony_ci			drm_mode_probed_add(connector, mode);
34062306a36Sopenharmony_ci			num = 1;
34162306a36Sopenharmony_ci		} else {
34262306a36Sopenharmony_ci			dev_err(panel->base.dev, "failed to add override mode\n");
34362306a36Sopenharmony_ci		}
34462306a36Sopenharmony_ci	}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	/* Only add timings if override was not there or failed to validate */
34762306a36Sopenharmony_ci	if (num == 0 && panel->desc->num_timings)
34862306a36Sopenharmony_ci		num = panel_edp_get_timings_modes(panel, connector);
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	/*
35162306a36Sopenharmony_ci	 * Only add fixed modes if timings/override added no mode.
35262306a36Sopenharmony_ci	 *
35362306a36Sopenharmony_ci	 * We should only ever have either the display timings specified
35462306a36Sopenharmony_ci	 * or a fixed mode. Anything else is rather bogus.
35562306a36Sopenharmony_ci	 */
35662306a36Sopenharmony_ci	WARN_ON(panel->desc->num_timings && panel->desc->num_modes);
35762306a36Sopenharmony_ci	if (num == 0)
35862306a36Sopenharmony_ci		num = panel_edp_get_display_modes(panel, connector);
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	connector->display_info.bpc = panel->desc->bpc;
36162306a36Sopenharmony_ci	connector->display_info.width_mm = panel->desc->size.width;
36262306a36Sopenharmony_ci	connector->display_info.height_mm = panel->desc->size.height;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	return num;
36562306a36Sopenharmony_ci}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_cistatic void panel_edp_wait(ktime_t start_ktime, unsigned int min_ms)
36862306a36Sopenharmony_ci{
36962306a36Sopenharmony_ci	ktime_t now_ktime, min_ktime;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	if (!min_ms)
37262306a36Sopenharmony_ci		return;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	min_ktime = ktime_add(start_ktime, ms_to_ktime(min_ms));
37562306a36Sopenharmony_ci	now_ktime = ktime_get_boottime();
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	if (ktime_before(now_ktime, min_ktime))
37862306a36Sopenharmony_ci		msleep(ktime_to_ms(ktime_sub(min_ktime, now_ktime)) + 1);
37962306a36Sopenharmony_ci}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_cistatic int panel_edp_disable(struct drm_panel *panel)
38262306a36Sopenharmony_ci{
38362306a36Sopenharmony_ci	struct panel_edp *p = to_panel_edp(panel);
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	if (!p->enabled)
38662306a36Sopenharmony_ci		return 0;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	if (p->desc->delay.disable)
38962306a36Sopenharmony_ci		msleep(p->desc->delay.disable);
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	p->enabled = false;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	return 0;
39462306a36Sopenharmony_ci}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_cistatic int panel_edp_suspend(struct device *dev)
39762306a36Sopenharmony_ci{
39862306a36Sopenharmony_ci	struct panel_edp *p = dev_get_drvdata(dev);
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	gpiod_set_value_cansleep(p->enable_gpio, 0);
40162306a36Sopenharmony_ci	regulator_disable(p->supply);
40262306a36Sopenharmony_ci	p->unprepared_time = ktime_get_boottime();
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	return 0;
40562306a36Sopenharmony_ci}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_cistatic int panel_edp_unprepare(struct drm_panel *panel)
40862306a36Sopenharmony_ci{
40962306a36Sopenharmony_ci	struct panel_edp *p = to_panel_edp(panel);
41062306a36Sopenharmony_ci	int ret;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	/* Unpreparing when already unprepared is a no-op */
41362306a36Sopenharmony_ci	if (!p->prepared)
41462306a36Sopenharmony_ci		return 0;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	ret = pm_runtime_put_sync_suspend(panel->dev);
41762306a36Sopenharmony_ci	if (ret < 0)
41862306a36Sopenharmony_ci		return ret;
41962306a36Sopenharmony_ci	p->prepared = false;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	return 0;
42262306a36Sopenharmony_ci}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_cistatic int panel_edp_get_hpd_gpio(struct device *dev, struct panel_edp *p)
42562306a36Sopenharmony_ci{
42662306a36Sopenharmony_ci	p->hpd_gpio = devm_gpiod_get_optional(dev, "hpd", GPIOD_IN);
42762306a36Sopenharmony_ci	if (IS_ERR(p->hpd_gpio))
42862306a36Sopenharmony_ci		return dev_err_probe(dev, PTR_ERR(p->hpd_gpio),
42962306a36Sopenharmony_ci				     "failed to get 'hpd' GPIO\n");
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	return 0;
43262306a36Sopenharmony_ci}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_cistatic bool panel_edp_can_read_hpd(struct panel_edp *p)
43562306a36Sopenharmony_ci{
43662306a36Sopenharmony_ci	return !p->no_hpd && (p->hpd_gpio || (p->aux && p->aux->wait_hpd_asserted));
43762306a36Sopenharmony_ci}
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_cistatic int panel_edp_prepare_once(struct panel_edp *p)
44062306a36Sopenharmony_ci{
44162306a36Sopenharmony_ci	struct device *dev = p->base.dev;
44262306a36Sopenharmony_ci	unsigned int delay;
44362306a36Sopenharmony_ci	int err;
44462306a36Sopenharmony_ci	int hpd_asserted;
44562306a36Sopenharmony_ci	unsigned long hpd_wait_us;
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	panel_edp_wait(p->unprepared_time, p->desc->delay.unprepare);
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	err = regulator_enable(p->supply);
45062306a36Sopenharmony_ci	if (err < 0) {
45162306a36Sopenharmony_ci		dev_err(dev, "failed to enable supply: %d\n", err);
45262306a36Sopenharmony_ci		return err;
45362306a36Sopenharmony_ci	}
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	gpiod_set_value_cansleep(p->enable_gpio, 1);
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	delay = p->desc->delay.hpd_reliable;
45862306a36Sopenharmony_ci	if (p->no_hpd)
45962306a36Sopenharmony_ci		delay = max(delay, p->desc->delay.hpd_absent);
46062306a36Sopenharmony_ci	if (delay)
46162306a36Sopenharmony_ci		msleep(delay);
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	if (panel_edp_can_read_hpd(p)) {
46462306a36Sopenharmony_ci		if (p->desc->delay.hpd_absent)
46562306a36Sopenharmony_ci			hpd_wait_us = p->desc->delay.hpd_absent * 1000UL;
46662306a36Sopenharmony_ci		else
46762306a36Sopenharmony_ci			hpd_wait_us = 2000000;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci		if (p->hpd_gpio) {
47062306a36Sopenharmony_ci			err = readx_poll_timeout(gpiod_get_value_cansleep,
47162306a36Sopenharmony_ci						 p->hpd_gpio, hpd_asserted,
47262306a36Sopenharmony_ci						 hpd_asserted, 1000, hpd_wait_us);
47362306a36Sopenharmony_ci			if (hpd_asserted < 0)
47462306a36Sopenharmony_ci				err = hpd_asserted;
47562306a36Sopenharmony_ci		} else {
47662306a36Sopenharmony_ci			err = p->aux->wait_hpd_asserted(p->aux, hpd_wait_us);
47762306a36Sopenharmony_ci		}
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci		if (err) {
48062306a36Sopenharmony_ci			if (err != -ETIMEDOUT)
48162306a36Sopenharmony_ci				dev_err(dev,
48262306a36Sopenharmony_ci					"error waiting for hpd GPIO: %d\n", err);
48362306a36Sopenharmony_ci			goto error;
48462306a36Sopenharmony_ci		}
48562306a36Sopenharmony_ci	}
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	p->prepared_time = ktime_get_boottime();
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	return 0;
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_cierror:
49262306a36Sopenharmony_ci	gpiod_set_value_cansleep(p->enable_gpio, 0);
49362306a36Sopenharmony_ci	regulator_disable(p->supply);
49462306a36Sopenharmony_ci	p->unprepared_time = ktime_get_boottime();
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	return err;
49762306a36Sopenharmony_ci}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci/*
50062306a36Sopenharmony_ci * Some panels simply don't always come up and need to be power cycled to
50162306a36Sopenharmony_ci * work properly.  We'll allow for a handful of retries.
50262306a36Sopenharmony_ci */
50362306a36Sopenharmony_ci#define MAX_PANEL_PREPARE_TRIES		5
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_cistatic int panel_edp_resume(struct device *dev)
50662306a36Sopenharmony_ci{
50762306a36Sopenharmony_ci	struct panel_edp *p = dev_get_drvdata(dev);
50862306a36Sopenharmony_ci	int ret;
50962306a36Sopenharmony_ci	int try;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	for (try = 0; try < MAX_PANEL_PREPARE_TRIES; try++) {
51262306a36Sopenharmony_ci		ret = panel_edp_prepare_once(p);
51362306a36Sopenharmony_ci		if (ret != -ETIMEDOUT)
51462306a36Sopenharmony_ci			break;
51562306a36Sopenharmony_ci	}
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	if (ret == -ETIMEDOUT)
51862306a36Sopenharmony_ci		dev_err(dev, "Prepare timeout after %d tries\n", try);
51962306a36Sopenharmony_ci	else if (try)
52062306a36Sopenharmony_ci		dev_warn(dev, "Prepare needed %d retries\n", try);
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	return ret;
52362306a36Sopenharmony_ci}
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_cistatic int panel_edp_prepare(struct drm_panel *panel)
52662306a36Sopenharmony_ci{
52762306a36Sopenharmony_ci	struct panel_edp *p = to_panel_edp(panel);
52862306a36Sopenharmony_ci	int ret;
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	/* Preparing when already prepared is a no-op */
53162306a36Sopenharmony_ci	if (p->prepared)
53262306a36Sopenharmony_ci		return 0;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	ret = pm_runtime_get_sync(panel->dev);
53562306a36Sopenharmony_ci	if (ret < 0) {
53662306a36Sopenharmony_ci		pm_runtime_put_autosuspend(panel->dev);
53762306a36Sopenharmony_ci		return ret;
53862306a36Sopenharmony_ci	}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	p->prepared = true;
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	return 0;
54362306a36Sopenharmony_ci}
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_cistatic int panel_edp_enable(struct drm_panel *panel)
54662306a36Sopenharmony_ci{
54762306a36Sopenharmony_ci	struct panel_edp *p = to_panel_edp(panel);
54862306a36Sopenharmony_ci	unsigned int delay;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	if (p->enabled)
55162306a36Sopenharmony_ci		return 0;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	delay = p->desc->delay.enable;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	/*
55662306a36Sopenharmony_ci	 * If there is a "prepare_to_enable" delay then that's supposed to be
55762306a36Sopenharmony_ci	 * the delay from HPD going high until we can turn the backlight on.
55862306a36Sopenharmony_ci	 * However, we can only count this if HPD is readable by the panel
55962306a36Sopenharmony_ci	 * driver.
56062306a36Sopenharmony_ci	 *
56162306a36Sopenharmony_ci	 * If we aren't handling the HPD pin ourselves then the best we
56262306a36Sopenharmony_ci	 * can do is assume that HPD went high immediately before we were
56362306a36Sopenharmony_ci	 * called (and link training took zero time). Note that "no-hpd"
56462306a36Sopenharmony_ci	 * actually counts as handling HPD ourselves since we're doing the
56562306a36Sopenharmony_ci	 * worst case delay (in prepare) ourselves.
56662306a36Sopenharmony_ci	 *
56762306a36Sopenharmony_ci	 * NOTE: if we ever end up in this "if" statement then we're
56862306a36Sopenharmony_ci	 * guaranteed that the panel_edp_wait() call below will do no delay.
56962306a36Sopenharmony_ci	 * It already handles that case, though, so we don't need any special
57062306a36Sopenharmony_ci	 * code for it.
57162306a36Sopenharmony_ci	 */
57262306a36Sopenharmony_ci	if (p->desc->delay.prepare_to_enable &&
57362306a36Sopenharmony_ci	    !panel_edp_can_read_hpd(p) && !p->no_hpd)
57462306a36Sopenharmony_ci		delay = max(delay, p->desc->delay.prepare_to_enable);
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	if (delay)
57762306a36Sopenharmony_ci		msleep(delay);
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	panel_edp_wait(p->prepared_time, p->desc->delay.prepare_to_enable);
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	p->enabled = true;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	return 0;
58462306a36Sopenharmony_ci}
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_cistatic int panel_edp_get_modes(struct drm_panel *panel,
58762306a36Sopenharmony_ci			       struct drm_connector *connector)
58862306a36Sopenharmony_ci{
58962306a36Sopenharmony_ci	struct panel_edp *p = to_panel_edp(panel);
59062306a36Sopenharmony_ci	int num = 0;
59162306a36Sopenharmony_ci	bool has_override_edid_mode = p->detected_panel &&
59262306a36Sopenharmony_ci				      p->detected_panel != ERR_PTR(-EINVAL) &&
59362306a36Sopenharmony_ci				      p->detected_panel->override_edid_mode;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	/* probe EDID if a DDC bus is available */
59662306a36Sopenharmony_ci	if (p->ddc) {
59762306a36Sopenharmony_ci		pm_runtime_get_sync(panel->dev);
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci		if (!p->edid)
60062306a36Sopenharmony_ci			p->edid = drm_get_edid(connector, p->ddc);
60162306a36Sopenharmony_ci		if (p->edid) {
60262306a36Sopenharmony_ci			if (has_override_edid_mode) {
60362306a36Sopenharmony_ci				/*
60462306a36Sopenharmony_ci				 * override_edid_mode is specified. Use
60562306a36Sopenharmony_ci				 * override_edid_mode instead of from edid.
60662306a36Sopenharmony_ci				 */
60762306a36Sopenharmony_ci				num += panel_edp_override_edid_mode(p, connector,
60862306a36Sopenharmony_ci						p->detected_panel->override_edid_mode);
60962306a36Sopenharmony_ci			} else {
61062306a36Sopenharmony_ci				num += drm_add_edid_modes(connector, p->edid);
61162306a36Sopenharmony_ci			}
61262306a36Sopenharmony_ci		}
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci		pm_runtime_mark_last_busy(panel->dev);
61562306a36Sopenharmony_ci		pm_runtime_put_autosuspend(panel->dev);
61662306a36Sopenharmony_ci	}
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	/*
61962306a36Sopenharmony_ci	 * Add hard-coded panel modes. Don't call this if there are no timings
62062306a36Sopenharmony_ci	 * and no modes (the generic edp-panel case) because it will clobber
62162306a36Sopenharmony_ci	 * the display_info that was already set by drm_add_edid_modes().
62262306a36Sopenharmony_ci	 */
62362306a36Sopenharmony_ci	if (p->desc->num_timings || p->desc->num_modes)
62462306a36Sopenharmony_ci		num += panel_edp_get_non_edid_modes(p, connector);
62562306a36Sopenharmony_ci	else if (!num)
62662306a36Sopenharmony_ci		dev_warn(p->base.dev, "No display modes\n");
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	/*
62962306a36Sopenharmony_ci	 * TODO: Remove once all drm drivers call
63062306a36Sopenharmony_ci	 * drm_connector_set_orientation_from_panel()
63162306a36Sopenharmony_ci	 */
63262306a36Sopenharmony_ci	drm_connector_set_panel_orientation(connector, p->orientation);
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	return num;
63562306a36Sopenharmony_ci}
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_cistatic int panel_edp_get_timings(struct drm_panel *panel,
63862306a36Sopenharmony_ci				 unsigned int num_timings,
63962306a36Sopenharmony_ci				 struct display_timing *timings)
64062306a36Sopenharmony_ci{
64162306a36Sopenharmony_ci	struct panel_edp *p = to_panel_edp(panel);
64262306a36Sopenharmony_ci	unsigned int i;
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	if (p->desc->num_timings < num_timings)
64562306a36Sopenharmony_ci		num_timings = p->desc->num_timings;
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	if (timings)
64862306a36Sopenharmony_ci		for (i = 0; i < num_timings; i++)
64962306a36Sopenharmony_ci			timings[i] = p->desc->timings[i];
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	return p->desc->num_timings;
65262306a36Sopenharmony_ci}
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_cistatic enum drm_panel_orientation panel_edp_get_orientation(struct drm_panel *panel)
65562306a36Sopenharmony_ci{
65662306a36Sopenharmony_ci	struct panel_edp *p = to_panel_edp(panel);
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	return p->orientation;
65962306a36Sopenharmony_ci}
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_cistatic int detected_panel_show(struct seq_file *s, void *data)
66262306a36Sopenharmony_ci{
66362306a36Sopenharmony_ci	struct drm_panel *panel = s->private;
66462306a36Sopenharmony_ci	struct panel_edp *p = to_panel_edp(panel);
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	if (IS_ERR(p->detected_panel))
66762306a36Sopenharmony_ci		seq_puts(s, "UNKNOWN\n");
66862306a36Sopenharmony_ci	else if (!p->detected_panel)
66962306a36Sopenharmony_ci		seq_puts(s, "HARDCODED\n");
67062306a36Sopenharmony_ci	else
67162306a36Sopenharmony_ci		seq_printf(s, "%s\n", p->detected_panel->name);
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	return 0;
67462306a36Sopenharmony_ci}
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(detected_panel);
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_cistatic void panel_edp_debugfs_init(struct drm_panel *panel, struct dentry *root)
67962306a36Sopenharmony_ci{
68062306a36Sopenharmony_ci	debugfs_create_file("detected_panel", 0600, root, panel, &detected_panel_fops);
68162306a36Sopenharmony_ci}
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_cistatic const struct drm_panel_funcs panel_edp_funcs = {
68462306a36Sopenharmony_ci	.disable = panel_edp_disable,
68562306a36Sopenharmony_ci	.unprepare = panel_edp_unprepare,
68662306a36Sopenharmony_ci	.prepare = panel_edp_prepare,
68762306a36Sopenharmony_ci	.enable = panel_edp_enable,
68862306a36Sopenharmony_ci	.get_modes = panel_edp_get_modes,
68962306a36Sopenharmony_ci	.get_orientation = panel_edp_get_orientation,
69062306a36Sopenharmony_ci	.get_timings = panel_edp_get_timings,
69162306a36Sopenharmony_ci	.debugfs_init = panel_edp_debugfs_init,
69262306a36Sopenharmony_ci};
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci#define PANEL_EDP_BOUNDS_CHECK(to_check, bounds, field) \
69562306a36Sopenharmony_ci	(to_check->field.typ >= bounds->field.min && \
69662306a36Sopenharmony_ci	 to_check->field.typ <= bounds->field.max)
69762306a36Sopenharmony_cistatic void panel_edp_parse_panel_timing_node(struct device *dev,
69862306a36Sopenharmony_ci					      struct panel_edp *panel,
69962306a36Sopenharmony_ci					      const struct display_timing *ot)
70062306a36Sopenharmony_ci{
70162306a36Sopenharmony_ci	const struct panel_desc *desc = panel->desc;
70262306a36Sopenharmony_ci	struct videomode vm;
70362306a36Sopenharmony_ci	unsigned int i;
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	if (WARN_ON(desc->num_modes)) {
70662306a36Sopenharmony_ci		dev_err(dev, "Reject override mode: panel has a fixed mode\n");
70762306a36Sopenharmony_ci		return;
70862306a36Sopenharmony_ci	}
70962306a36Sopenharmony_ci	if (WARN_ON(!desc->num_timings)) {
71062306a36Sopenharmony_ci		dev_err(dev, "Reject override mode: no timings specified\n");
71162306a36Sopenharmony_ci		return;
71262306a36Sopenharmony_ci	}
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	for (i = 0; i < panel->desc->num_timings; i++) {
71562306a36Sopenharmony_ci		const struct display_timing *dt = &panel->desc->timings[i];
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci		if (!PANEL_EDP_BOUNDS_CHECK(ot, dt, hactive) ||
71862306a36Sopenharmony_ci		    !PANEL_EDP_BOUNDS_CHECK(ot, dt, hfront_porch) ||
71962306a36Sopenharmony_ci		    !PANEL_EDP_BOUNDS_CHECK(ot, dt, hback_porch) ||
72062306a36Sopenharmony_ci		    !PANEL_EDP_BOUNDS_CHECK(ot, dt, hsync_len) ||
72162306a36Sopenharmony_ci		    !PANEL_EDP_BOUNDS_CHECK(ot, dt, vactive) ||
72262306a36Sopenharmony_ci		    !PANEL_EDP_BOUNDS_CHECK(ot, dt, vfront_porch) ||
72362306a36Sopenharmony_ci		    !PANEL_EDP_BOUNDS_CHECK(ot, dt, vback_porch) ||
72462306a36Sopenharmony_ci		    !PANEL_EDP_BOUNDS_CHECK(ot, dt, vsync_len))
72562306a36Sopenharmony_ci			continue;
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci		if (ot->flags != dt->flags)
72862306a36Sopenharmony_ci			continue;
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci		videomode_from_timing(ot, &vm);
73162306a36Sopenharmony_ci		drm_display_mode_from_videomode(&vm, &panel->override_mode);
73262306a36Sopenharmony_ci		panel->override_mode.type |= DRM_MODE_TYPE_DRIVER |
73362306a36Sopenharmony_ci					     DRM_MODE_TYPE_PREFERRED;
73462306a36Sopenharmony_ci		break;
73562306a36Sopenharmony_ci	}
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	if (WARN_ON(!panel->override_mode.type))
73862306a36Sopenharmony_ci		dev_err(dev, "Reject override mode: No display_timing found\n");
73962306a36Sopenharmony_ci}
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_cistatic const struct edp_panel_entry *find_edp_panel(u32 panel_id);
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_cistatic int generic_edp_panel_probe(struct device *dev, struct panel_edp *panel)
74462306a36Sopenharmony_ci{
74562306a36Sopenharmony_ci	struct panel_desc *desc;
74662306a36Sopenharmony_ci	u32 panel_id;
74762306a36Sopenharmony_ci	char vend[4];
74862306a36Sopenharmony_ci	u16 product_id;
74962306a36Sopenharmony_ci	u32 reliable_ms = 0;
75062306a36Sopenharmony_ci	u32 absent_ms = 0;
75162306a36Sopenharmony_ci	int ret;
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
75462306a36Sopenharmony_ci	if (!desc)
75562306a36Sopenharmony_ci		return -ENOMEM;
75662306a36Sopenharmony_ci	panel->desc = desc;
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	/*
75962306a36Sopenharmony_ci	 * Read the dts properties for the initial probe. These are used by
76062306a36Sopenharmony_ci	 * the runtime resume code which will get called by the
76162306a36Sopenharmony_ci	 * pm_runtime_get_sync() call below.
76262306a36Sopenharmony_ci	 */
76362306a36Sopenharmony_ci	of_property_read_u32(dev->of_node, "hpd-reliable-delay-ms", &reliable_ms);
76462306a36Sopenharmony_ci	desc->delay.hpd_reliable = reliable_ms;
76562306a36Sopenharmony_ci	of_property_read_u32(dev->of_node, "hpd-absent-delay-ms", &absent_ms);
76662306a36Sopenharmony_ci	desc->delay.hpd_absent = absent_ms;
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	/* Power the panel on so we can read the EDID */
76962306a36Sopenharmony_ci	ret = pm_runtime_get_sync(dev);
77062306a36Sopenharmony_ci	if (ret < 0) {
77162306a36Sopenharmony_ci		dev_err(dev, "Couldn't power on panel to read EDID: %d\n", ret);
77262306a36Sopenharmony_ci		goto exit;
77362306a36Sopenharmony_ci	}
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	panel_id = drm_edid_get_panel_id(panel->ddc);
77662306a36Sopenharmony_ci	if (!panel_id) {
77762306a36Sopenharmony_ci		dev_err(dev, "Couldn't identify panel via EDID\n");
77862306a36Sopenharmony_ci		ret = -EIO;
77962306a36Sopenharmony_ci		goto exit;
78062306a36Sopenharmony_ci	}
78162306a36Sopenharmony_ci	drm_edid_decode_panel_id(panel_id, vend, &product_id);
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	panel->detected_panel = find_edp_panel(panel_id);
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	/*
78662306a36Sopenharmony_ci	 * We're using non-optimized timings and want it really obvious that
78762306a36Sopenharmony_ci	 * someone needs to add an entry to the table, so we'll do a WARN_ON
78862306a36Sopenharmony_ci	 * splat.
78962306a36Sopenharmony_ci	 */
79062306a36Sopenharmony_ci	if (WARN_ON(!panel->detected_panel)) {
79162306a36Sopenharmony_ci		dev_warn(dev,
79262306a36Sopenharmony_ci			 "Unknown panel %s %#06x, using conservative timings\n",
79362306a36Sopenharmony_ci			 vend, product_id);
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci		/*
79662306a36Sopenharmony_ci		 * It's highly likely that the panel will work if we use very
79762306a36Sopenharmony_ci		 * conservative timings, so let's do that. We already know that
79862306a36Sopenharmony_ci		 * the HPD-related delays must have worked since we got this
79962306a36Sopenharmony_ci		 * far, so we really just need the "unprepare" / "enable"
80062306a36Sopenharmony_ci		 * delays. We don't need "prepare_to_enable" since that
80162306a36Sopenharmony_ci		 * overlaps the "enable" delay anyway.
80262306a36Sopenharmony_ci		 *
80362306a36Sopenharmony_ci		 * Nearly all panels have a "unprepare" delay of 500 ms though
80462306a36Sopenharmony_ci		 * there are a few with 1000. Let's stick 2000 in just to be
80562306a36Sopenharmony_ci		 * super conservative.
80662306a36Sopenharmony_ci		 *
80762306a36Sopenharmony_ci		 * An "enable" delay of 80 ms seems the most common, but we'll
80862306a36Sopenharmony_ci		 * throw in 200 ms to be safe.
80962306a36Sopenharmony_ci		 */
81062306a36Sopenharmony_ci		desc->delay.unprepare = 2000;
81162306a36Sopenharmony_ci		desc->delay.enable = 200;
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci		panel->detected_panel = ERR_PTR(-EINVAL);
81462306a36Sopenharmony_ci	} else {
81562306a36Sopenharmony_ci		dev_info(dev, "Detected %s %s (%#06x)\n",
81662306a36Sopenharmony_ci			 vend, panel->detected_panel->name, product_id);
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci		/* Update the delay; everything else comes from EDID */
81962306a36Sopenharmony_ci		desc->delay = *panel->detected_panel->delay;
82062306a36Sopenharmony_ci	}
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci	ret = 0;
82362306a36Sopenharmony_ciexit:
82462306a36Sopenharmony_ci	pm_runtime_mark_last_busy(dev);
82562306a36Sopenharmony_ci	pm_runtime_put_autosuspend(dev);
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	return ret;
82862306a36Sopenharmony_ci}
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_cistatic int panel_edp_probe(struct device *dev, const struct panel_desc *desc,
83162306a36Sopenharmony_ci			   struct drm_dp_aux *aux)
83262306a36Sopenharmony_ci{
83362306a36Sopenharmony_ci	struct panel_edp *panel;
83462306a36Sopenharmony_ci	struct display_timing dt;
83562306a36Sopenharmony_ci	struct device_node *ddc;
83662306a36Sopenharmony_ci	int err;
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL);
83962306a36Sopenharmony_ci	if (!panel)
84062306a36Sopenharmony_ci		return -ENOMEM;
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	panel->enabled = false;
84362306a36Sopenharmony_ci	panel->prepared_time = 0;
84462306a36Sopenharmony_ci	panel->desc = desc;
84562306a36Sopenharmony_ci	panel->aux = aux;
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	panel->no_hpd = of_property_read_bool(dev->of_node, "no-hpd");
84862306a36Sopenharmony_ci	if (!panel->no_hpd) {
84962306a36Sopenharmony_ci		err = panel_edp_get_hpd_gpio(dev, panel);
85062306a36Sopenharmony_ci		if (err)
85162306a36Sopenharmony_ci			return err;
85262306a36Sopenharmony_ci	}
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci	panel->supply = devm_regulator_get(dev, "power");
85562306a36Sopenharmony_ci	if (IS_ERR(panel->supply))
85662306a36Sopenharmony_ci		return PTR_ERR(panel->supply);
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	panel->enable_gpio = devm_gpiod_get_optional(dev, "enable",
85962306a36Sopenharmony_ci						     GPIOD_OUT_LOW);
86062306a36Sopenharmony_ci	if (IS_ERR(panel->enable_gpio))
86162306a36Sopenharmony_ci		return dev_err_probe(dev, PTR_ERR(panel->enable_gpio),
86262306a36Sopenharmony_ci				     "failed to request GPIO\n");
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	err = of_drm_get_panel_orientation(dev->of_node, &panel->orientation);
86562306a36Sopenharmony_ci	if (err) {
86662306a36Sopenharmony_ci		dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, err);
86762306a36Sopenharmony_ci		return err;
86862306a36Sopenharmony_ci	}
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	ddc = of_parse_phandle(dev->of_node, "ddc-i2c-bus", 0);
87162306a36Sopenharmony_ci	if (ddc) {
87262306a36Sopenharmony_ci		panel->ddc = of_find_i2c_adapter_by_node(ddc);
87362306a36Sopenharmony_ci		of_node_put(ddc);
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci		if (!panel->ddc)
87662306a36Sopenharmony_ci			return -EPROBE_DEFER;
87762306a36Sopenharmony_ci	} else if (aux) {
87862306a36Sopenharmony_ci		panel->ddc = &aux->ddc;
87962306a36Sopenharmony_ci	}
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci	if (!of_get_display_timing(dev->of_node, "panel-timing", &dt))
88262306a36Sopenharmony_ci		panel_edp_parse_panel_timing_node(dev, panel, &dt);
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci	dev_set_drvdata(dev, panel);
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	drm_panel_init(&panel->base, dev, &panel_edp_funcs, DRM_MODE_CONNECTOR_eDP);
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	err = drm_panel_of_backlight(&panel->base);
88962306a36Sopenharmony_ci	if (err)
89062306a36Sopenharmony_ci		goto err_finished_ddc_init;
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	/*
89362306a36Sopenharmony_ci	 * We use runtime PM for prepare / unprepare since those power the panel
89462306a36Sopenharmony_ci	 * on and off and those can be very slow operations. This is important
89562306a36Sopenharmony_ci	 * to optimize powering the panel on briefly to read the EDID before
89662306a36Sopenharmony_ci	 * fully enabling the panel.
89762306a36Sopenharmony_ci	 */
89862306a36Sopenharmony_ci	pm_runtime_enable(dev);
89962306a36Sopenharmony_ci	pm_runtime_set_autosuspend_delay(dev, 1000);
90062306a36Sopenharmony_ci	pm_runtime_use_autosuspend(dev);
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	if (of_device_is_compatible(dev->of_node, "edp-panel")) {
90362306a36Sopenharmony_ci		err = generic_edp_panel_probe(dev, panel);
90462306a36Sopenharmony_ci		if (err) {
90562306a36Sopenharmony_ci			dev_err_probe(dev, err,
90662306a36Sopenharmony_ci				      "Couldn't detect panel nor find a fallback\n");
90762306a36Sopenharmony_ci			goto err_finished_pm_runtime;
90862306a36Sopenharmony_ci		}
90962306a36Sopenharmony_ci		/* generic_edp_panel_probe() replaces desc in the panel */
91062306a36Sopenharmony_ci		desc = panel->desc;
91162306a36Sopenharmony_ci	} else if (desc->bpc != 6 && desc->bpc != 8 && desc->bpc != 10) {
91262306a36Sopenharmony_ci		dev_warn(dev, "Expected bpc in {6,8,10} but got: %u\n", desc->bpc);
91362306a36Sopenharmony_ci	}
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	if (!panel->base.backlight && panel->aux) {
91662306a36Sopenharmony_ci		pm_runtime_get_sync(dev);
91762306a36Sopenharmony_ci		err = drm_panel_dp_aux_backlight(&panel->base, panel->aux);
91862306a36Sopenharmony_ci		pm_runtime_mark_last_busy(dev);
91962306a36Sopenharmony_ci		pm_runtime_put_autosuspend(dev);
92062306a36Sopenharmony_ci		if (err)
92162306a36Sopenharmony_ci			goto err_finished_pm_runtime;
92262306a36Sopenharmony_ci	}
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci	drm_panel_add(&panel->base);
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	return 0;
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_cierr_finished_pm_runtime:
92962306a36Sopenharmony_ci	pm_runtime_dont_use_autosuspend(dev);
93062306a36Sopenharmony_ci	pm_runtime_disable(dev);
93162306a36Sopenharmony_cierr_finished_ddc_init:
93262306a36Sopenharmony_ci	if (panel->ddc && (!panel->aux || panel->ddc != &panel->aux->ddc))
93362306a36Sopenharmony_ci		put_device(&panel->ddc->dev);
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	return err;
93662306a36Sopenharmony_ci}
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_cistatic void panel_edp_remove(struct device *dev)
93962306a36Sopenharmony_ci{
94062306a36Sopenharmony_ci	struct panel_edp *panel = dev_get_drvdata(dev);
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	drm_panel_remove(&panel->base);
94362306a36Sopenharmony_ci	drm_panel_disable(&panel->base);
94462306a36Sopenharmony_ci	drm_panel_unprepare(&panel->base);
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	pm_runtime_dont_use_autosuspend(dev);
94762306a36Sopenharmony_ci	pm_runtime_disable(dev);
94862306a36Sopenharmony_ci	if (panel->ddc && (!panel->aux || panel->ddc != &panel->aux->ddc))
94962306a36Sopenharmony_ci		put_device(&panel->ddc->dev);
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	kfree(panel->edid);
95262306a36Sopenharmony_ci	panel->edid = NULL;
95362306a36Sopenharmony_ci}
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_cistatic void panel_edp_shutdown(struct device *dev)
95662306a36Sopenharmony_ci{
95762306a36Sopenharmony_ci	struct panel_edp *panel = dev_get_drvdata(dev);
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci	drm_panel_disable(&panel->base);
96062306a36Sopenharmony_ci	drm_panel_unprepare(&panel->base);
96162306a36Sopenharmony_ci}
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_cistatic const struct display_timing auo_b101ean01_timing = {
96462306a36Sopenharmony_ci	.pixelclock = { 65300000, 72500000, 75000000 },
96562306a36Sopenharmony_ci	.hactive = { 1280, 1280, 1280 },
96662306a36Sopenharmony_ci	.hfront_porch = { 18, 119, 119 },
96762306a36Sopenharmony_ci	.hback_porch = { 21, 21, 21 },
96862306a36Sopenharmony_ci	.hsync_len = { 32, 32, 32 },
96962306a36Sopenharmony_ci	.vactive = { 800, 800, 800 },
97062306a36Sopenharmony_ci	.vfront_porch = { 4, 4, 4 },
97162306a36Sopenharmony_ci	.vback_porch = { 8, 8, 8 },
97262306a36Sopenharmony_ci	.vsync_len = { 18, 20, 20 },
97362306a36Sopenharmony_ci};
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_cistatic const struct panel_desc auo_b101ean01 = {
97662306a36Sopenharmony_ci	.timings = &auo_b101ean01_timing,
97762306a36Sopenharmony_ci	.num_timings = 1,
97862306a36Sopenharmony_ci	.bpc = 6,
97962306a36Sopenharmony_ci	.size = {
98062306a36Sopenharmony_ci		.width = 217,
98162306a36Sopenharmony_ci		.height = 136,
98262306a36Sopenharmony_ci	},
98362306a36Sopenharmony_ci};
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_cistatic const struct drm_display_mode auo_b116xak01_mode = {
98662306a36Sopenharmony_ci	.clock = 69300,
98762306a36Sopenharmony_ci	.hdisplay = 1366,
98862306a36Sopenharmony_ci	.hsync_start = 1366 + 48,
98962306a36Sopenharmony_ci	.hsync_end = 1366 + 48 + 32,
99062306a36Sopenharmony_ci	.htotal = 1366 + 48 + 32 + 10,
99162306a36Sopenharmony_ci	.vdisplay = 768,
99262306a36Sopenharmony_ci	.vsync_start = 768 + 4,
99362306a36Sopenharmony_ci	.vsync_end = 768 + 4 + 6,
99462306a36Sopenharmony_ci	.vtotal = 768 + 4 + 6 + 15,
99562306a36Sopenharmony_ci	.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
99662306a36Sopenharmony_ci};
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_cistatic const struct panel_desc auo_b116xak01 = {
99962306a36Sopenharmony_ci	.modes = &auo_b116xak01_mode,
100062306a36Sopenharmony_ci	.num_modes = 1,
100162306a36Sopenharmony_ci	.bpc = 6,
100262306a36Sopenharmony_ci	.size = {
100362306a36Sopenharmony_ci		.width = 256,
100462306a36Sopenharmony_ci		.height = 144,
100562306a36Sopenharmony_ci	},
100662306a36Sopenharmony_ci	.delay = {
100762306a36Sopenharmony_ci		.hpd_absent = 200,
100862306a36Sopenharmony_ci		.unprepare = 500,
100962306a36Sopenharmony_ci		.enable = 50,
101062306a36Sopenharmony_ci	},
101162306a36Sopenharmony_ci};
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_cistatic const struct drm_display_mode auo_b133han05_mode = {
101462306a36Sopenharmony_ci	.clock = 142600,
101562306a36Sopenharmony_ci	.hdisplay = 1920,
101662306a36Sopenharmony_ci	.hsync_start = 1920 + 58,
101762306a36Sopenharmony_ci	.hsync_end = 1920 + 58 + 42,
101862306a36Sopenharmony_ci	.htotal = 1920 + 58 + 42 + 60,
101962306a36Sopenharmony_ci	.vdisplay = 1080,
102062306a36Sopenharmony_ci	.vsync_start = 1080 + 3,
102162306a36Sopenharmony_ci	.vsync_end = 1080 + 3 + 5,
102262306a36Sopenharmony_ci	.vtotal = 1080 + 3 + 5 + 54,
102362306a36Sopenharmony_ci};
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_cistatic const struct panel_desc auo_b133han05 = {
102662306a36Sopenharmony_ci	.modes = &auo_b133han05_mode,
102762306a36Sopenharmony_ci	.num_modes = 1,
102862306a36Sopenharmony_ci	.bpc = 8,
102962306a36Sopenharmony_ci	.size = {
103062306a36Sopenharmony_ci		.width = 293,
103162306a36Sopenharmony_ci		.height = 165,
103262306a36Sopenharmony_ci	},
103362306a36Sopenharmony_ci	.delay = {
103462306a36Sopenharmony_ci		.hpd_reliable = 100,
103562306a36Sopenharmony_ci		.enable = 20,
103662306a36Sopenharmony_ci		.unprepare = 50,
103762306a36Sopenharmony_ci	},
103862306a36Sopenharmony_ci};
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_cistatic const struct drm_display_mode auo_b133htn01_mode = {
104162306a36Sopenharmony_ci	.clock = 150660,
104262306a36Sopenharmony_ci	.hdisplay = 1920,
104362306a36Sopenharmony_ci	.hsync_start = 1920 + 172,
104462306a36Sopenharmony_ci	.hsync_end = 1920 + 172 + 80,
104562306a36Sopenharmony_ci	.htotal = 1920 + 172 + 80 + 60,
104662306a36Sopenharmony_ci	.vdisplay = 1080,
104762306a36Sopenharmony_ci	.vsync_start = 1080 + 25,
104862306a36Sopenharmony_ci	.vsync_end = 1080 + 25 + 10,
104962306a36Sopenharmony_ci	.vtotal = 1080 + 25 + 10 + 10,
105062306a36Sopenharmony_ci};
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_cistatic const struct panel_desc auo_b133htn01 = {
105362306a36Sopenharmony_ci	.modes = &auo_b133htn01_mode,
105462306a36Sopenharmony_ci	.num_modes = 1,
105562306a36Sopenharmony_ci	.bpc = 6,
105662306a36Sopenharmony_ci	.size = {
105762306a36Sopenharmony_ci		.width = 293,
105862306a36Sopenharmony_ci		.height = 165,
105962306a36Sopenharmony_ci	},
106062306a36Sopenharmony_ci	.delay = {
106162306a36Sopenharmony_ci		.hpd_reliable = 105,
106262306a36Sopenharmony_ci		.enable = 20,
106362306a36Sopenharmony_ci		.unprepare = 50,
106462306a36Sopenharmony_ci	},
106562306a36Sopenharmony_ci};
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_cistatic const struct drm_display_mode auo_b133xtn01_mode = {
106862306a36Sopenharmony_ci	.clock = 69500,
106962306a36Sopenharmony_ci	.hdisplay = 1366,
107062306a36Sopenharmony_ci	.hsync_start = 1366 + 48,
107162306a36Sopenharmony_ci	.hsync_end = 1366 + 48 + 32,
107262306a36Sopenharmony_ci	.htotal = 1366 + 48 + 32 + 20,
107362306a36Sopenharmony_ci	.vdisplay = 768,
107462306a36Sopenharmony_ci	.vsync_start = 768 + 3,
107562306a36Sopenharmony_ci	.vsync_end = 768 + 3 + 6,
107662306a36Sopenharmony_ci	.vtotal = 768 + 3 + 6 + 13,
107762306a36Sopenharmony_ci};
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_cistatic const struct panel_desc auo_b133xtn01 = {
108062306a36Sopenharmony_ci	.modes = &auo_b133xtn01_mode,
108162306a36Sopenharmony_ci	.num_modes = 1,
108262306a36Sopenharmony_ci	.bpc = 6,
108362306a36Sopenharmony_ci	.size = {
108462306a36Sopenharmony_ci		.width = 293,
108562306a36Sopenharmony_ci		.height = 165,
108662306a36Sopenharmony_ci	},
108762306a36Sopenharmony_ci};
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_cistatic const struct drm_display_mode auo_b140han06_mode = {
109062306a36Sopenharmony_ci	.clock = 141000,
109162306a36Sopenharmony_ci	.hdisplay = 1920,
109262306a36Sopenharmony_ci	.hsync_start = 1920 + 16,
109362306a36Sopenharmony_ci	.hsync_end = 1920 + 16 + 16,
109462306a36Sopenharmony_ci	.htotal = 1920 + 16 + 16 + 152,
109562306a36Sopenharmony_ci	.vdisplay = 1080,
109662306a36Sopenharmony_ci	.vsync_start = 1080 + 3,
109762306a36Sopenharmony_ci	.vsync_end = 1080 + 3 + 14,
109862306a36Sopenharmony_ci	.vtotal = 1080 + 3 + 14 + 19,
109962306a36Sopenharmony_ci};
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_cistatic const struct panel_desc auo_b140han06 = {
110262306a36Sopenharmony_ci	.modes = &auo_b140han06_mode,
110362306a36Sopenharmony_ci	.num_modes = 1,
110462306a36Sopenharmony_ci	.bpc = 8,
110562306a36Sopenharmony_ci	.size = {
110662306a36Sopenharmony_ci		.width = 309,
110762306a36Sopenharmony_ci		.height = 174,
110862306a36Sopenharmony_ci	},
110962306a36Sopenharmony_ci	.delay = {
111062306a36Sopenharmony_ci		.hpd_reliable = 100,
111162306a36Sopenharmony_ci		.enable = 20,
111262306a36Sopenharmony_ci		.unprepare = 50,
111362306a36Sopenharmony_ci	},
111462306a36Sopenharmony_ci};
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_cistatic const struct drm_display_mode boe_nv101wxmn51_modes[] = {
111762306a36Sopenharmony_ci	{
111862306a36Sopenharmony_ci		.clock = 71900,
111962306a36Sopenharmony_ci		.hdisplay = 1280,
112062306a36Sopenharmony_ci		.hsync_start = 1280 + 48,
112162306a36Sopenharmony_ci		.hsync_end = 1280 + 48 + 32,
112262306a36Sopenharmony_ci		.htotal = 1280 + 48 + 32 + 80,
112362306a36Sopenharmony_ci		.vdisplay = 800,
112462306a36Sopenharmony_ci		.vsync_start = 800 + 3,
112562306a36Sopenharmony_ci		.vsync_end = 800 + 3 + 5,
112662306a36Sopenharmony_ci		.vtotal = 800 + 3 + 5 + 24,
112762306a36Sopenharmony_ci	},
112862306a36Sopenharmony_ci	{
112962306a36Sopenharmony_ci		.clock = 57500,
113062306a36Sopenharmony_ci		.hdisplay = 1280,
113162306a36Sopenharmony_ci		.hsync_start = 1280 + 48,
113262306a36Sopenharmony_ci		.hsync_end = 1280 + 48 + 32,
113362306a36Sopenharmony_ci		.htotal = 1280 + 48 + 32 + 80,
113462306a36Sopenharmony_ci		.vdisplay = 800,
113562306a36Sopenharmony_ci		.vsync_start = 800 + 3,
113662306a36Sopenharmony_ci		.vsync_end = 800 + 3 + 5,
113762306a36Sopenharmony_ci		.vtotal = 800 + 3 + 5 + 24,
113862306a36Sopenharmony_ci	},
113962306a36Sopenharmony_ci};
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_cistatic const struct panel_desc boe_nv101wxmn51 = {
114262306a36Sopenharmony_ci	.modes = boe_nv101wxmn51_modes,
114362306a36Sopenharmony_ci	.num_modes = ARRAY_SIZE(boe_nv101wxmn51_modes),
114462306a36Sopenharmony_ci	.bpc = 8,
114562306a36Sopenharmony_ci	.size = {
114662306a36Sopenharmony_ci		.width = 217,
114762306a36Sopenharmony_ci		.height = 136,
114862306a36Sopenharmony_ci	},
114962306a36Sopenharmony_ci	.delay = {
115062306a36Sopenharmony_ci		/* TODO: should be hpd-absent and no-hpd should be set? */
115162306a36Sopenharmony_ci		.hpd_reliable = 210,
115262306a36Sopenharmony_ci		.enable = 50,
115362306a36Sopenharmony_ci		.unprepare = 160,
115462306a36Sopenharmony_ci	},
115562306a36Sopenharmony_ci};
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_cistatic const struct drm_display_mode boe_nv110wtm_n61_modes[] = {
115862306a36Sopenharmony_ci	{
115962306a36Sopenharmony_ci		.clock = 207800,
116062306a36Sopenharmony_ci		.hdisplay = 2160,
116162306a36Sopenharmony_ci		.hsync_start = 2160 + 48,
116262306a36Sopenharmony_ci		.hsync_end = 2160 + 48 + 32,
116362306a36Sopenharmony_ci		.htotal = 2160 + 48 + 32 + 100,
116462306a36Sopenharmony_ci		.vdisplay = 1440,
116562306a36Sopenharmony_ci		.vsync_start = 1440 + 3,
116662306a36Sopenharmony_ci		.vsync_end = 1440 + 3 + 6,
116762306a36Sopenharmony_ci		.vtotal = 1440 + 3 + 6 + 31,
116862306a36Sopenharmony_ci		.flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC,
116962306a36Sopenharmony_ci	},
117062306a36Sopenharmony_ci	{
117162306a36Sopenharmony_ci		.clock = 138500,
117262306a36Sopenharmony_ci		.hdisplay = 2160,
117362306a36Sopenharmony_ci		.hsync_start = 2160 + 48,
117462306a36Sopenharmony_ci		.hsync_end = 2160 + 48 + 32,
117562306a36Sopenharmony_ci		.htotal = 2160 + 48 + 32 + 100,
117662306a36Sopenharmony_ci		.vdisplay = 1440,
117762306a36Sopenharmony_ci		.vsync_start = 1440 + 3,
117862306a36Sopenharmony_ci		.vsync_end = 1440 + 3 + 6,
117962306a36Sopenharmony_ci		.vtotal = 1440 + 3 + 6 + 31,
118062306a36Sopenharmony_ci		.flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC,
118162306a36Sopenharmony_ci	},
118262306a36Sopenharmony_ci};
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_cistatic const struct panel_desc boe_nv110wtm_n61 = {
118562306a36Sopenharmony_ci	.modes = boe_nv110wtm_n61_modes,
118662306a36Sopenharmony_ci	.num_modes = ARRAY_SIZE(boe_nv110wtm_n61_modes),
118762306a36Sopenharmony_ci	.bpc = 8,
118862306a36Sopenharmony_ci	.size = {
118962306a36Sopenharmony_ci		.width = 233,
119062306a36Sopenharmony_ci		.height = 155,
119162306a36Sopenharmony_ci	},
119262306a36Sopenharmony_ci	.delay = {
119362306a36Sopenharmony_ci		.hpd_absent = 200,
119462306a36Sopenharmony_ci		.prepare_to_enable = 80,
119562306a36Sopenharmony_ci		.enable = 50,
119662306a36Sopenharmony_ci		.unprepare = 500,
119762306a36Sopenharmony_ci	},
119862306a36Sopenharmony_ci};
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci/* Also used for boe_nv133fhm_n62 */
120162306a36Sopenharmony_cistatic const struct drm_display_mode boe_nv133fhm_n61_modes = {
120262306a36Sopenharmony_ci	.clock = 147840,
120362306a36Sopenharmony_ci	.hdisplay = 1920,
120462306a36Sopenharmony_ci	.hsync_start = 1920 + 48,
120562306a36Sopenharmony_ci	.hsync_end = 1920 + 48 + 32,
120662306a36Sopenharmony_ci	.htotal = 1920 + 48 + 32 + 200,
120762306a36Sopenharmony_ci	.vdisplay = 1080,
120862306a36Sopenharmony_ci	.vsync_start = 1080 + 3,
120962306a36Sopenharmony_ci	.vsync_end = 1080 + 3 + 6,
121062306a36Sopenharmony_ci	.vtotal = 1080 + 3 + 6 + 31,
121162306a36Sopenharmony_ci	.flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC,
121262306a36Sopenharmony_ci};
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci/* Also used for boe_nv133fhm_n62 */
121562306a36Sopenharmony_cistatic const struct panel_desc boe_nv133fhm_n61 = {
121662306a36Sopenharmony_ci	.modes = &boe_nv133fhm_n61_modes,
121762306a36Sopenharmony_ci	.num_modes = 1,
121862306a36Sopenharmony_ci	.bpc = 6,
121962306a36Sopenharmony_ci	.size = {
122062306a36Sopenharmony_ci		.width = 294,
122162306a36Sopenharmony_ci		.height = 165,
122262306a36Sopenharmony_ci	},
122362306a36Sopenharmony_ci	.delay = {
122462306a36Sopenharmony_ci		/*
122562306a36Sopenharmony_ci		 * When power is first given to the panel there's a short
122662306a36Sopenharmony_ci		 * spike on the HPD line.  It was explained that this spike
122762306a36Sopenharmony_ci		 * was until the TCON data download was complete.  On
122862306a36Sopenharmony_ci		 * one system this was measured at 8 ms.  We'll put 15 ms
122962306a36Sopenharmony_ci		 * in the prepare delay just to be safe.  That means:
123062306a36Sopenharmony_ci		 * - If HPD isn't hooked up you still have 200 ms delay.
123162306a36Sopenharmony_ci		 * - If HPD is hooked up we won't try to look at it for the
123262306a36Sopenharmony_ci		 *   first 15 ms.
123362306a36Sopenharmony_ci		 */
123462306a36Sopenharmony_ci		.hpd_reliable = 15,
123562306a36Sopenharmony_ci		.hpd_absent = 200,
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci		.unprepare = 500,
123862306a36Sopenharmony_ci	},
123962306a36Sopenharmony_ci};
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_cistatic const struct drm_display_mode boe_nv140fhmn49_modes[] = {
124262306a36Sopenharmony_ci	{
124362306a36Sopenharmony_ci		.clock = 148500,
124462306a36Sopenharmony_ci		.hdisplay = 1920,
124562306a36Sopenharmony_ci		.hsync_start = 1920 + 48,
124662306a36Sopenharmony_ci		.hsync_end = 1920 + 48 + 32,
124762306a36Sopenharmony_ci		.htotal = 2200,
124862306a36Sopenharmony_ci		.vdisplay = 1080,
124962306a36Sopenharmony_ci		.vsync_start = 1080 + 3,
125062306a36Sopenharmony_ci		.vsync_end = 1080 + 3 + 5,
125162306a36Sopenharmony_ci		.vtotal = 1125,
125262306a36Sopenharmony_ci	},
125362306a36Sopenharmony_ci};
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_cistatic const struct panel_desc boe_nv140fhmn49 = {
125662306a36Sopenharmony_ci	.modes = boe_nv140fhmn49_modes,
125762306a36Sopenharmony_ci	.num_modes = ARRAY_SIZE(boe_nv140fhmn49_modes),
125862306a36Sopenharmony_ci	.bpc = 6,
125962306a36Sopenharmony_ci	.size = {
126062306a36Sopenharmony_ci		.width = 309,
126162306a36Sopenharmony_ci		.height = 174,
126262306a36Sopenharmony_ci	},
126362306a36Sopenharmony_ci	.delay = {
126462306a36Sopenharmony_ci		/* TODO: should be hpd-absent and no-hpd should be set? */
126562306a36Sopenharmony_ci		.hpd_reliable = 210,
126662306a36Sopenharmony_ci		.enable = 50,
126762306a36Sopenharmony_ci		.unprepare = 160,
126862306a36Sopenharmony_ci	},
126962306a36Sopenharmony_ci};
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_cistatic const struct drm_display_mode innolux_n116bca_ea1_mode = {
127262306a36Sopenharmony_ci	.clock = 76420,
127362306a36Sopenharmony_ci	.hdisplay = 1366,
127462306a36Sopenharmony_ci	.hsync_start = 1366 + 136,
127562306a36Sopenharmony_ci	.hsync_end = 1366 + 136 + 30,
127662306a36Sopenharmony_ci	.htotal = 1366 + 136 + 30 + 60,
127762306a36Sopenharmony_ci	.vdisplay = 768,
127862306a36Sopenharmony_ci	.vsync_start = 768 + 8,
127962306a36Sopenharmony_ci	.vsync_end = 768 + 8 + 12,
128062306a36Sopenharmony_ci	.vtotal = 768 + 8 + 12 + 12,
128162306a36Sopenharmony_ci	.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
128262306a36Sopenharmony_ci};
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_cistatic const struct panel_desc innolux_n116bca_ea1 = {
128562306a36Sopenharmony_ci	.modes = &innolux_n116bca_ea1_mode,
128662306a36Sopenharmony_ci	.num_modes = 1,
128762306a36Sopenharmony_ci	.bpc = 6,
128862306a36Sopenharmony_ci	.size = {
128962306a36Sopenharmony_ci		.width = 256,
129062306a36Sopenharmony_ci		.height = 144,
129162306a36Sopenharmony_ci	},
129262306a36Sopenharmony_ci	.delay = {
129362306a36Sopenharmony_ci		.hpd_absent = 200,
129462306a36Sopenharmony_ci		.enable = 80,
129562306a36Sopenharmony_ci		.disable = 50,
129662306a36Sopenharmony_ci		.unprepare = 500,
129762306a36Sopenharmony_ci	},
129862306a36Sopenharmony_ci};
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci/*
130162306a36Sopenharmony_ci * Datasheet specifies that at 60 Hz refresh rate:
130262306a36Sopenharmony_ci * - total horizontal time: { 1506, 1592, 1716 }
130362306a36Sopenharmony_ci * - total vertical time: { 788, 800, 868 }
130462306a36Sopenharmony_ci *
130562306a36Sopenharmony_ci * ...but doesn't go into exactly how that should be split into a front
130662306a36Sopenharmony_ci * porch, back porch, or sync length.  For now we'll leave a single setting
130762306a36Sopenharmony_ci * here which allows a bit of tweaking of the pixel clock at the expense of
130862306a36Sopenharmony_ci * refresh rate.
130962306a36Sopenharmony_ci */
131062306a36Sopenharmony_cistatic const struct display_timing innolux_n116bge_timing = {
131162306a36Sopenharmony_ci	.pixelclock = { 72600000, 76420000, 80240000 },
131262306a36Sopenharmony_ci	.hactive = { 1366, 1366, 1366 },
131362306a36Sopenharmony_ci	.hfront_porch = { 136, 136, 136 },
131462306a36Sopenharmony_ci	.hback_porch = { 60, 60, 60 },
131562306a36Sopenharmony_ci	.hsync_len = { 30, 30, 30 },
131662306a36Sopenharmony_ci	.vactive = { 768, 768, 768 },
131762306a36Sopenharmony_ci	.vfront_porch = { 8, 8, 8 },
131862306a36Sopenharmony_ci	.vback_porch = { 12, 12, 12 },
131962306a36Sopenharmony_ci	.vsync_len = { 12, 12, 12 },
132062306a36Sopenharmony_ci	.flags = DISPLAY_FLAGS_VSYNC_LOW | DISPLAY_FLAGS_HSYNC_LOW,
132162306a36Sopenharmony_ci};
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_cistatic const struct panel_desc innolux_n116bge = {
132462306a36Sopenharmony_ci	.timings = &innolux_n116bge_timing,
132562306a36Sopenharmony_ci	.num_timings = 1,
132662306a36Sopenharmony_ci	.bpc = 6,
132762306a36Sopenharmony_ci	.size = {
132862306a36Sopenharmony_ci		.width = 256,
132962306a36Sopenharmony_ci		.height = 144,
133062306a36Sopenharmony_ci	},
133162306a36Sopenharmony_ci};
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_cistatic const struct drm_display_mode innolux_n125hce_gn1_mode = {
133462306a36Sopenharmony_ci	.clock = 162000,
133562306a36Sopenharmony_ci	.hdisplay = 1920,
133662306a36Sopenharmony_ci	.hsync_start = 1920 + 40,
133762306a36Sopenharmony_ci	.hsync_end = 1920 + 40 + 40,
133862306a36Sopenharmony_ci	.htotal = 1920 + 40 + 40 + 80,
133962306a36Sopenharmony_ci	.vdisplay = 1080,
134062306a36Sopenharmony_ci	.vsync_start = 1080 + 4,
134162306a36Sopenharmony_ci	.vsync_end = 1080 + 4 + 4,
134262306a36Sopenharmony_ci	.vtotal = 1080 + 4 + 4 + 24,
134362306a36Sopenharmony_ci};
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_cistatic const struct panel_desc innolux_n125hce_gn1 = {
134662306a36Sopenharmony_ci	.modes = &innolux_n125hce_gn1_mode,
134762306a36Sopenharmony_ci	.num_modes = 1,
134862306a36Sopenharmony_ci	.bpc = 8,
134962306a36Sopenharmony_ci	.size = {
135062306a36Sopenharmony_ci		.width = 276,
135162306a36Sopenharmony_ci		.height = 155,
135262306a36Sopenharmony_ci	},
135362306a36Sopenharmony_ci};
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_cistatic const struct drm_display_mode innolux_p120zdg_bf1_mode = {
135662306a36Sopenharmony_ci	.clock = 206016,
135762306a36Sopenharmony_ci	.hdisplay = 2160,
135862306a36Sopenharmony_ci	.hsync_start = 2160 + 48,
135962306a36Sopenharmony_ci	.hsync_end = 2160 + 48 + 32,
136062306a36Sopenharmony_ci	.htotal = 2160 + 48 + 32 + 80,
136162306a36Sopenharmony_ci	.vdisplay = 1440,
136262306a36Sopenharmony_ci	.vsync_start = 1440 + 3,
136362306a36Sopenharmony_ci	.vsync_end = 1440 + 3 + 10,
136462306a36Sopenharmony_ci	.vtotal = 1440 + 3 + 10 + 27,
136562306a36Sopenharmony_ci	.flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC,
136662306a36Sopenharmony_ci};
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_cistatic const struct panel_desc innolux_p120zdg_bf1 = {
136962306a36Sopenharmony_ci	.modes = &innolux_p120zdg_bf1_mode,
137062306a36Sopenharmony_ci	.num_modes = 1,
137162306a36Sopenharmony_ci	.bpc = 8,
137262306a36Sopenharmony_ci	.size = {
137362306a36Sopenharmony_ci		.width = 254,
137462306a36Sopenharmony_ci		.height = 169,
137562306a36Sopenharmony_ci	},
137662306a36Sopenharmony_ci	.delay = {
137762306a36Sopenharmony_ci		.hpd_absent = 200,
137862306a36Sopenharmony_ci		.unprepare = 500,
137962306a36Sopenharmony_ci	},
138062306a36Sopenharmony_ci};
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_cistatic const struct drm_display_mode ivo_m133nwf4_r0_mode = {
138362306a36Sopenharmony_ci	.clock = 138778,
138462306a36Sopenharmony_ci	.hdisplay = 1920,
138562306a36Sopenharmony_ci	.hsync_start = 1920 + 24,
138662306a36Sopenharmony_ci	.hsync_end = 1920 + 24 + 48,
138762306a36Sopenharmony_ci	.htotal = 1920 + 24 + 48 + 88,
138862306a36Sopenharmony_ci	.vdisplay = 1080,
138962306a36Sopenharmony_ci	.vsync_start = 1080 + 3,
139062306a36Sopenharmony_ci	.vsync_end = 1080 + 3 + 12,
139162306a36Sopenharmony_ci	.vtotal = 1080 + 3 + 12 + 17,
139262306a36Sopenharmony_ci	.flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC,
139362306a36Sopenharmony_ci};
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_cistatic const struct panel_desc ivo_m133nwf4_r0 = {
139662306a36Sopenharmony_ci	.modes = &ivo_m133nwf4_r0_mode,
139762306a36Sopenharmony_ci	.num_modes = 1,
139862306a36Sopenharmony_ci	.bpc = 8,
139962306a36Sopenharmony_ci	.size = {
140062306a36Sopenharmony_ci		.width = 294,
140162306a36Sopenharmony_ci		.height = 165,
140262306a36Sopenharmony_ci	},
140362306a36Sopenharmony_ci	.delay = {
140462306a36Sopenharmony_ci		.hpd_absent = 200,
140562306a36Sopenharmony_ci		.unprepare = 500,
140662306a36Sopenharmony_ci	},
140762306a36Sopenharmony_ci};
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_cistatic const struct drm_display_mode kingdisplay_kd116n21_30nv_a010_mode = {
141062306a36Sopenharmony_ci	.clock = 81000,
141162306a36Sopenharmony_ci	.hdisplay = 1366,
141262306a36Sopenharmony_ci	.hsync_start = 1366 + 40,
141362306a36Sopenharmony_ci	.hsync_end = 1366 + 40 + 32,
141462306a36Sopenharmony_ci	.htotal = 1366 + 40 + 32 + 62,
141562306a36Sopenharmony_ci	.vdisplay = 768,
141662306a36Sopenharmony_ci	.vsync_start = 768 + 5,
141762306a36Sopenharmony_ci	.vsync_end = 768 + 5 + 5,
141862306a36Sopenharmony_ci	.vtotal = 768 + 5 + 5 + 122,
141962306a36Sopenharmony_ci	.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
142062306a36Sopenharmony_ci};
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_cistatic const struct panel_desc kingdisplay_kd116n21_30nv_a010 = {
142362306a36Sopenharmony_ci	.modes = &kingdisplay_kd116n21_30nv_a010_mode,
142462306a36Sopenharmony_ci	.num_modes = 1,
142562306a36Sopenharmony_ci	.bpc = 6,
142662306a36Sopenharmony_ci	.size = {
142762306a36Sopenharmony_ci		.width = 256,
142862306a36Sopenharmony_ci		.height = 144,
142962306a36Sopenharmony_ci	},
143062306a36Sopenharmony_ci	.delay = {
143162306a36Sopenharmony_ci		.hpd_absent = 200,
143262306a36Sopenharmony_ci	},
143362306a36Sopenharmony_ci};
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_cistatic const struct drm_display_mode lg_lp079qx1_sp0v_mode = {
143662306a36Sopenharmony_ci	.clock = 200000,
143762306a36Sopenharmony_ci	.hdisplay = 1536,
143862306a36Sopenharmony_ci	.hsync_start = 1536 + 12,
143962306a36Sopenharmony_ci	.hsync_end = 1536 + 12 + 16,
144062306a36Sopenharmony_ci	.htotal = 1536 + 12 + 16 + 48,
144162306a36Sopenharmony_ci	.vdisplay = 2048,
144262306a36Sopenharmony_ci	.vsync_start = 2048 + 8,
144362306a36Sopenharmony_ci	.vsync_end = 2048 + 8 + 4,
144462306a36Sopenharmony_ci	.vtotal = 2048 + 8 + 4 + 8,
144562306a36Sopenharmony_ci	.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
144662306a36Sopenharmony_ci};
144762306a36Sopenharmony_ci
144862306a36Sopenharmony_cistatic const struct panel_desc lg_lp079qx1_sp0v = {
144962306a36Sopenharmony_ci	.modes = &lg_lp079qx1_sp0v_mode,
145062306a36Sopenharmony_ci	.num_modes = 1,
145162306a36Sopenharmony_ci	.size = {
145262306a36Sopenharmony_ci		.width = 129,
145362306a36Sopenharmony_ci		.height = 171,
145462306a36Sopenharmony_ci	},
145562306a36Sopenharmony_ci};
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_cistatic const struct drm_display_mode lg_lp097qx1_spa1_mode = {
145862306a36Sopenharmony_ci	.clock = 205210,
145962306a36Sopenharmony_ci	.hdisplay = 2048,
146062306a36Sopenharmony_ci	.hsync_start = 2048 + 150,
146162306a36Sopenharmony_ci	.hsync_end = 2048 + 150 + 5,
146262306a36Sopenharmony_ci	.htotal = 2048 + 150 + 5 + 5,
146362306a36Sopenharmony_ci	.vdisplay = 1536,
146462306a36Sopenharmony_ci	.vsync_start = 1536 + 3,
146562306a36Sopenharmony_ci	.vsync_end = 1536 + 3 + 1,
146662306a36Sopenharmony_ci	.vtotal = 1536 + 3 + 1 + 9,
146762306a36Sopenharmony_ci};
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_cistatic const struct panel_desc lg_lp097qx1_spa1 = {
147062306a36Sopenharmony_ci	.modes = &lg_lp097qx1_spa1_mode,
147162306a36Sopenharmony_ci	.num_modes = 1,
147262306a36Sopenharmony_ci	.size = {
147362306a36Sopenharmony_ci		.width = 208,
147462306a36Sopenharmony_ci		.height = 147,
147562306a36Sopenharmony_ci	},
147662306a36Sopenharmony_ci};
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_cistatic const struct drm_display_mode lg_lp120up1_mode = {
147962306a36Sopenharmony_ci	.clock = 162300,
148062306a36Sopenharmony_ci	.hdisplay = 1920,
148162306a36Sopenharmony_ci	.hsync_start = 1920 + 40,
148262306a36Sopenharmony_ci	.hsync_end = 1920 + 40 + 40,
148362306a36Sopenharmony_ci	.htotal = 1920 + 40 + 40 + 80,
148462306a36Sopenharmony_ci	.vdisplay = 1280,
148562306a36Sopenharmony_ci	.vsync_start = 1280 + 4,
148662306a36Sopenharmony_ci	.vsync_end = 1280 + 4 + 4,
148762306a36Sopenharmony_ci	.vtotal = 1280 + 4 + 4 + 12,
148862306a36Sopenharmony_ci};
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_cistatic const struct panel_desc lg_lp120up1 = {
149162306a36Sopenharmony_ci	.modes = &lg_lp120up1_mode,
149262306a36Sopenharmony_ci	.num_modes = 1,
149362306a36Sopenharmony_ci	.bpc = 8,
149462306a36Sopenharmony_ci	.size = {
149562306a36Sopenharmony_ci		.width = 267,
149662306a36Sopenharmony_ci		.height = 183,
149762306a36Sopenharmony_ci	},
149862306a36Sopenharmony_ci};
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_cistatic const struct drm_display_mode lg_lp129qe_mode = {
150162306a36Sopenharmony_ci	.clock = 285250,
150262306a36Sopenharmony_ci	.hdisplay = 2560,
150362306a36Sopenharmony_ci	.hsync_start = 2560 + 48,
150462306a36Sopenharmony_ci	.hsync_end = 2560 + 48 + 32,
150562306a36Sopenharmony_ci	.htotal = 2560 + 48 + 32 + 80,
150662306a36Sopenharmony_ci	.vdisplay = 1700,
150762306a36Sopenharmony_ci	.vsync_start = 1700 + 3,
150862306a36Sopenharmony_ci	.vsync_end = 1700 + 3 + 10,
150962306a36Sopenharmony_ci	.vtotal = 1700 + 3 + 10 + 36,
151062306a36Sopenharmony_ci};
151162306a36Sopenharmony_ci
151262306a36Sopenharmony_cistatic const struct panel_desc lg_lp129qe = {
151362306a36Sopenharmony_ci	.modes = &lg_lp129qe_mode,
151462306a36Sopenharmony_ci	.num_modes = 1,
151562306a36Sopenharmony_ci	.bpc = 8,
151662306a36Sopenharmony_ci	.size = {
151762306a36Sopenharmony_ci		.width = 272,
151862306a36Sopenharmony_ci		.height = 181,
151962306a36Sopenharmony_ci	},
152062306a36Sopenharmony_ci};
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_cistatic const struct drm_display_mode neweast_wjfh116008a_modes[] = {
152362306a36Sopenharmony_ci	{
152462306a36Sopenharmony_ci		.clock = 138500,
152562306a36Sopenharmony_ci		.hdisplay = 1920,
152662306a36Sopenharmony_ci		.hsync_start = 1920 + 48,
152762306a36Sopenharmony_ci		.hsync_end = 1920 + 48 + 32,
152862306a36Sopenharmony_ci		.htotal = 1920 + 48 + 32 + 80,
152962306a36Sopenharmony_ci		.vdisplay = 1080,
153062306a36Sopenharmony_ci		.vsync_start = 1080 + 3,
153162306a36Sopenharmony_ci		.vsync_end = 1080 + 3 + 5,
153262306a36Sopenharmony_ci		.vtotal = 1080 + 3 + 5 + 23,
153362306a36Sopenharmony_ci		.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
153462306a36Sopenharmony_ci	}, {
153562306a36Sopenharmony_ci		.clock = 110920,
153662306a36Sopenharmony_ci		.hdisplay = 1920,
153762306a36Sopenharmony_ci		.hsync_start = 1920 + 48,
153862306a36Sopenharmony_ci		.hsync_end = 1920 + 48 + 32,
153962306a36Sopenharmony_ci		.htotal = 1920 + 48 + 32 + 80,
154062306a36Sopenharmony_ci		.vdisplay = 1080,
154162306a36Sopenharmony_ci		.vsync_start = 1080 + 3,
154262306a36Sopenharmony_ci		.vsync_end = 1080 + 3 + 5,
154362306a36Sopenharmony_ci		.vtotal = 1080 + 3 + 5 + 23,
154462306a36Sopenharmony_ci		.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
154562306a36Sopenharmony_ci	}
154662306a36Sopenharmony_ci};
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_cistatic const struct panel_desc neweast_wjfh116008a = {
154962306a36Sopenharmony_ci	.modes = neweast_wjfh116008a_modes,
155062306a36Sopenharmony_ci	.num_modes = 2,
155162306a36Sopenharmony_ci	.bpc = 6,
155262306a36Sopenharmony_ci	.size = {
155362306a36Sopenharmony_ci		.width = 260,
155462306a36Sopenharmony_ci		.height = 150,
155562306a36Sopenharmony_ci	},
155662306a36Sopenharmony_ci	.delay = {
155762306a36Sopenharmony_ci		.hpd_reliable = 110,
155862306a36Sopenharmony_ci		.enable = 20,
155962306a36Sopenharmony_ci		.unprepare = 500,
156062306a36Sopenharmony_ci	},
156162306a36Sopenharmony_ci};
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_cistatic const struct drm_display_mode samsung_lsn122dl01_c01_mode = {
156462306a36Sopenharmony_ci	.clock = 271560,
156562306a36Sopenharmony_ci	.hdisplay = 2560,
156662306a36Sopenharmony_ci	.hsync_start = 2560 + 48,
156762306a36Sopenharmony_ci	.hsync_end = 2560 + 48 + 32,
156862306a36Sopenharmony_ci	.htotal = 2560 + 48 + 32 + 80,
156962306a36Sopenharmony_ci	.vdisplay = 1600,
157062306a36Sopenharmony_ci	.vsync_start = 1600 + 2,
157162306a36Sopenharmony_ci	.vsync_end = 1600 + 2 + 5,
157262306a36Sopenharmony_ci	.vtotal = 1600 + 2 + 5 + 57,
157362306a36Sopenharmony_ci};
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_cistatic const struct panel_desc samsung_lsn122dl01_c01 = {
157662306a36Sopenharmony_ci	.modes = &samsung_lsn122dl01_c01_mode,
157762306a36Sopenharmony_ci	.num_modes = 1,
157862306a36Sopenharmony_ci	.size = {
157962306a36Sopenharmony_ci		.width = 263,
158062306a36Sopenharmony_ci		.height = 164,
158162306a36Sopenharmony_ci	},
158262306a36Sopenharmony_ci};
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_cistatic const struct drm_display_mode samsung_ltn140at29_301_mode = {
158562306a36Sopenharmony_ci	.clock = 76300,
158662306a36Sopenharmony_ci	.hdisplay = 1366,
158762306a36Sopenharmony_ci	.hsync_start = 1366 + 64,
158862306a36Sopenharmony_ci	.hsync_end = 1366 + 64 + 48,
158962306a36Sopenharmony_ci	.htotal = 1366 + 64 + 48 + 128,
159062306a36Sopenharmony_ci	.vdisplay = 768,
159162306a36Sopenharmony_ci	.vsync_start = 768 + 2,
159262306a36Sopenharmony_ci	.vsync_end = 768 + 2 + 5,
159362306a36Sopenharmony_ci	.vtotal = 768 + 2 + 5 + 17,
159462306a36Sopenharmony_ci};
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_cistatic const struct panel_desc samsung_ltn140at29_301 = {
159762306a36Sopenharmony_ci	.modes = &samsung_ltn140at29_301_mode,
159862306a36Sopenharmony_ci	.num_modes = 1,
159962306a36Sopenharmony_ci	.bpc = 6,
160062306a36Sopenharmony_ci	.size = {
160162306a36Sopenharmony_ci		.width = 320,
160262306a36Sopenharmony_ci		.height = 187,
160362306a36Sopenharmony_ci	},
160462306a36Sopenharmony_ci};
160562306a36Sopenharmony_ci
160662306a36Sopenharmony_cistatic const struct drm_display_mode sharp_ld_d5116z01b_mode = {
160762306a36Sopenharmony_ci	.clock = 168480,
160862306a36Sopenharmony_ci	.hdisplay = 1920,
160962306a36Sopenharmony_ci	.hsync_start = 1920 + 48,
161062306a36Sopenharmony_ci	.hsync_end = 1920 + 48 + 32,
161162306a36Sopenharmony_ci	.htotal = 1920 + 48 + 32 + 80,
161262306a36Sopenharmony_ci	.vdisplay = 1280,
161362306a36Sopenharmony_ci	.vsync_start = 1280 + 3,
161462306a36Sopenharmony_ci	.vsync_end = 1280 + 3 + 10,
161562306a36Sopenharmony_ci	.vtotal = 1280 + 3 + 10 + 57,
161662306a36Sopenharmony_ci	.flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC,
161762306a36Sopenharmony_ci};
161862306a36Sopenharmony_ci
161962306a36Sopenharmony_cistatic const struct panel_desc sharp_ld_d5116z01b = {
162062306a36Sopenharmony_ci	.modes = &sharp_ld_d5116z01b_mode,
162162306a36Sopenharmony_ci	.num_modes = 1,
162262306a36Sopenharmony_ci	.bpc = 8,
162362306a36Sopenharmony_ci	.size = {
162462306a36Sopenharmony_ci		.width = 260,
162562306a36Sopenharmony_ci		.height = 120,
162662306a36Sopenharmony_ci	},
162762306a36Sopenharmony_ci};
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_cistatic const struct display_timing sharp_lq123p1jx31_timing = {
163062306a36Sopenharmony_ci	.pixelclock = { 252750000, 252750000, 266604720 },
163162306a36Sopenharmony_ci	.hactive = { 2400, 2400, 2400 },
163262306a36Sopenharmony_ci	.hfront_porch = { 48, 48, 48 },
163362306a36Sopenharmony_ci	.hback_porch = { 80, 80, 84 },
163462306a36Sopenharmony_ci	.hsync_len = { 32, 32, 32 },
163562306a36Sopenharmony_ci	.vactive = { 1600, 1600, 1600 },
163662306a36Sopenharmony_ci	.vfront_porch = { 3, 3, 3 },
163762306a36Sopenharmony_ci	.vback_porch = { 33, 33, 120 },
163862306a36Sopenharmony_ci	.vsync_len = { 10, 10, 10 },
163962306a36Sopenharmony_ci	.flags = DISPLAY_FLAGS_VSYNC_LOW | DISPLAY_FLAGS_HSYNC_LOW,
164062306a36Sopenharmony_ci};
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_cistatic const struct panel_desc sharp_lq123p1jx31 = {
164362306a36Sopenharmony_ci	.timings = &sharp_lq123p1jx31_timing,
164462306a36Sopenharmony_ci	.num_timings = 1,
164562306a36Sopenharmony_ci	.bpc = 8,
164662306a36Sopenharmony_ci	.size = {
164762306a36Sopenharmony_ci		.width = 259,
164862306a36Sopenharmony_ci		.height = 173,
164962306a36Sopenharmony_ci	},
165062306a36Sopenharmony_ci	.delay = {
165162306a36Sopenharmony_ci		.hpd_reliable = 110,
165262306a36Sopenharmony_ci		.enable = 50,
165362306a36Sopenharmony_ci		.unprepare = 550,
165462306a36Sopenharmony_ci	},
165562306a36Sopenharmony_ci};
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_cistatic const struct drm_display_mode sharp_lq140m1jw46_mode[] = {
165862306a36Sopenharmony_ci	{
165962306a36Sopenharmony_ci		.clock = 346500,
166062306a36Sopenharmony_ci		.hdisplay = 1920,
166162306a36Sopenharmony_ci		.hsync_start = 1920 + 48,
166262306a36Sopenharmony_ci		.hsync_end = 1920 + 48 + 32,
166362306a36Sopenharmony_ci		.htotal = 1920 + 48 + 32 + 80,
166462306a36Sopenharmony_ci		.vdisplay = 1080,
166562306a36Sopenharmony_ci		.vsync_start = 1080 + 3,
166662306a36Sopenharmony_ci		.vsync_end = 1080 + 3 + 5,
166762306a36Sopenharmony_ci		.vtotal = 1080 + 3 + 5 + 69,
166862306a36Sopenharmony_ci		.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
166962306a36Sopenharmony_ci	}, {
167062306a36Sopenharmony_ci		.clock = 144370,
167162306a36Sopenharmony_ci		.hdisplay = 1920,
167262306a36Sopenharmony_ci		.hsync_start = 1920 + 48,
167362306a36Sopenharmony_ci		.hsync_end = 1920 + 48 + 32,
167462306a36Sopenharmony_ci		.htotal = 1920 + 48 + 32 + 80,
167562306a36Sopenharmony_ci		.vdisplay = 1080,
167662306a36Sopenharmony_ci		.vsync_start = 1080 + 3,
167762306a36Sopenharmony_ci		.vsync_end = 1080 + 3 + 5,
167862306a36Sopenharmony_ci		.vtotal = 1080 + 3 + 5 + 69,
167962306a36Sopenharmony_ci		.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
168062306a36Sopenharmony_ci	},
168162306a36Sopenharmony_ci};
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_cistatic const struct panel_desc sharp_lq140m1jw46 = {
168462306a36Sopenharmony_ci	.modes = sharp_lq140m1jw46_mode,
168562306a36Sopenharmony_ci	.num_modes = ARRAY_SIZE(sharp_lq140m1jw46_mode),
168662306a36Sopenharmony_ci	.bpc = 8,
168762306a36Sopenharmony_ci	.size = {
168862306a36Sopenharmony_ci		.width = 309,
168962306a36Sopenharmony_ci		.height = 174,
169062306a36Sopenharmony_ci	},
169162306a36Sopenharmony_ci	.delay = {
169262306a36Sopenharmony_ci		.hpd_absent = 80,
169362306a36Sopenharmony_ci		.enable = 50,
169462306a36Sopenharmony_ci		.unprepare = 500,
169562306a36Sopenharmony_ci	},
169662306a36Sopenharmony_ci};
169762306a36Sopenharmony_ci
169862306a36Sopenharmony_cistatic const struct drm_display_mode starry_kr122ea0sra_mode = {
169962306a36Sopenharmony_ci	.clock = 147000,
170062306a36Sopenharmony_ci	.hdisplay = 1920,
170162306a36Sopenharmony_ci	.hsync_start = 1920 + 16,
170262306a36Sopenharmony_ci	.hsync_end = 1920 + 16 + 16,
170362306a36Sopenharmony_ci	.htotal = 1920 + 16 + 16 + 32,
170462306a36Sopenharmony_ci	.vdisplay = 1200,
170562306a36Sopenharmony_ci	.vsync_start = 1200 + 15,
170662306a36Sopenharmony_ci	.vsync_end = 1200 + 15 + 2,
170762306a36Sopenharmony_ci	.vtotal = 1200 + 15 + 2 + 18,
170862306a36Sopenharmony_ci	.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
170962306a36Sopenharmony_ci};
171062306a36Sopenharmony_ci
171162306a36Sopenharmony_cistatic const struct panel_desc starry_kr122ea0sra = {
171262306a36Sopenharmony_ci	.modes = &starry_kr122ea0sra_mode,
171362306a36Sopenharmony_ci	.num_modes = 1,
171462306a36Sopenharmony_ci	.size = {
171562306a36Sopenharmony_ci		.width = 263,
171662306a36Sopenharmony_ci		.height = 164,
171762306a36Sopenharmony_ci	},
171862306a36Sopenharmony_ci	.delay = {
171962306a36Sopenharmony_ci		/* TODO: should be hpd-absent and no-hpd should be set? */
172062306a36Sopenharmony_ci		.hpd_reliable = 10 + 200,
172162306a36Sopenharmony_ci		.enable = 50,
172262306a36Sopenharmony_ci		.unprepare = 10 + 500,
172362306a36Sopenharmony_ci	},
172462306a36Sopenharmony_ci};
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_cistatic const struct of_device_id platform_of_match[] = {
172762306a36Sopenharmony_ci	{
172862306a36Sopenharmony_ci		/* Must be first */
172962306a36Sopenharmony_ci		.compatible = "edp-panel",
173062306a36Sopenharmony_ci	}, {
173162306a36Sopenharmony_ci		.compatible = "auo,b101ean01",
173262306a36Sopenharmony_ci		.data = &auo_b101ean01,
173362306a36Sopenharmony_ci	}, {
173462306a36Sopenharmony_ci		.compatible = "auo,b116xa01",
173562306a36Sopenharmony_ci		.data = &auo_b116xak01,
173662306a36Sopenharmony_ci	}, {
173762306a36Sopenharmony_ci		.compatible = "auo,b133han05",
173862306a36Sopenharmony_ci		.data = &auo_b133han05,
173962306a36Sopenharmony_ci	}, {
174062306a36Sopenharmony_ci		.compatible = "auo,b133htn01",
174162306a36Sopenharmony_ci		.data = &auo_b133htn01,
174262306a36Sopenharmony_ci	}, {
174362306a36Sopenharmony_ci		.compatible = "auo,b133xtn01",
174462306a36Sopenharmony_ci		.data = &auo_b133xtn01,
174562306a36Sopenharmony_ci	}, {
174662306a36Sopenharmony_ci		.compatible = "auo,b140han06",
174762306a36Sopenharmony_ci		.data = &auo_b140han06,
174862306a36Sopenharmony_ci	}, {
174962306a36Sopenharmony_ci		.compatible = "boe,nv101wxmn51",
175062306a36Sopenharmony_ci		.data = &boe_nv101wxmn51,
175162306a36Sopenharmony_ci	}, {
175262306a36Sopenharmony_ci		.compatible = "boe,nv110wtm-n61",
175362306a36Sopenharmony_ci		.data = &boe_nv110wtm_n61,
175462306a36Sopenharmony_ci	}, {
175562306a36Sopenharmony_ci		.compatible = "boe,nv133fhm-n61",
175662306a36Sopenharmony_ci		.data = &boe_nv133fhm_n61,
175762306a36Sopenharmony_ci	}, {
175862306a36Sopenharmony_ci		.compatible = "boe,nv133fhm-n62",
175962306a36Sopenharmony_ci		.data = &boe_nv133fhm_n61,
176062306a36Sopenharmony_ci	}, {
176162306a36Sopenharmony_ci		.compatible = "boe,nv140fhmn49",
176262306a36Sopenharmony_ci		.data = &boe_nv140fhmn49,
176362306a36Sopenharmony_ci	}, {
176462306a36Sopenharmony_ci		.compatible = "innolux,n116bca-ea1",
176562306a36Sopenharmony_ci		.data = &innolux_n116bca_ea1,
176662306a36Sopenharmony_ci	}, {
176762306a36Sopenharmony_ci		.compatible = "innolux,n116bge",
176862306a36Sopenharmony_ci		.data = &innolux_n116bge,
176962306a36Sopenharmony_ci	}, {
177062306a36Sopenharmony_ci		.compatible = "innolux,n125hce-gn1",
177162306a36Sopenharmony_ci		.data = &innolux_n125hce_gn1,
177262306a36Sopenharmony_ci	}, {
177362306a36Sopenharmony_ci		.compatible = "innolux,p120zdg-bf1",
177462306a36Sopenharmony_ci		.data = &innolux_p120zdg_bf1,
177562306a36Sopenharmony_ci	}, {
177662306a36Sopenharmony_ci		.compatible = "ivo,m133nwf4-r0",
177762306a36Sopenharmony_ci		.data = &ivo_m133nwf4_r0,
177862306a36Sopenharmony_ci	}, {
177962306a36Sopenharmony_ci		.compatible = "kingdisplay,kd116n21-30nv-a010",
178062306a36Sopenharmony_ci		.data = &kingdisplay_kd116n21_30nv_a010,
178162306a36Sopenharmony_ci	}, {
178262306a36Sopenharmony_ci		.compatible = "lg,lp079qx1-sp0v",
178362306a36Sopenharmony_ci		.data = &lg_lp079qx1_sp0v,
178462306a36Sopenharmony_ci	}, {
178562306a36Sopenharmony_ci		.compatible = "lg,lp097qx1-spa1",
178662306a36Sopenharmony_ci		.data = &lg_lp097qx1_spa1,
178762306a36Sopenharmony_ci	}, {
178862306a36Sopenharmony_ci		.compatible = "lg,lp120up1",
178962306a36Sopenharmony_ci		.data = &lg_lp120up1,
179062306a36Sopenharmony_ci	}, {
179162306a36Sopenharmony_ci		.compatible = "lg,lp129qe",
179262306a36Sopenharmony_ci		.data = &lg_lp129qe,
179362306a36Sopenharmony_ci	}, {
179462306a36Sopenharmony_ci		.compatible = "neweast,wjfh116008a",
179562306a36Sopenharmony_ci		.data = &neweast_wjfh116008a,
179662306a36Sopenharmony_ci	}, {
179762306a36Sopenharmony_ci		.compatible = "samsung,lsn122dl01-c01",
179862306a36Sopenharmony_ci		.data = &samsung_lsn122dl01_c01,
179962306a36Sopenharmony_ci	}, {
180062306a36Sopenharmony_ci		.compatible = "samsung,ltn140at29-301",
180162306a36Sopenharmony_ci		.data = &samsung_ltn140at29_301,
180262306a36Sopenharmony_ci	}, {
180362306a36Sopenharmony_ci		.compatible = "sharp,ld-d5116z01b",
180462306a36Sopenharmony_ci		.data = &sharp_ld_d5116z01b,
180562306a36Sopenharmony_ci	}, {
180662306a36Sopenharmony_ci		.compatible = "sharp,lq123p1jx31",
180762306a36Sopenharmony_ci		.data = &sharp_lq123p1jx31,
180862306a36Sopenharmony_ci	}, {
180962306a36Sopenharmony_ci		.compatible = "sharp,lq140m1jw46",
181062306a36Sopenharmony_ci		.data = &sharp_lq140m1jw46,
181162306a36Sopenharmony_ci	}, {
181262306a36Sopenharmony_ci		.compatible = "starry,kr122ea0sra",
181362306a36Sopenharmony_ci		.data = &starry_kr122ea0sra,
181462306a36Sopenharmony_ci	}, {
181562306a36Sopenharmony_ci		/* sentinel */
181662306a36Sopenharmony_ci	}
181762306a36Sopenharmony_ci};
181862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, platform_of_match);
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_cistatic const struct panel_delay delay_200_500_p2e80 = {
182162306a36Sopenharmony_ci	.hpd_absent = 200,
182262306a36Sopenharmony_ci	.unprepare = 500,
182362306a36Sopenharmony_ci	.prepare_to_enable = 80,
182462306a36Sopenharmony_ci};
182562306a36Sopenharmony_ci
182662306a36Sopenharmony_cistatic const struct panel_delay delay_200_500_p2e100 = {
182762306a36Sopenharmony_ci	.hpd_absent = 200,
182862306a36Sopenharmony_ci	.unprepare = 500,
182962306a36Sopenharmony_ci	.prepare_to_enable = 100,
183062306a36Sopenharmony_ci};
183162306a36Sopenharmony_ci
183262306a36Sopenharmony_cistatic const struct panel_delay delay_200_500_e50 = {
183362306a36Sopenharmony_ci	.hpd_absent = 200,
183462306a36Sopenharmony_ci	.unprepare = 500,
183562306a36Sopenharmony_ci	.enable = 50,
183662306a36Sopenharmony_ci};
183762306a36Sopenharmony_ci
183862306a36Sopenharmony_cistatic const struct panel_delay delay_200_500_e80_d50 = {
183962306a36Sopenharmony_ci	.hpd_absent = 200,
184062306a36Sopenharmony_ci	.unprepare = 500,
184162306a36Sopenharmony_ci	.enable = 80,
184262306a36Sopenharmony_ci	.disable = 50,
184362306a36Sopenharmony_ci};
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_cistatic const struct panel_delay delay_100_500_e200 = {
184662306a36Sopenharmony_ci	.hpd_absent = 100,
184762306a36Sopenharmony_ci	.unprepare = 500,
184862306a36Sopenharmony_ci	.enable = 200,
184962306a36Sopenharmony_ci};
185062306a36Sopenharmony_ci
185162306a36Sopenharmony_cistatic const struct panel_delay delay_200_500_e200 = {
185262306a36Sopenharmony_ci	.hpd_absent = 200,
185362306a36Sopenharmony_ci	.unprepare = 500,
185462306a36Sopenharmony_ci	.enable = 200,
185562306a36Sopenharmony_ci};
185662306a36Sopenharmony_ci
185762306a36Sopenharmony_ci#define EDP_PANEL_ENTRY(vend_chr_0, vend_chr_1, vend_chr_2, product_id, _delay, _name) \
185862306a36Sopenharmony_ci{ \
185962306a36Sopenharmony_ci	.name = _name, \
186062306a36Sopenharmony_ci	.panel_id = drm_edid_encode_panel_id(vend_chr_0, vend_chr_1, vend_chr_2, \
186162306a36Sopenharmony_ci					     product_id), \
186262306a36Sopenharmony_ci	.delay = _delay \
186362306a36Sopenharmony_ci}
186462306a36Sopenharmony_ci
186562306a36Sopenharmony_ci#define EDP_PANEL_ENTRY2(vend_chr_0, vend_chr_1, vend_chr_2, product_id, _delay, _name, _mode) \
186662306a36Sopenharmony_ci{ \
186762306a36Sopenharmony_ci	.name = _name, \
186862306a36Sopenharmony_ci	.panel_id = drm_edid_encode_panel_id(vend_chr_0, vend_chr_1, vend_chr_2, \
186962306a36Sopenharmony_ci					     product_id), \
187062306a36Sopenharmony_ci	.delay = _delay, \
187162306a36Sopenharmony_ci	.override_edid_mode = _mode \
187262306a36Sopenharmony_ci}
187362306a36Sopenharmony_ci
187462306a36Sopenharmony_ci/*
187562306a36Sopenharmony_ci * This table is used to figure out power sequencing delays for panels that
187662306a36Sopenharmony_ci * are detected by EDID. Entries here may point to entries in the
187762306a36Sopenharmony_ci * platform_of_match table (if a panel is listed in both places).
187862306a36Sopenharmony_ci *
187962306a36Sopenharmony_ci * Sort first by vendor, then by product ID.
188062306a36Sopenharmony_ci */
188162306a36Sopenharmony_cistatic const struct edp_panel_entry edp_panels[] = {
188262306a36Sopenharmony_ci	EDP_PANEL_ENTRY('A', 'U', 'O', 0x1062, &delay_200_500_e50, "B120XAN01.0"),
188362306a36Sopenharmony_ci	EDP_PANEL_ENTRY('A', 'U', 'O', 0x145c, &delay_200_500_e50, "B116XAB01.4"),
188462306a36Sopenharmony_ci	EDP_PANEL_ENTRY('A', 'U', 'O', 0x1e9b, &delay_200_500_e50, "B133UAN02.1"),
188562306a36Sopenharmony_ci	EDP_PANEL_ENTRY('A', 'U', 'O', 0x1ea5, &delay_200_500_e50, "B116XAK01.6"),
188662306a36Sopenharmony_ci	EDP_PANEL_ENTRY('A', 'U', 'O', 0x235c, &delay_200_500_e50, "B116XTN02.3"),
188762306a36Sopenharmony_ci	EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, &auo_b116xak01.delay, "B116XAK01.0"),
188862306a36Sopenharmony_ci	EDP_PANEL_ENTRY('A', 'U', 'O', 0x582d, &delay_200_500_e50, "B133UAN01.0"),
188962306a36Sopenharmony_ci	EDP_PANEL_ENTRY('A', 'U', 'O', 0x615c, &delay_200_500_e50, "B116XAN06.1"),
189062306a36Sopenharmony_ci	EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, &delay_200_500_e50, "B133UAN01.0"),
189162306a36Sopenharmony_ci
189262306a36Sopenharmony_ci	EDP_PANEL_ENTRY('B', 'O', 'E', 0x0786, &delay_200_500_p2e80, "NV116WHM-T01"),
189362306a36Sopenharmony_ci	EDP_PANEL_ENTRY('B', 'O', 'E', 0x07d1, &boe_nv133fhm_n61.delay, "NV133FHM-N61"),
189462306a36Sopenharmony_ci	EDP_PANEL_ENTRY('B', 'O', 'E', 0x082d, &boe_nv133fhm_n61.delay, "NV133FHM-N62"),
189562306a36Sopenharmony_ci	EDP_PANEL_ENTRY('B', 'O', 'E', 0x09c3, &delay_200_500_e50, "NT116WHM-N21,836X2"),
189662306a36Sopenharmony_ci	EDP_PANEL_ENTRY('B', 'O', 'E', 0x094b, &delay_200_500_e50, "NT116WHM-N21"),
189762306a36Sopenharmony_ci	EDP_PANEL_ENTRY('B', 'O', 'E', 0x095f, &delay_200_500_e50, "NE135FBM-N41 v8.1"),
189862306a36Sopenharmony_ci	EDP_PANEL_ENTRY('B', 'O', 'E', 0x0979, &delay_200_500_e50, "NV116WHM-N49 V8.0"),
189962306a36Sopenharmony_ci	EDP_PANEL_ENTRY('B', 'O', 'E', 0x098d, &boe_nv110wtm_n61.delay, "NV110WTM-N61"),
190062306a36Sopenharmony_ci	EDP_PANEL_ENTRY('B', 'O', 'E', 0x09dd, &delay_200_500_e50, "NT116WHM-N21"),
190162306a36Sopenharmony_ci	EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a5d, &delay_200_500_e50, "NV116WHM-N45"),
190262306a36Sopenharmony_ci	EDP_PANEL_ENTRY('B', 'O', 'E', 0x0ac5, &delay_200_500_e50, "NV116WHM-N4C"),
190362306a36Sopenharmony_ci
190462306a36Sopenharmony_ci	EDP_PANEL_ENTRY('C', 'M', 'N', 0x1139, &delay_200_500_e80_d50, "N116BGE-EA2"),
190562306a36Sopenharmony_ci	EDP_PANEL_ENTRY('C', 'M', 'N', 0x114c, &innolux_n116bca_ea1.delay, "N116BCA-EA1"),
190662306a36Sopenharmony_ci	EDP_PANEL_ENTRY('C', 'M', 'N', 0x1152, &delay_200_500_e80_d50, "N116BCN-EA1"),
190762306a36Sopenharmony_ci	EDP_PANEL_ENTRY('C', 'M', 'N', 0x1153, &delay_200_500_e80_d50, "N116BGE-EA2"),
190862306a36Sopenharmony_ci	EDP_PANEL_ENTRY('C', 'M', 'N', 0x1154, &delay_200_500_e80_d50, "N116BCA-EA2"),
190962306a36Sopenharmony_ci	EDP_PANEL_ENTRY('C', 'M', 'N', 0x1247, &delay_200_500_e80_d50, "N120ACA-EA1"),
191062306a36Sopenharmony_ci	EDP_PANEL_ENTRY('C', 'M', 'N', 0x14d4, &delay_200_500_e80_d50, "N140HCA-EAC"),
191162306a36Sopenharmony_ci
191262306a36Sopenharmony_ci	EDP_PANEL_ENTRY('I', 'V', 'O', 0x057d, &delay_200_500_e200, "R140NWF5 RH"),
191362306a36Sopenharmony_ci	EDP_PANEL_ENTRY('I', 'V', 'O', 0x854a, &delay_200_500_p2e100, "M133NW4J"),
191462306a36Sopenharmony_ci	EDP_PANEL_ENTRY('I', 'V', 'O', 0x854b, &delay_200_500_p2e100, "R133NW4K-R0"),
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_ci	EDP_PANEL_ENTRY('K', 'D', 'B', 0x0624, &kingdisplay_kd116n21_30nv_a010.delay, "116N21-30NV-A010"),
191762306a36Sopenharmony_ci	EDP_PANEL_ENTRY('K', 'D', 'B', 0x1120, &delay_200_500_e80_d50, "116N29-30NK-C007"),
191862306a36Sopenharmony_ci
191962306a36Sopenharmony_ci	EDP_PANEL_ENTRY('S', 'H', 'P', 0x1511, &delay_200_500_e50, "LQ140M1JW48"),
192062306a36Sopenharmony_ci	EDP_PANEL_ENTRY('S', 'H', 'P', 0x1523, &sharp_lq140m1jw46.delay, "LQ140M1JW46"),
192162306a36Sopenharmony_ci	EDP_PANEL_ENTRY('S', 'H', 'P', 0x154c, &delay_200_500_p2e100, "LQ116M1JW10"),
192262306a36Sopenharmony_ci
192362306a36Sopenharmony_ci	EDP_PANEL_ENTRY('S', 'T', 'A', 0x0100, &delay_100_500_e200, "2081116HHD028001-51D"),
192462306a36Sopenharmony_ci
192562306a36Sopenharmony_ci	{ /* sentinal */ }
192662306a36Sopenharmony_ci};
192762306a36Sopenharmony_ci
192862306a36Sopenharmony_cistatic const struct edp_panel_entry *find_edp_panel(u32 panel_id)
192962306a36Sopenharmony_ci{
193062306a36Sopenharmony_ci	const struct edp_panel_entry *panel;
193162306a36Sopenharmony_ci
193262306a36Sopenharmony_ci	if (!panel_id)
193362306a36Sopenharmony_ci		return NULL;
193462306a36Sopenharmony_ci
193562306a36Sopenharmony_ci	for (panel = edp_panels; panel->panel_id; panel++)
193662306a36Sopenharmony_ci		if (panel->panel_id == panel_id)
193762306a36Sopenharmony_ci			return panel;
193862306a36Sopenharmony_ci
193962306a36Sopenharmony_ci	return NULL;
194062306a36Sopenharmony_ci}
194162306a36Sopenharmony_ci
194262306a36Sopenharmony_cistatic int panel_edp_platform_probe(struct platform_device *pdev)
194362306a36Sopenharmony_ci{
194462306a36Sopenharmony_ci	const struct of_device_id *id;
194562306a36Sopenharmony_ci
194662306a36Sopenharmony_ci	/* Skip one since "edp-panel" is only supported on DP AUX bus */
194762306a36Sopenharmony_ci	id = of_match_node(platform_of_match + 1, pdev->dev.of_node);
194862306a36Sopenharmony_ci	if (!id)
194962306a36Sopenharmony_ci		return -ENODEV;
195062306a36Sopenharmony_ci
195162306a36Sopenharmony_ci	return panel_edp_probe(&pdev->dev, id->data, NULL);
195262306a36Sopenharmony_ci}
195362306a36Sopenharmony_ci
195462306a36Sopenharmony_cistatic void panel_edp_platform_remove(struct platform_device *pdev)
195562306a36Sopenharmony_ci{
195662306a36Sopenharmony_ci	panel_edp_remove(&pdev->dev);
195762306a36Sopenharmony_ci}
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_cistatic void panel_edp_platform_shutdown(struct platform_device *pdev)
196062306a36Sopenharmony_ci{
196162306a36Sopenharmony_ci	panel_edp_shutdown(&pdev->dev);
196262306a36Sopenharmony_ci}
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_cistatic const struct dev_pm_ops panel_edp_pm_ops = {
196562306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(panel_edp_suspend, panel_edp_resume, NULL)
196662306a36Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
196762306a36Sopenharmony_ci				pm_runtime_force_resume)
196862306a36Sopenharmony_ci};
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_cistatic struct platform_driver panel_edp_platform_driver = {
197162306a36Sopenharmony_ci	.driver = {
197262306a36Sopenharmony_ci		.name = "panel-edp",
197362306a36Sopenharmony_ci		.of_match_table = platform_of_match,
197462306a36Sopenharmony_ci		.pm = &panel_edp_pm_ops,
197562306a36Sopenharmony_ci	},
197662306a36Sopenharmony_ci	.probe = panel_edp_platform_probe,
197762306a36Sopenharmony_ci	.remove_new = panel_edp_platform_remove,
197862306a36Sopenharmony_ci	.shutdown = panel_edp_platform_shutdown,
197962306a36Sopenharmony_ci};
198062306a36Sopenharmony_ci
198162306a36Sopenharmony_cistatic int panel_edp_dp_aux_ep_probe(struct dp_aux_ep_device *aux_ep)
198262306a36Sopenharmony_ci{
198362306a36Sopenharmony_ci	const struct of_device_id *id;
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_ci	id = of_match_node(platform_of_match, aux_ep->dev.of_node);
198662306a36Sopenharmony_ci	if (!id)
198762306a36Sopenharmony_ci		return -ENODEV;
198862306a36Sopenharmony_ci
198962306a36Sopenharmony_ci	return panel_edp_probe(&aux_ep->dev, id->data, aux_ep->aux);
199062306a36Sopenharmony_ci}
199162306a36Sopenharmony_ci
199262306a36Sopenharmony_cistatic void panel_edp_dp_aux_ep_remove(struct dp_aux_ep_device *aux_ep)
199362306a36Sopenharmony_ci{
199462306a36Sopenharmony_ci	panel_edp_remove(&aux_ep->dev);
199562306a36Sopenharmony_ci}
199662306a36Sopenharmony_ci
199762306a36Sopenharmony_cistatic void panel_edp_dp_aux_ep_shutdown(struct dp_aux_ep_device *aux_ep)
199862306a36Sopenharmony_ci{
199962306a36Sopenharmony_ci	panel_edp_shutdown(&aux_ep->dev);
200062306a36Sopenharmony_ci}
200162306a36Sopenharmony_ci
200262306a36Sopenharmony_cistatic struct dp_aux_ep_driver panel_edp_dp_aux_ep_driver = {
200362306a36Sopenharmony_ci	.driver = {
200462306a36Sopenharmony_ci		.name = "panel-simple-dp-aux",
200562306a36Sopenharmony_ci		.of_match_table = platform_of_match,	/* Same as platform one! */
200662306a36Sopenharmony_ci		.pm = &panel_edp_pm_ops,
200762306a36Sopenharmony_ci	},
200862306a36Sopenharmony_ci	.probe = panel_edp_dp_aux_ep_probe,
200962306a36Sopenharmony_ci	.remove = panel_edp_dp_aux_ep_remove,
201062306a36Sopenharmony_ci	.shutdown = panel_edp_dp_aux_ep_shutdown,
201162306a36Sopenharmony_ci};
201262306a36Sopenharmony_ci
201362306a36Sopenharmony_cistatic int __init panel_edp_init(void)
201462306a36Sopenharmony_ci{
201562306a36Sopenharmony_ci	int err;
201662306a36Sopenharmony_ci
201762306a36Sopenharmony_ci	err = platform_driver_register(&panel_edp_platform_driver);
201862306a36Sopenharmony_ci	if (err < 0)
201962306a36Sopenharmony_ci		return err;
202062306a36Sopenharmony_ci
202162306a36Sopenharmony_ci	err = dp_aux_dp_driver_register(&panel_edp_dp_aux_ep_driver);
202262306a36Sopenharmony_ci	if (err < 0)
202362306a36Sopenharmony_ci		goto err_did_platform_register;
202462306a36Sopenharmony_ci
202562306a36Sopenharmony_ci	return 0;
202662306a36Sopenharmony_ci
202762306a36Sopenharmony_cierr_did_platform_register:
202862306a36Sopenharmony_ci	platform_driver_unregister(&panel_edp_platform_driver);
202962306a36Sopenharmony_ci
203062306a36Sopenharmony_ci	return err;
203162306a36Sopenharmony_ci}
203262306a36Sopenharmony_cimodule_init(panel_edp_init);
203362306a36Sopenharmony_ci
203462306a36Sopenharmony_cistatic void __exit panel_edp_exit(void)
203562306a36Sopenharmony_ci{
203662306a36Sopenharmony_ci	dp_aux_dp_driver_unregister(&panel_edp_dp_aux_ep_driver);
203762306a36Sopenharmony_ci	platform_driver_unregister(&panel_edp_platform_driver);
203862306a36Sopenharmony_ci}
203962306a36Sopenharmony_cimodule_exit(panel_edp_exit);
204062306a36Sopenharmony_ci
204162306a36Sopenharmony_ciMODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
204262306a36Sopenharmony_ciMODULE_DESCRIPTION("DRM Driver for Simple eDP Panels");
204362306a36Sopenharmony_ciMODULE_LICENSE("GPL and additional rights");
2044