From 131f909ad55f798f7bd0c3119d93778da312694a Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Mon, 9 Nov 2020 17:00:55 -0800 Subject: drm: panel: simple: Fixup the struct panel_desc kernel doc When I run: scripts/kernel-doc -rst drivers/gpu/drm/panel/panel-simple.c I see that several of the kernel-doc entries aren't showing up because they don't specify the full path down the hierarchy. Let's fix that and also move to inline kernel docs. Signed-off-by: Douglas Anderson Signed-off-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20201109170018.v4.1.Icaa86f0a4ca45a9a7184da4bc63386b29792d613@changeid --- drivers/gpu/drm/panel/panel-simple.c | 59 +++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 17 deletions(-) (limited to 'drivers/gpu/drm/panel/panel-simple.c') diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 41bbec72b2da..c6f152789a4e 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -64,33 +64,58 @@ struct panel_desc { unsigned int bpc; - /** - * @width: width (in millimeters) of the panel's active display area - * @height: height (in millimeters) of the panel's active display area - */ struct { + /** + * @size.width: Width (in mm) of the active display area. + */ unsigned int width; + + /** + * @size.height: Height (in mm) of the active display area. + */ unsigned int height; } size; - /** - * @prepare: the time (in milliseconds) that it takes for the panel to - * become ready and start receiving video data - * @hpd_absent_delay: Add this to the prepare delay if we know Hot - * Plug Detect isn't used. - * @enable: the time (in milliseconds) that it takes for the panel to - * display the first valid frame after starting to receive - * video data - * @disable: the time (in milliseconds) that it takes for the panel to - * turn the display off (no content is visible) - * @unprepare: the time (in milliseconds) that it takes for the panel - * to power itself down completely - */ struct { + /** + * @delay.prepare: Time for the panel to become ready. + * + * The time (in milliseconds) that it takes for the panel to + * become ready and start receiving video data + */ unsigned int prepare; + + /** + * @delay.hpd_absent_delay: Time to wait if HPD isn't hooked up. + * + * Add this to the prepare delay if we know Hot Plug Detect + * isn't used. + */ unsigned int hpd_absent_delay; + + /** + * @delay.enable: Time for the panel to display a valid frame. + * + * The time (in milliseconds) that it takes for the panel to + * display the first valid frame after starting to receive + * video data. + */ unsigned int enable; + + /** + * @delay.disable: Time for the panel to turn the display off. + * + * The time (in milliseconds) that it takes for the panel to + * turn the display off (no content is visible). + */ unsigned int disable; + + /** + * @delay.unprepare: Time to power down completely. + * + * The time (in milliseconds) that it takes for the panel + * to power itself down completely. + */ unsigned int unprepare; } delay; -- cgit From e5e30dfcf3db1534019c40d94ed58fd2869f9359 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Mon, 9 Nov 2020 17:00:56 -0800 Subject: drm: panel: simple: Defer unprepare delay till next prepare to shorten it It is believed that all of the current users of the "unprepare" delay don't actually need to wait the amount of time specified directly in the unprepare phase. The purpose of the delay that's specified is to allow the panel to fully power off so that we don't try to power it back on before it's managed to full power down. Let's use this observation to avoid the fixed delay that we currently have. Instead of delaying, we'll note the current time when the unprepare happens. If someone then tries to prepare the panel later and not enough time has passed, we'll do the delay before starting the prepare phase. Signed-off-by: Douglas Anderson Signed-off-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20201109170018.v4.2.I06a95d83e7fa1bd919c8edd63dacacb5436e495a@changeid --- drivers/gpu/drm/panel/panel-simple.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/panel/panel-simple.c') diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index c6f152789a4e..72c120a68266 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -115,6 +115,11 @@ struct panel_desc { * * The time (in milliseconds) that it takes for the panel * to power itself down completely. + * + * This time is used to prevent a future "prepare" from + * starting until at least this many milliseconds has passed. + * If at prepare time less time has passed since unprepare + * finished, the driver waits for the remaining time. */ unsigned int unprepare; } delay; @@ -130,6 +135,8 @@ struct panel_simple { bool enabled; bool no_hpd; + ktime_t unprepared_time; + const struct panel_desc *desc; struct regulator *supply; @@ -257,6 +264,20 @@ static int panel_simple_get_non_edid_modes(struct panel_simple *panel, return num; } +static void panel_simple_wait(ktime_t start_ktime, unsigned int min_ms) +{ + ktime_t now_ktime, min_ktime; + + if (!min_ms) + return; + + min_ktime = ktime_add(start_ktime, ms_to_ktime(min_ms)); + now_ktime = ktime_get(); + + if (ktime_before(now_ktime, min_ktime)) + msleep(ktime_to_ms(ktime_sub(min_ktime, now_ktime)) + 1); +} + static int panel_simple_disable(struct drm_panel *panel) { struct panel_simple *p = to_panel_simple(panel); @@ -283,10 +304,8 @@ static int panel_simple_unprepare(struct drm_panel *panel) regulator_disable(p->supply); - if (p->desc->delay.unprepare) - msleep(p->desc->delay.unprepare); - p->prepared = false; + p->unprepared_time = ktime_get(); return 0; } @@ -326,6 +345,8 @@ static int panel_simple_prepare(struct drm_panel *panel) if (p->prepared) return 0; + panel_simple_wait(p->unprepared_time, p->desc->delay.unprepare); + err = regulator_enable(p->supply); if (err < 0) { dev_err(panel->dev, "failed to enable supply: %d\n", err); -- cgit From 4beb04beb24afe5268bf91407b44864f42f448ed Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Mon, 9 Nov 2020 17:00:57 -0800 Subject: drm: panel: simple: Allow specifying the delay from prepare to enable On the panel I'm looking at, there's an 80 ms minimum time between HPD being asserted by the panel and setting the backlight enable GPIO. While we could just add an 80 ms "enable" delay, this is not ideal. Link training is allowed to happen in parallel with this delay so the fixed 80 ms delay over-delays. We'll support this by logging the time at the end of prepare and then delaying in enable if enough time hasn't passed. Signed-off-by: Douglas Anderson Signed-off-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20201109170018.v4.3.Ib9ce3c6482f464bf594161581521ced46bbd54ed@changeid --- drivers/gpu/drm/panel/panel-simple.c | 44 +++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/panel/panel-simple.c') diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 72c120a68266..cd30f3f51964 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -93,6 +93,36 @@ struct panel_desc { */ unsigned int hpd_absent_delay; + /** + * @delay.prepare_to_enable: Time between prepare and enable. + * + * The minimum time, in milliseconds, that needs to have passed + * between when prepare finished and enable may begin. If at + * enable time less time has passed since prepare finished, + * the driver waits for the remaining time. + * + * If a fixed enable delay is also specified, we'll start + * counting before delaying for the fixed delay. + * + * If a fixed prepare delay is also specified, we won't start + * counting until after the fixed delay. We can't overlap this + * fixed delay with the min time because the fixed delay + * doesn't happen at the end of the function if a HPD GPIO was + * specified. + * + * In other words: + * prepare() + * ... + * // do fixed prepare delay + * // wait for HPD GPIO if applicable + * // start counting for prepare_to_enable + * + * enable() + * // do fixed enable delay + * // enforce prepare_to_enable min time + */ + unsigned int prepare_to_enable; + /** * @delay.enable: Time for the panel to display a valid frame. * @@ -131,10 +161,10 @@ struct panel_desc { struct panel_simple { struct drm_panel base; - bool prepared; bool enabled; bool no_hpd; + ktime_t prepared_time; ktime_t unprepared_time; const struct panel_desc *desc; @@ -297,14 +327,14 @@ static int panel_simple_unprepare(struct drm_panel *panel) { struct panel_simple *p = to_panel_simple(panel); - if (!p->prepared) + if (p->prepared_time == 0) return 0; gpiod_set_value_cansleep(p->enable_gpio, 0); regulator_disable(p->supply); - p->prepared = false; + p->prepared_time = 0; p->unprepared_time = ktime_get(); return 0; @@ -342,7 +372,7 @@ static int panel_simple_prepare(struct drm_panel *panel) int err; int hpd_asserted; - if (p->prepared) + if (p->prepared_time != 0) return 0; panel_simple_wait(p->unprepared_time, p->desc->delay.unprepare); @@ -381,7 +411,7 @@ static int panel_simple_prepare(struct drm_panel *panel) } } - p->prepared = true; + p->prepared_time = ktime_get(); return 0; } @@ -396,6 +426,8 @@ static int panel_simple_enable(struct drm_panel *panel) if (p->desc->delay.enable) msleep(p->desc->delay.enable); + panel_simple_wait(p->prepared_time, p->desc->delay.prepare_to_enable); + p->enabled = true; return 0; @@ -562,7 +594,7 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) return -ENOMEM; panel->enabled = false; - panel->prepared = false; + panel->prepared_time = 0; panel->desc = desc; panel->no_hpd = of_property_read_bool(dev->of_node, "no-hpd"); -- cgit From a96ee0f6b58de5c4f627489b2d31a5099a779cb9 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Mon, 9 Nov 2020 17:00:58 -0800 Subject: drm: panel: simple: Add BOE NV110WTM-N61 Add support for the BOE NV110WTM-N61 panel. The EDID lists two modes (one for 60 Hz refresh rate and one for 40 Hz), so we'll list both of them here. Note that the panel datasheet requires 80 ms between HPD asserting and the backlight power being turned on. We'll use the new timing constraints structure to do this cleanly. This assumes that the backlight will be enabled _after_ the panel enable finishes. This is how it works today and seems a sane assumption. Signed-off-by: Douglas Anderson Signed-off-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20201109170018.v4.4.I71b2118dfc00fd7b43b02d28e7b890081c2acfa2@changeid --- drivers/gpu/drm/panel/panel-simple.c | 46 ++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'drivers/gpu/drm/panel/panel-simple.c') diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index cd30f3f51964..216cde33b5c4 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -1396,6 +1396,49 @@ static const struct panel_desc boe_nv101wxmn51 = { }, }; +static const struct drm_display_mode boe_nv110wtm_n61_modes[] = { + { + .clock = 207800, + .hdisplay = 2160, + .hsync_start = 2160 + 48, + .hsync_end = 2160 + 48 + 32, + .htotal = 2160 + 48 + 32 + 100, + .vdisplay = 1440, + .vsync_start = 1440 + 3, + .vsync_end = 1440 + 3 + 6, + .vtotal = 1440 + 3 + 6 + 31, + }, + { + .clock = 138500, + .hdisplay = 2160, + .hsync_start = 2160 + 48, + .hsync_end = 2160 + 48 + 32, + .htotal = 2160 + 48 + 32 + 100, + .vdisplay = 1440, + .vsync_start = 1440 + 3, + .vsync_end = 1440 + 3 + 6, + .vtotal = 1440 + 3 + 6 + 31, + }, +}; + +static const struct panel_desc boe_nv110wtm_n61 = { + .modes = boe_nv110wtm_n61_modes, + .num_modes = ARRAY_SIZE(boe_nv110wtm_n61_modes), + .bpc = 8, + .size = { + .width = 233, + .height = 155, + }, + .delay = { + .hpd_absent_delay = 200, + .prepare_to_enable = 80, + .unprepare = 500, + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X24, + .bus_flags = DRM_BUS_FLAG_DATA_MSB_TO_LSB, + .connector_type = DRM_MODE_CONNECTOR_eDP, +}; + /* Also used for boe_nv133fhm_n62 */ static const struct drm_display_mode boe_nv133fhm_n61_modes = { .clock = 147840, @@ -4111,6 +4154,9 @@ static const struct of_device_id platform_of_match[] = { }, { .compatible = "boe,nv101wxmn51", .data = &boe_nv101wxmn51, + }, { + .compatible = "boe,nv110wtm-n61", + .data = &boe_nv110wtm_n61, }, { .compatible = "boe,nv133fhm-n61", .data = &boe_nv133fhm_n61, -- cgit From a00fa4285878e5fe5b452111bc8004c185cc2dd5 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Tue, 1 Dec 2020 12:59:12 -0800 Subject: drm: panel: Fully transition panel_desc kerneldoc to inline style In commit 131f909ad55f ("drm: panel: simple: Fixup the struct panel_desc kernel doc") I transitioned the more deeply nested kerneldoc comments into the inline style. Apparently it is desirable to continue the job and move _everything_ in this struct to inline. Let's do it. While doing this, we also add a short summary for the whole struct to fix a warning when we run with extra warnings, AKA: scripts/kernel-doc -v -rst drivers/gpu/drm/panel/panel-simple.c The warning was: drivers/gpu/drm/panel/panel-simple.c:42: warning: missing initial short description on line: * struct panel_desc Suggested-by: Sam Ravnborg Signed-off-by: Douglas Anderson Cc: Douglas Anderson Cc: Sam Ravnborg Cc: Thierry Reding Cc: dri-devel@lists.freedesktop.org Signed-off-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20201201125822.1.I3c4191336014bd57364309439e56f600c94bb12b@changeid --- drivers/gpu/drm/panel/panel-simple.c | 43 ++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 16 deletions(-) (limited to 'drivers/gpu/drm/panel/panel-simple.c') diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 216cde33b5c4..faa45af48c15 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -39,31 +39,36 @@ #include /** - * struct panel_desc - * @modes: Pointer to array of fixed modes appropriate for this panel. If - * only one mode then this can just be the address of this the mode. - * NOTE: cannot be used with "timings" and also if this is specified - * then you cannot override the mode in the device tree. - * @num_modes: Number of elements in modes array. - * @timings: Pointer to array of display timings. NOTE: cannot be used with - * "modes" and also these will be used to validate a device tree - * override if one is present. - * @num_timings: Number of elements in timings array. - * @bpc: Bits per color. - * @size: Structure containing the physical size of this panel. - * @delay: Structure containing various delay values for this panel. - * @bus_format: See MEDIA_BUS_FMT_... defines. - * @bus_flags: See DRM_BUS_FLAG_... defines. - * @connector_type: LVDS, eDP, DSI, DPI, etc. + * struct panel_desc - Describes a simple panel. */ struct panel_desc { + /** + * @modes: Pointer to array of fixed modes appropriate for this panel. + * + * If only one mode then this can just be the address of the mode. + * NOTE: cannot be used with "timings" and also if this is specified + * then you cannot override the mode in the device tree. + */ const struct drm_display_mode *modes; + + /** @num_modes: Number of elements in modes array. */ unsigned int num_modes; + + /** + * @timings: Pointer to array of display timings + * + * NOTE: cannot be used with "modes" and also these will be used to + * validate a device tree override if one is present. + */ const struct display_timing *timings; + + /** @num_timings: Number of elements in timings array. */ unsigned int num_timings; + /** @bpc: Bits per color. */ unsigned int bpc; + /** @size: Structure containing the physical size of this panel. */ struct { /** * @size.width: Width (in mm) of the active display area. @@ -76,6 +81,7 @@ struct panel_desc { unsigned int height; } size; + /** @delay: Structure containing various delay values for this panel. */ struct { /** * @delay.prepare: Time for the panel to become ready. @@ -154,8 +160,13 @@ struct panel_desc { unsigned int unprepare; } delay; + /** @bus_format: See MEDIA_BUS_FMT_... defines. */ u32 bus_format; + + /** @bus_flags: See DRM_BUS_FLAG_... defines. */ u32 bus_flags; + + /** @connector_type: LVDS, eDP, DSI, DPI, etc. */ int connector_type; }; -- cgit From 9dbf1a4516cff8617fde63d265ccbdd6a0f56854 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Tue, 1 Dec 2020 12:56:11 -0800 Subject: drm: panel: add flags to BOE NV110WTM-N61 I forgot to add these when posting up the support for BOE NV110WTM-N61. Add them now. Fixes: a96ee0f6b58d ("drm: panel: simple: Add BOE NV110WTM-N61") Signed-off-by: Douglas Anderson Cc: Douglas Anderson Cc: Sam Ravnborg Cc: Thierry Reding Cc: dri-devel@lists.freedesktop.org Signed-off-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20201201125554.v2.1.I8a7bfc0966e803ab91001c9e6d01a736950c4981@changeid --- drivers/gpu/drm/panel/panel-simple.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/gpu/drm/panel/panel-simple.c') diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index faa45af48c15..71ae200ac48a 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -1418,6 +1418,7 @@ static const struct drm_display_mode boe_nv110wtm_n61_modes[] = { .vsync_start = 1440 + 3, .vsync_end = 1440 + 3 + 6, .vtotal = 1440 + 3 + 6 + 31, + .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC, }, { .clock = 138500, @@ -1429,6 +1430,7 @@ static const struct drm_display_mode boe_nv110wtm_n61_modes[] = { .vsync_start = 1440 + 3, .vsync_end = 1440 + 3 + 6, .vtotal = 1440 + 3 + 6 + 31, + .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC, }, }; -- cgit