From 9677547d836299497ba2da1ad59851e200109ca1 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 18 Mar 2024 22:44:07 +0200 Subject: drm: Introduce plane SIZE_HINTS property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a new immutable plane property by which a plane can advertise a handful of recommended plane sizes. This would be mostly exposed by cursor planes as a slightly more capable replacement for the DRM_CAP_CURSOR_WIDTH/HEIGHT caps, which can only declare a one size fits all limit for the whole device. Currently eg. amdgpu/i915/nouveau just advertize the max cursor size via the cursor size caps. But always using the max sized cursor can waste a surprising amount of power, so a better strategy is desirable. Most other drivers don't specify any cursor size at all, in which case the ioctl code just claims that 64x64 is a great choice. Whether that is actually true is debatable. A poll of various compositor developers informs us that blindly probing with setcursor/atomic ioctl to determine suitable cursor sizes is not acceptable, thus the introduction of the new property to supplant the cursor size caps. The compositor will now be free to select a more optimal cursor size from the short list of options. Note that the reported sizes (either via the property or the caps) make no claims about things such as plane scaling. So these things should only really be consulted for simple "cursor like" use cases. Userspace consumer in the form of mutter seems ready: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3165 v2: Try to add some docs v3: Specify that value 0 is reserved for future use (basic idea from Jonas) Drop the note about typical hardware (Pekka) v4: Update the docs to indicate the list is "in order of preference" Add a a link to the mutter MR v5: Limit to cursors only for now (Simon) Cc: Jonas Ådahl Cc: Sameer Lattannavar Reviewed-by: Sebastian Wick Reviewed-by: Simon Ser Acked-by: Daniel Stone Acked-by: Harry Wentland Acked-by: Pekka Paalanen Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20240318204408.9687-2-ville.syrjala@linux.intel.com --- include/drm/drm_mode_config.h | 5 +++++ include/drm/drm_plane.h | 4 ++++ 2 files changed, 9 insertions(+) (limited to 'include/drm') diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h index 973119a9176b..9d8acf7a10eb 100644 --- a/include/drm/drm_mode_config.h +++ b/include/drm/drm_mode_config.h @@ -942,6 +942,11 @@ struct drm_mode_config { */ struct drm_property *modifiers_property; + /** + * @size_hints_propertty: Plane SIZE_HINTS property. + */ + struct drm_property *size_hints_property; + /* cursor size */ uint32_t cursor_width, cursor_height; diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index 641fe298052d..ec1112208b73 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -32,6 +32,7 @@ #include struct drm_crtc; +struct drm_plane_size_hint; struct drm_printer; struct drm_modeset_acquire_ctx; @@ -976,5 +977,8 @@ drm_plane_get_damage_clips(const struct drm_plane_state *state); int drm_plane_create_scaling_filter_property(struct drm_plane *plane, unsigned int supported_filters); +int drm_plane_add_size_hints_property(struct drm_plane *plane, + const struct drm_plane_size_hint *hints, + int num_hints); #endif -- cgit v1.2.3 From 3ddbd345539eb89cb1ccceb79ef0a3c150aeebbf Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 9 Apr 2024 12:46:09 +0300 Subject: drm/edid: add drm_edid_get_product_id() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a struct drm_edid based function to get the vendor and product ID from an EDID. Add a separate struct for defining this part of the EDID, with defined byte order for manufacturer name, product code and serial number. v2: Define manufacturer_name as __be16 instead of u8[2] (Ville) Cc: Ville Syrjälä Acked-by: Melissa Wen Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/df0e7dedbf7f2c190039d6e6eae3e126eba113c9.1712655867.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/drm_edid.c | 15 +++++++++++++++ include/drm/drm_edid.h | 25 ++++++++++++++++++++----- 2 files changed, 35 insertions(+), 5 deletions(-) (limited to 'include/drm') diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index ea77577a3786..626a0e24e66a 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -2756,6 +2756,21 @@ const struct drm_edid *drm_edid_read(struct drm_connector *connector) } EXPORT_SYMBOL(drm_edid_read); +/** + * drm_edid_get_product_id - Get the vendor and product identification + * @drm_edid: EDID + * @id: Where to place the product id + */ +void drm_edid_get_product_id(const struct drm_edid *drm_edid, + struct drm_edid_product_id *id) +{ + if (drm_edid && drm_edid->edid && drm_edid->size >= EDID_LENGTH) + memcpy(id, &drm_edid->edid->product_id, sizeof(*id)); + else + memset(id, 0, sizeof(*id)); +} +EXPORT_SYMBOL(drm_edid_get_product_id); + /** * drm_edid_get_panel_id - Get a panel's ID from EDID * @drm_edid: EDID that contains panel ID. diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 6f65bbf655a1..8bdd8d54815d 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -272,14 +272,27 @@ struct detailed_timing { #define DRM_EDID_DSC_MAX_SLICES 0xf #define DRM_EDID_DSC_TOTAL_CHUNK_KBYTES 0x3f +struct drm_edid_product_id { + __be16 manufacturer_name; + __le16 product_code; + __le32 serial_number; + u8 week_of_manufacture; + u8 year_of_manufacture; +} __packed; + struct edid { u8 header[8]; /* Vendor & product info */ - u8 mfg_id[2]; - u8 prod_code[2]; - u32 serial; /* FIXME: byte order */ - u8 mfg_week; - u8 mfg_year; + union { + struct drm_edid_product_id product_id; + struct { + u8 mfg_id[2]; + u8 prod_code[2]; + u32 serial; /* FIXME: byte order */ + u8 mfg_week; + u8 mfg_year; + } __packed; + } __packed; /* EDID version */ u8 version; u8 revision; @@ -466,6 +479,8 @@ int drm_edid_connector_update(struct drm_connector *connector, const struct drm_edid *edid); int drm_edid_connector_add_modes(struct drm_connector *connector); bool drm_edid_is_digital(const struct drm_edid *drm_edid); +void drm_edid_get_product_id(const struct drm_edid *drm_edid, + struct drm_edid_product_id *id); const u8 *drm_find_edid_extension(const struct drm_edid *drm_edid, int ext_id, int *ext_index); -- cgit v1.2.3 From 3f56e5514bfd99aaba649e4af6b11a11b731d3a2 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 9 Apr 2024 12:46:10 +0300 Subject: drm/edid: add drm_edid_print_product_id() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a function to print a decoded EDID vendor and product id to a drm printer, optionally with the raw data. v2: - refactor date printing - use seq_buf to avoid kasprintf() (Ville) - handle week == 0 (Ville) - use be16_to_cpu() on manufacturer_name Cc: Ville Syrjälä Acked-by: Melissa Wen # v1 Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/32bbc83ee6557809ef6d7a5edb1bc8ef4d56d10f.1712655867.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/drm_edid.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ include/drm/drm_edid.h | 3 +++ 2 files changed, 47 insertions(+) (limited to 'include/drm') diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 626a0e24e66a..1400722ae3fe 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -29,12 +29,14 @@ */ #include +#include #include #include #include #include #include #include +#include #include #include @@ -2771,6 +2773,48 @@ void drm_edid_get_product_id(const struct drm_edid *drm_edid, } EXPORT_SYMBOL(drm_edid_get_product_id); +static void decode_date(struct seq_buf *s, const struct drm_edid_product_id *id) +{ + int week = id->week_of_manufacture; + int year = id->year_of_manufacture + 1990; + + if (week == 0xff) + seq_buf_printf(s, "model year: %d", year); + else if (!week) + seq_buf_printf(s, "year of manufacture: %d", year); + else + seq_buf_printf(s, "week/year of manufacture: %d/%d", week, year); +} + +/** + * drm_edid_print_product_id - Print decoded product id to printer + * @p: drm printer + * @id: EDID product id + * @raw: If true, also print the raw hex + * + * See VESA E-EDID 1.4 section 3.4. + */ +void drm_edid_print_product_id(struct drm_printer *p, + const struct drm_edid_product_id *id, bool raw) +{ + DECLARE_SEQ_BUF(date, 40); + char vend[4]; + + drm_edid_decode_mfg_id(be16_to_cpu(id->manufacturer_name), vend); + + decode_date(&date, id); + + drm_printf(p, "manufacturer name: %s, product code: %u, serial number: %u, %s\n", + vend, le16_to_cpu(id->product_code), + le32_to_cpu(id->serial_number), seq_buf_str(&date)); + + if (raw) + drm_printf(p, "raw product id: %*ph\n", (int)sizeof(*id), id); + + WARN_ON(seq_buf_has_overflowed(&date)); +} +EXPORT_SYMBOL(drm_edid_print_product_id); + /** * drm_edid_get_panel_id - Get a panel's ID from EDID * @drm_edid: EDID that contains panel ID. diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 8bdd8d54815d..8e0e32349332 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -30,6 +30,7 @@ struct drm_connector; struct drm_device; struct drm_display_mode; struct drm_edid; +struct drm_printer; struct hdmi_avi_infoframe; struct hdmi_vendor_infoframe; struct i2c_adapter; @@ -481,6 +482,8 @@ int drm_edid_connector_add_modes(struct drm_connector *connector); bool drm_edid_is_digital(const struct drm_edid *drm_edid); void drm_edid_get_product_id(const struct drm_edid *drm_edid, struct drm_edid_product_id *id); +void drm_edid_print_product_id(struct drm_printer *p, + const struct drm_edid_product_id *id, bool raw); const u8 *drm_find_edid_extension(const struct drm_edid *drm_edid, int ext_id, int *ext_index); -- cgit v1.2.3 From e2a1cda3e0c784740751d46431973dcee32cf108 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 9 Apr 2024 18:30:40 +0200 Subject: drm/panic: Add drm panic locking Rough sketch for the locking of drm panic printing code. The upshot of this approach is that we can pretty much entirely rely on the atomic commit flow, with the pair of raw_spin_lock/unlock providing any barriers we need, without having to create really big critical sections in code. This also avoids the need that drivers must explicitly update the panic handler state, which they might forget to do, or not do consistently, and then we blow up in the worst possible times. It is somewhat racy against a concurrent atomic update, and we might write into a buffer which the hardware will never display. But there's fundamentally no way to avoid that - if we do the panic state update explicitly after writing to the hardware, we might instead write to an old buffer that the user will barely ever see. Note that an rcu protected deference of plane->state would give us the the same guarantees, but it has the downside that we then need to protect the plane state freeing functions with call_rcu too. Which would very widely impact a lot of code and therefore doesn't seem worth the complexity compared to a raw spinlock with very tiny critical sections. Plus rcu cannot be used to protect access to peek/poke registers anyway, so we'd still need it for those cases. Peek/poke registers for vram access (or a gart pte reserved just for panic code) are also the reason I've gone with a per-device and not per-plane spinlock, since usually these things are global for the entire display. Going with per-plane locks would mean drivers for such hardware would need additional locks, which we don't want, since it deviates from the per-console takeoverlocks design. Longer term it might be useful if the panic notifiers grow a bit more structure than just the absolute bare EXPORT_SYMBOL(panic_notifier_list) - somewhat aside, why is that not EXPORT_SYMBOL_GPL ... If panic notifiers would be more like console drivers with proper register/unregister interfaces we could perhaps reuse the very fancy console lock with all it's check and takeover semantics that John Ogness is developing to fix the console_lock mess. But for the initial cut of a drm panic printing support I don't think we need that, because the critical sections are extremely small and only happen once per display refresh. So generally just 60 tiny locked sections per second, which is nothing compared to a serial console running a 115kbaud doing really slow mmio writes for each byte. So for now the raw spintrylock in drm panic notifier callback should be good enough. Another benefit of making panic notifiers more like full blown consoles (that are used in panics only) would be that we get the two stage design, where first all the safe outputs are used. And then the dangerous takeover tricks are deployed (where for display drivers we also might try to intercept any in-flight display buffer flips, which if we race and misprogram fifos and watermarks can hang the memory controller on some hw). For context the actual implementation on the drm side is by Jocelyn and this patch is meant to be combined with the overall approach in v7 (v8 is a bit less flexible, which I think is the wrong direction): https://lore.kernel.org/dri-devel/20240104160301.185915-1-jfalempe@redhat.com/ Note that the locking is very much not correct there, hence this separate rfc. Starting from v10, I (Jocelyn) have included this patch in the drm_panic series, and done the corresponding changes. v2: - fix authorship, this was all my typing - some typo oopsies - link to the drm panic work by Jocelyn for context v10: - Use spinlock_irqsave/restore (John Ogness) v11: - Use macro instead of inline functions for drm_panic_lock/unlock (John Ogness) Signed-off-by: Daniel Vetter Cc: Jocelyn Falempe Cc: Andrew Morton Cc: "Peter Zijlstra (Intel)" Cc: Lukas Wunner Cc: Petr Mladek Cc: Steven Rostedt Cc: John Ogness Cc: Sergey Senozhatsky Cc: Maarten Lankhorst Cc: Maxime Ripard Cc: Thomas Zimmermann Cc: David Airlie Cc: Daniel Vetter Signed-off-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20240409163432.352518-2-jfalempe@redhat.com Acked-by: Daniel Vetter --- drivers/gpu/drm/drm_atomic_helper.c | 4 ++ drivers/gpu/drm/drm_drv.c | 1 + include/drm/drm_mode_config.h | 10 ++++ include/drm/drm_panic.h | 95 +++++++++++++++++++++++++++++++++++++ 4 files changed, 110 insertions(+) create mode 100644 include/drm/drm_panic.h (limited to 'include/drm') diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 39ef0a6addeb..fb97b51b38f1 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -3016,6 +3017,7 @@ int drm_atomic_helper_swap_state(struct drm_atomic_state *state, bool stall) { int i, ret; + unsigned long flags; struct drm_connector *connector; struct drm_connector_state *old_conn_state, *new_conn_state; struct drm_crtc *crtc; @@ -3099,6 +3101,7 @@ int drm_atomic_helper_swap_state(struct drm_atomic_state *state, } } + drm_panic_lock(state->dev, flags); for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) { WARN_ON(plane->state != old_plane_state); @@ -3108,6 +3111,7 @@ int drm_atomic_helper_swap_state(struct drm_atomic_state *state, state->planes[i].state = old_plane_state; plane->state = new_plane_state; } + drm_panic_unlock(state->dev, flags); for_each_oldnew_private_obj_in_state(state, obj, old_obj_state, new_obj_state, i) { WARN_ON(obj->state != old_obj_state); diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 243cacb3575c..c157500b3135 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -638,6 +638,7 @@ static int drm_dev_init(struct drm_device *dev, mutex_init(&dev->filelist_mutex); mutex_init(&dev->clientlist_mutex); mutex_init(&dev->master_mutex); + raw_spin_lock_init(&dev->mode_config.panic_lock); ret = drmm_add_action_or_reset(dev, drm_dev_init_release, NULL); if (ret) diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h index 9d8acf7a10eb..06d7777a881f 100644 --- a/include/drm/drm_mode_config.h +++ b/include/drm/drm_mode_config.h @@ -505,6 +505,16 @@ struct drm_mode_config { */ struct list_head plane_list; + /** + * @panic_lock: + * + * Raw spinlock used to protect critical sections of code that access + * the display hardware or modeset software state, which the panic + * printing code must be protected against. See drm_panic_trylock(), + * drm_panic_lock() and drm_panic_unlock(). + */ + struct raw_spinlock panic_lock; + /** * @num_crtc: * diff --git a/include/drm/drm_panic.h b/include/drm/drm_panic.h new file mode 100644 index 000000000000..967e02ccc6d5 --- /dev/null +++ b/include/drm/drm_panic.h @@ -0,0 +1,95 @@ +/* SPDX-License-Identifier: GPL-2.0 or MIT */ +#ifndef __DRM_PANIC_H__ +#define __DRM_PANIC_H__ + +#include +/* + * Copyright (c) 2024 Intel + */ + +/** + * drm_panic_trylock - try to enter the panic printing critical section + * @dev: struct drm_device + * @flags: unsigned long irq flags you need to pass to the unlock() counterpart + * + * This function must be called by any panic printing code. The panic printing + * attempt must be aborted if the trylock fails. + * + * Panic printing code can make the following assumptions while holding the + * panic lock: + * + * - Anything protected by drm_panic_lock() and drm_panic_unlock() pairs is safe + * to access. + * + * - Furthermore the panic printing code only registers in drm_dev_unregister() + * and gets removed in drm_dev_unregister(). This allows the panic code to + * safely access any state which is invariant in between these two function + * calls, like the list of planes &drm_mode_config.plane_list or most of the + * struct drm_plane structure. + * + * Specifically thanks to the protection around plane updates in + * drm_atomic_helper_swap_state() the following additional guarantees hold: + * + * - It is safe to deference the drm_plane.state pointer. + * + * - Anything in struct drm_plane_state or the driver's subclass thereof which + * stays invariant after the atomic check code has finished is safe to access. + * Specifically this includes the reference counted pointers to framebuffer + * and buffer objects. + * + * - Anything set up by &drm_plane_helper_funcs.fb_prepare and cleaned up + * &drm_plane_helper_funcs.fb_cleanup is safe to access, as long as it stays + * invariant between these two calls. This also means that for drivers using + * dynamic buffer management the framebuffer is pinned, and therefer all + * relevant datastructures can be accessed without taking any further locks + * (which would be impossible in panic context anyway). + * + * - Importantly, software and hardware state set up by + * &drm_plane_helper_funcs.begin_fb_access and + * &drm_plane_helper_funcs.end_fb_access is not safe to access. + * + * Drivers must not make any assumptions about the actual state of the hardware, + * unless they explicitly protected these hardware access with drm_panic_lock() + * and drm_panic_unlock(). + * + * Return: + * %0 when failing to acquire the raw spinlock, nonzero on success. + */ +#define drm_panic_trylock(dev, flags) \ + raw_spin_trylock_irqsave(&(dev)->mode_config.panic_lock, flags) + +/** + * drm_panic_lock - protect panic printing relevant state + * @dev: struct drm_device + * @flags: unsigned long irq flags you need to pass to the unlock() counterpart + * + * This function must be called to protect software and hardware state that the + * panic printing code must be able to rely on. The protected sections must be + * as small as possible. It uses the irqsave/irqrestore variant, and can be + * called from irq handler. Examples include: + * + * - Access to peek/poke or other similar registers, if that is the way the + * driver prints the pixels into the scanout buffer at panic time. + * + * - Updates to pointers like &drm_plane.state, allowing the panic handler to + * safely deference these. This is done in drm_atomic_helper_swap_state(). + * + * - An state that isn't invariant and that the driver must be able to access + * during panic printing. + */ + +#define drm_panic_lock(dev, flags) \ + raw_spin_lock_irqsave(&(dev)->mode_config.panic_lock, flags) + +/** + * drm_panic_unlock - end of the panic printing critical section + * @dev: struct drm_device + * @flags: irq flags that were returned when acquiring the lock + * + * Unlocks the raw spinlock acquired by either drm_panic_lock() or + * drm_panic_trylock(). + */ +#define drm_panic_unlock(dev, flags) \ + raw_spin_unlock_irqrestore(&(dev)->mode_config.panic_lock, flags) + +#endif /* __DRM_PANIC_H__ */ -- cgit v1.2.3 From bf9fb17c6672868d95126321762c8fdfe0ff0a2a Mon Sep 17 00:00:00 2001 From: Jocelyn Falempe Date: Tue, 9 Apr 2024 18:30:41 +0200 Subject: drm/panic: Add a drm panic handler This module displays a user friendly message when a kernel panic occurs. It currently doesn't contain any debug information, but that can be added later. v2 * Use get_scanout_buffer() instead of the drm client API. (Thomas Zimmermann) * Add the panic reason to the panic message (Nerdopolis) * Add an exclamation mark (Nerdopolis) v3 * Rework the drawing functions, to write the pixels line by line and to use the drm conversion helper to support other formats. (Thomas Zimmermann) v4 * Use drm_fb_r1_to_32bit for fonts (Thomas Zimmermann) * Remove the default y to DRM_PANIC config option (Thomas Zimmermann) * Add foreground/background color config option * Fix the bottom lines not painted if the framebuffer height is not a multiple of the font height. * Automatically register the device to drm_panic, if the function get_scanout_buffer exists. (Thomas Zimmermann) v5 * Change the drawing API, use drm_fb_blit_from_r1() to draw the font. * Also add drm_fb_fill() to fill area with background color. * Add draw_pixel_xy() API for drivers that can't provide a linear buffer. * Add a flush() callback for drivers that needs to synchronize the buffer. * Add a void *private field, so drivers can pass private data to draw_pixel_xy() and flush(). v6 * Fix sparse warning for panic_msg and logo. v7 * Add select DRM_KMS_HELPER for the color conversion functions. v8 * Register directly each plane to the panic notifier (Sima) * Add raw_spinlock to properly handle concurrency (Sima) * Register plane instead of device, to avoid looping through plane list, and simplify code. * Replace get_scanout_buffer() logic with drm_panic_set_buffer() (Thomas Zimmermann) * Removed the draw_pixel_xy() API, will see later if it can be added back. v9 * Revert to using get_scanout_buffer() (Sima) * Move get_scanout_buffer() and panic_flush() to the plane helper functions (Thomas Zimmermann) * Register all planes with get_scanout_buffer() to the panic notifier * Use drm_panic_lock() to protect against race (Sima) v10 * Move blit and fill functions back in drm_panic (Thomas Zimmermann). * Simplify the text drawing functions. * Use kmsg_dumper instead of panic_notifier (Sima). v12 * Use array for map and pitch in struct drm_scanout_buffer to support multi-planar format later. (Thomas Zimmermann) * Better indent struct drm_scanout_buffer declaration. (Thomas Zimmermann) Signed-off-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20240409163432.352518-3-jfalempe@redhat.com Acked-by: Daniel Vetter --- Documentation/gpu/drm-kms.rst | 15 ++ drivers/gpu/drm/Kconfig | 23 +++ drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/drm_drv.c | 4 + drivers/gpu/drm/drm_panic.c | 290 +++++++++++++++++++++++++++++++ include/drm/drm_modeset_helper_vtables.h | 39 +++++ include/drm/drm_panic.h | 57 ++++++ include/drm/drm_plane.h | 6 + 8 files changed, 435 insertions(+) create mode 100644 drivers/gpu/drm/drm_panic.c (limited to 'include/drm') diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index b98b98359c90..abfe220764e1 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -398,6 +398,21 @@ Plane Damage Tracking Functions Reference .. kernel-doc:: include/drm/drm_damage_helper.h :internal: +Plane Panic Feature +------------------- + +.. kernel-doc:: drivers/gpu/drm/drm_panic.c + :doc: overview + +Plane Panic Functions Reference +------------------------------- + +.. kernel-doc:: include/drm/drm_panic.h + :internal: + +.. kernel-doc:: drivers/gpu/drm/drm_panic.c + :export: + Display Modes Function Reference ================================ diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 3914aaf443a8..f8a26423369e 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -104,6 +104,29 @@ config DRM_KMS_HELPER help CRTC helpers for KMS drivers. +config DRM_PANIC + bool "Display a user-friendly message when a kernel panic occurs" + depends on DRM && !FRAMEBUFFER_CONSOLE + select DRM_KMS_HELPER + select FONT_SUPPORT + help + Enable a drm panic handler, which will display a user-friendly message + when a kernel panic occurs. It's useful when using a user-space + console instead of fbcon. + It will only work if your graphic driver supports this feature. + To support Hi-DPI Display, you can enable bigger fonts like + FONT_TER16x32 + +config DRM_PANIC_FOREGROUND_COLOR + hex "Drm panic screen foreground color, in RGB" + depends on DRM_PANIC + default 0xffffff + +config DRM_PANIC_BACKGROUND_COLOR + hex "Drm panic screen background color, in RGB" + depends on DRM_PANIC + default 0x000000 + config DRM_DEBUG_DP_MST_TOPOLOGY_REFS bool "Enable refcount backtrace history in the DP MST helpers" depends on STACKTRACE_SUPPORT diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index a73c04d2d7a3..f9ca4f8fa6c5 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -88,6 +88,7 @@ drm-$(CONFIG_DRM_PRIVACY_SCREEN) += \ drm_privacy_screen.o \ drm_privacy_screen_x86.o drm-$(CONFIG_DRM_ACCEL) += ../../accel/drm_accel.o +drm-$(CONFIG_DRM_PANIC) += drm_panic.o obj-$(CONFIG_DRM) += drm.o obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index c157500b3135..535b624d4c9d 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -944,6 +945,7 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags) if (ret) goto err_unload; } + drm_panic_register(dev); DRM_INFO("Initialized %s %d.%d.%d %s for %s on minor %d\n", driver->name, driver->major, driver->minor, @@ -988,6 +990,8 @@ void drm_dev_unregister(struct drm_device *dev) { dev->registered = false; + drm_panic_unregister(dev); + drm_client_dev_unregister(dev); if (drm_core_check_feature(dev, DRIVER_MODESET)) diff --git a/drivers/gpu/drm/drm_panic.c b/drivers/gpu/drm/drm_panic.c new file mode 100644 index 000000000000..7c81b3d73239 --- /dev/null +++ b/drivers/gpu/drm/drm_panic.c @@ -0,0 +1,290 @@ +// SPDX-License-Identifier: GPL-2.0 or MIT +/* + * Copyright (c) 2023 Red Hat. + * Author: Jocelyn Falempe + * inspired by the drm_log driver from David Herrmann + * Tux Ascii art taken from cowsay written by Tony Monroe + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Jocelyn Falempe"); +MODULE_DESCRIPTION("DRM panic handler"); +MODULE_LICENSE("GPL"); + +/** + * DOC: overview + * + * To enable DRM panic for a driver, the primary plane must implement a + * &drm_plane_helper_funcs.get_scanout_buffer helper function. It is then + * automatically registered to the drm panic handler. + * When a panic occurs, the &drm_plane_helper_funcs.get_scanout_buffer will be + * called, and the driver can provide a framebuffer so the panic handler can + * draw the panic screen on it. Currently only linear buffer and a few color + * formats are supported. + * Optionally the driver can also provide a &drm_plane_helper_funcs.panic_flush + * callback, that will be called after that, to send additional commands to the + * hardware to make the scanout buffer visible. + */ + +/* + * This module displays a user friendly message on screen when a kernel panic + * occurs. This is conflicting with fbcon, so you can only enable it when fbcon + * is disabled. + * It's intended for end-user, so have minimal technical/debug information. + * + * Implementation details: + * + * It is a panic handler, so it can't take lock, allocate memory, run tasks/irq, + * or attempt to sleep. It's a best effort, and it may not be able to display + * the message in all situations (like if the panic occurs in the middle of a + * modesetting). + * It will display only one static frame, so performance optimizations are low + * priority as the machine is already in an unusable state. + */ + +struct drm_panic_line { + u32 len; + const char *txt; +}; + +#define PANIC_LINE(s) {.len = sizeof(s) - 1, .txt = s} + +static struct drm_panic_line panic_msg[] = { + PANIC_LINE("KERNEL PANIC !"), + PANIC_LINE(""), + PANIC_LINE("Please reboot your computer."), +}; + +static const struct drm_panic_line logo[] = { + PANIC_LINE(" .--. _"), + PANIC_LINE(" |o_o | | |"), + PANIC_LINE(" |:_/ | | |"), + PANIC_LINE(" // \\ \\ |_|"), + PANIC_LINE(" (| | ) _"), + PANIC_LINE(" /'\\_ _/`\\ (_)"), + PANIC_LINE(" \\___)=(___/"), +}; + +static void drm_panic_fill32(struct iosys_map *map, unsigned int pitch, + unsigned int height, unsigned int width, + u32 color) +{ + unsigned int y, x; + + for (y = 0; y < height; y++) + for (x = 0; x < width; x++) + iosys_map_wr(map, y * pitch + x * sizeof(u32), u32, color); +} + +static void drm_panic_blit32(struct iosys_map *dmap, unsigned int dpitch, + const u8 *sbuf8, unsigned int spitch, + unsigned int height, unsigned int width, + u32 fg32, u32 bg32) +{ + unsigned int y, x; + u32 val32; + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + val32 = (sbuf8[(y * spitch) + x / 8] & (0x80 >> (x % 8))) ? fg32 : bg32; + iosys_map_wr(dmap, y * dpitch + x * sizeof(u32), u32, val32); + } + } +} + +static const u8 *get_char_bitmap(const struct font_desc *font, char c, size_t font_pitch) +{ + return font->data + (c * font->height) * font_pitch; +} + +static unsigned int get_max_line_len(const struct drm_panic_line *lines, int len) +{ + int i; + unsigned int max = 0; + + for (i = 0; i < len; i++) + max = max(lines[i].len, max); + return max; +} + +/* + * Draw a text in a rectangle on a framebuffer. The text is truncated if it overflows the rectangle + */ +static void draw_txt_rectangle(struct drm_scanout_buffer *sb, + const struct font_desc *font, + const struct drm_panic_line *msg, + unsigned int msg_lines, + bool centered, + struct drm_rect *clip, + u32 fg_color, + u32 bg_color) +{ + int i, j; + const u8 *src; + size_t font_pitch = DIV_ROUND_UP(font->width, 8); + struct iosys_map dst; + unsigned int px_width = sb->format->cpp[0]; + int left = 0; + + msg_lines = min(msg_lines, drm_rect_height(clip) / font->height); + for (i = 0; i < msg_lines; i++) { + size_t line_len = min(msg[i].len, drm_rect_width(clip) / font->width); + + if (centered) + left = (drm_rect_width(clip) - (line_len * font->width)) / 2; + + dst = sb->map[0]; + iosys_map_incr(&dst, (clip->y1 + i * font->height) * sb->pitch[0] + + (clip->x1 + left) * px_width); + for (j = 0; j < line_len; j++) { + src = get_char_bitmap(font, msg[i].txt[j], font_pitch); + drm_panic_blit32(&dst, sb->pitch[0], src, font_pitch, + font->height, font->width, + fg_color, bg_color); + iosys_map_incr(&dst, font->width * px_width); + } + } +} + +/* + * Draw the panic message at the center of the screen + */ +static void draw_panic_static(struct drm_scanout_buffer *sb) +{ + size_t msg_lines = ARRAY_SIZE(panic_msg); + size_t logo_lines = ARRAY_SIZE(logo); + u32 fg_color = CONFIG_DRM_PANIC_FOREGROUND_COLOR; + u32 bg_color = CONFIG_DRM_PANIC_BACKGROUND_COLOR; + const struct font_desc *font = get_default_font(sb->width, sb->height, NULL, NULL); + struct drm_rect r_logo, r_msg; + + if (!font) + return; + + r_logo = DRM_RECT_INIT(0, 0, + get_max_line_len(logo, logo_lines) * font->width, + logo_lines * font->height); + r_msg = DRM_RECT_INIT(0, 0, + min(get_max_line_len(panic_msg, msg_lines) * font->width, sb->width), + min(msg_lines * font->height, sb->height)); + + /* Center the panic message */ + drm_rect_translate(&r_msg, (sb->width - r_msg.x2) / 2, (sb->height - r_msg.y2) / 2); + + /* Fill with the background color, and draw text on top */ + drm_panic_fill32(&sb->map[0], sb->pitch[0], sb->height, sb->width, bg_color); + + if ((r_msg.x1 >= drm_rect_width(&r_logo) || r_msg.y1 >= drm_rect_height(&r_logo)) && + drm_rect_width(&r_logo) < sb->width && drm_rect_height(&r_logo) < sb->height) { + draw_txt_rectangle(sb, font, logo, logo_lines, false, &r_logo, fg_color, bg_color); + } + draw_txt_rectangle(sb, font, panic_msg, msg_lines, true, &r_msg, fg_color, bg_color); +} + +/* + * drm_panic_is_format_supported() + * @format: a fourcc color code + * Returns: true if supported, false otherwise. + * + * Check if drm_panic will be able to use this color format. + */ +static bool drm_panic_is_format_supported(const struct drm_format_info *format) +{ + if (format->num_planes != 1) + return false; + return format->format == DRM_FORMAT_XRGB8888; +} + +static void draw_panic_plane(struct drm_plane *plane) +{ + struct drm_scanout_buffer sb; + int ret; + unsigned long flags; + + if (!drm_panic_trylock(plane->dev, flags)) + return; + + ret = plane->helper_private->get_scanout_buffer(plane, &sb); + + if (!ret && drm_panic_is_format_supported(sb.format)) { + draw_panic_static(&sb); + if (plane->helper_private->panic_flush) + plane->helper_private->panic_flush(plane); + } + drm_panic_unlock(plane->dev, flags); +} + +static struct drm_plane *to_drm_plane(struct kmsg_dumper *kd) +{ + return container_of(kd, struct drm_plane, kmsg_panic); +} + +static void drm_panic(struct kmsg_dumper *dumper, enum kmsg_dump_reason reason) +{ + struct drm_plane *plane = to_drm_plane(dumper); + + if (reason == KMSG_DUMP_PANIC) + draw_panic_plane(plane); +} + +/** + * drm_panic_register() - Initialize DRM panic for a device + * @dev: the drm device on which the panic screen will be displayed. + */ +void drm_panic_register(struct drm_device *dev) +{ + struct drm_plane *plane; + int registered_plane = 0; + + if (!dev->mode_config.num_total_plane) + return; + + drm_for_each_plane(plane, dev) { + if (!plane->helper_private || !plane->helper_private->get_scanout_buffer) + continue; + plane->kmsg_panic.dump = drm_panic; + plane->kmsg_panic.max_reason = KMSG_DUMP_PANIC; + if (kmsg_dump_register(&plane->kmsg_panic)) + drm_warn(dev, "Failed to register panic handler\n"); + else + registered_plane++; + } + if (registered_plane) + drm_info(dev, "Registered %d planes with drm panic\n", registered_plane); +} +EXPORT_SYMBOL(drm_panic_register); + +/** + * drm_panic_unregister() + * @dev: the drm device previously registered. + */ +void drm_panic_unregister(struct drm_device *dev) +{ + struct drm_plane *plane; + + if (!dev->mode_config.num_total_plane) + return; + + drm_for_each_plane(plane, dev) { + if (!plane->helper_private || !plane->helper_private->get_scanout_buffer) + continue; + kmsg_dump_unregister(&plane->kmsg_panic); + } +} +EXPORT_SYMBOL(drm_panic_unregister); diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h index 9ed42469540e..ec59015aec3c 100644 --- a/include/drm/drm_modeset_helper_vtables.h +++ b/include/drm/drm_modeset_helper_vtables.h @@ -48,6 +48,7 @@ * To make this clear all the helper vtables are pulled together in this location here. */ +struct drm_scanout_buffer; struct drm_writeback_connector; struct drm_writeback_job; @@ -1443,6 +1444,44 @@ struct drm_plane_helper_funcs { */ void (*atomic_async_update)(struct drm_plane *plane, struct drm_atomic_state *state); + + /** + * @get_scanout_buffer: + * + * Get the current scanout buffer, to display a message with drm_panic. + * The driver should do the minimum changes to provide a buffer, + * that can be used to display the panic screen. Currently only linear + * buffers are supported. Non-linear buffer support is on the TODO list. + * The device &dev.mode_config.panic_lock is taken before calling this + * function, so you can safely access the &plane.state + * It is called from a panic callback, and must follow its restrictions. + * Please look the documentation at drm_panic_trylock() for an in-depth + * discussions of what's safe and what is not allowed. + * It's a best effort mode, so it's expected that in some complex cases + * the panic screen won't be displayed. + * The returned &drm_scanout_buffer.map must be valid if no error code is + * returned. + * + * Return: + * %0 on success, negative errno on failure. + */ + int (*get_scanout_buffer)(struct drm_plane *plane, + struct drm_scanout_buffer *sb); + + /** + * @panic_flush: + * + * It is used by drm_panic, and is called after the panic screen is + * drawn to the scanout buffer. In this function, the driver + * can send additional commands to the hardware, to make the scanout + * buffer visible. + * It is only called if get_scanout_buffer() returned successfully, and + * the &dev.mode_config.panic_lock is held during the entire sequence. + * It is called from a panic callback, and must follow its restrictions. + * Please look the documentation at drm_panic_trylock() for an in-depth + * discussions of what's safe and what is not allowed. + */ + void (*panic_flush)(struct drm_plane *plane); }; /** diff --git a/include/drm/drm_panic.h b/include/drm/drm_panic.h index 967e02ccc6d5..822dbb1aa9d6 100644 --- a/include/drm/drm_panic.h +++ b/include/drm/drm_panic.h @@ -2,11 +2,56 @@ #ifndef __DRM_PANIC_H__ #define __DRM_PANIC_H__ +#include +#include +#include + #include +#include /* * Copyright (c) 2024 Intel */ +/** + * struct drm_scanout_buffer - DRM scanout buffer + * + * This structure holds the information necessary for drm_panic to draw the + * panic screen, and display it. + */ +struct drm_scanout_buffer { + /** + * @format: + * + * drm format of the scanout buffer. + */ + const struct drm_format_info *format; + + /** + * @map: + * + * Virtual address of the scanout buffer, either in memory or iomem. + * The scanout buffer should be in linear format, and can be directly + * sent to the display hardware. Tearing is not an issue for the panic + * screen. + */ + struct iosys_map map[DRM_FORMAT_MAX_PLANES]; + + /** + * @width: Width of the scanout buffer, in pixels. + */ + unsigned int width; + + /** + * @height: Height of the scanout buffer, in pixels. + */ + unsigned int height; + + /** + * @pitch: Length in bytes between the start of two consecutive lines. + */ + unsigned int pitch[DRM_FORMAT_MAX_PLANES]; +}; + /** * drm_panic_trylock - try to enter the panic printing critical section * @dev: struct drm_device @@ -92,4 +137,16 @@ #define drm_panic_unlock(dev, flags) \ raw_spin_unlock_irqrestore(&(dev)->mode_config.panic_lock, flags) +#ifdef CONFIG_DRM_PANIC + +void drm_panic_register(struct drm_device *dev); +void drm_panic_unregister(struct drm_device *dev); + +#else + +static inline void drm_panic_register(struct drm_device *dev) {} +static inline void drm_panic_unregister(struct drm_device *dev) {} + +#endif + #endif /* __DRM_PANIC_H__ */ diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index ec1112208b73..9507542121fa 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -780,6 +781,11 @@ struct drm_plane { * @hotspot_y_property: property to set mouse hotspot y offset. */ struct drm_property *hotspot_y_property; + + /** + * @kmsg_panic: Used to register a panic notifier for this plane + */ + struct kmsg_dumper kmsg_panic; }; #define obj_to_plane(x) container_of(x, struct drm_plane, base) -- cgit v1.2.3 From 879b3b6511fe92b1b93dfc543961347289a8aeaa Mon Sep 17 00:00:00 2001 From: Jocelyn Falempe Date: Tue, 9 Apr 2024 18:30:44 +0200 Subject: drm/fb_dma: Add generic get_scanout_buffer() for drm_panic This was initialy done for imx6, but should work on most drivers using drm_fb_dma_helper. v8: * Replace get_scanout_buffer() logic with drm_panic_set_buffer() (Thomas Zimmermann) v9: * go back to get_scanout_buffer() * move get_scanout_buffer() to plane helper functions v12: * Rename drm_panic_gem_get_scanout_buffer to drm_fb_dma_get_scanout_buffer (Thomas Zimmermann) * Remove the #ifdef CONFIG_DRM_PANIC, and build it unconditionnaly, as it's a small function. (Thomas Zimmermann) Signed-off-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20240409163432.352518-6-jfalempe@redhat.com Acked-by: Daniel Vetter --- drivers/gpu/drm/drm_fb_dma_helper.c | 42 +++++++++++++++++++++++++++++++++++++ include/drm/drm_fb_dma_helper.h | 4 ++++ 2 files changed, 46 insertions(+) (limited to 'include/drm') diff --git a/drivers/gpu/drm/drm_fb_dma_helper.c b/drivers/gpu/drm/drm_fb_dma_helper.c index 3b535ad1b07c..c79b5078303f 100644 --- a/drivers/gpu/drm/drm_fb_dma_helper.c +++ b/drivers/gpu/drm/drm_fb_dma_helper.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -148,3 +149,44 @@ void drm_fb_dma_sync_non_coherent(struct drm_device *drm, } } EXPORT_SYMBOL_GPL(drm_fb_dma_sync_non_coherent); + +/** + * drm_fb_dma_get_scanout_buffer - Provide a scanout buffer in case of panic + * @plane: DRM primary plane + * @drm_scanout_buffer: scanout buffer for the panic handler + * Returns: 0 or negative error code + * + * Generic get_scanout_buffer() implementation, for drivers that uses the + * drm_fb_dma_helper. It won't call vmap in the panic context, so the driver + * should make sure the primary plane is vmapped, otherwise the panic screen + * won't get displayed. + */ +int drm_fb_dma_get_scanout_buffer(struct drm_plane *plane, + struct drm_scanout_buffer *sb) +{ + struct drm_gem_dma_object *dma_obj; + struct drm_framebuffer *fb; + + fb = plane->state->fb; + /* Only support linear modifier */ + if (fb->modifier != DRM_FORMAT_MOD_LINEAR) + return -ENODEV; + + dma_obj = drm_fb_dma_get_gem_obj(fb, 0); + + /* Buffer should be accessible from the CPU */ + if (dma_obj->base.import_attach) + return -ENODEV; + + /* Buffer should be already mapped to CPU */ + if (!dma_obj->vaddr) + return -ENODEV; + + iosys_map_set_vaddr(&sb->map[0], dma_obj->vaddr); + sb->format = fb->format; + sb->height = fb->height; + sb->width = fb->width; + sb->pitch[0] = fb->pitches[0]; + return 0; +} +EXPORT_SYMBOL(drm_fb_dma_get_scanout_buffer); diff --git a/include/drm/drm_fb_dma_helper.h b/include/drm/drm_fb_dma_helper.h index d5e036c57801..61f24c2aba2f 100644 --- a/include/drm/drm_fb_dma_helper.h +++ b/include/drm/drm_fb_dma_helper.h @@ -7,6 +7,7 @@ struct drm_device; struct drm_framebuffer; struct drm_plane_state; +struct drm_scanout_buffer; struct drm_gem_dma_object *drm_fb_dma_get_gem_obj(struct drm_framebuffer *fb, unsigned int plane); @@ -19,5 +20,8 @@ void drm_fb_dma_sync_non_coherent(struct drm_device *drm, struct drm_plane_state *old_state, struct drm_plane_state *state); +int drm_panic_gem_get_scanout_buffer(struct drm_plane *plane, + struct drm_scanout_buffer *sb); + #endif -- cgit v1.2.3 From d894ea562f7ac908bf848bf15e1cfab503da71a9 Mon Sep 17 00:00:00 2001 From: Maíra Canal Date: Mon, 15 Apr 2024 12:09:53 -0300 Subject: drm/fb_dma: s/drm_panic_gem_get_scanout_buffer/drm_fb_dma_get_scanout_buffer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On version 11 of the "drm/panic: Add a drm panic handler" series [1], Thomas suggested to change the name of the function `drm_panic_gem_get_scanout_buffer` to `drm_fb_dma_get_scanout_buffer` and this request was applied on version 12, which is the version that landed [2]. Although the name of the function changed on the C file, it didn't changed on the header file, leading to a compilation error as such: drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c:780:24: error: use of undeclared identifier 'drm_fb_dma_get_scanout_buffer'; did you mean 'drm_panic_gem_get_scanout_buffer'? 780 | .get_scanout_buffer = drm_fb_dma_get_scanout_buffer, | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | drm_panic_gem_get_scanout_buffer ./include/drm/drm_fb_dma_helper.h:23:5: note: 'drm_panic_gem_get_scanout_buffer' declared here 23 | int drm_panic_gem_get_scanout_buffer(struct drm_plane *plane, | ^ 1 error generated. Fix the compilation error by changing `drm_panic_gem_get_scanout_buffer` to `drm_fb_dma_get_scanout_buffer` on the header file. Link: https://lore.kernel.org/dri-devel/20240328120638.468738-1-jfalempe@redhat.com/ [1] Link: https://lore.kernel.org/dri-devel/aea2aa01-7f03-453b-8b30-8f4d90b1b47f@redhat.com/ [2] Fixes: 879b3b6511fe ("drm/fb_dma: Add generic get_scanout_buffer() for drm_panic") Signed-off-by: Maíra Canal Reviewed-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20240415151013.3210278-1-mcanal@igalia.com --- include/drm/drm_fb_dma_helper.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'include/drm') diff --git a/include/drm/drm_fb_dma_helper.h b/include/drm/drm_fb_dma_helper.h index 61f24c2aba2f..c950732c6d36 100644 --- a/include/drm/drm_fb_dma_helper.h +++ b/include/drm/drm_fb_dma_helper.h @@ -6,6 +6,7 @@ struct drm_device; struct drm_framebuffer; +struct drm_plane; struct drm_plane_state; struct drm_scanout_buffer; @@ -20,8 +21,8 @@ void drm_fb_dma_sync_non_coherent(struct drm_device *drm, struct drm_plane_state *old_state, struct drm_plane_state *state); -int drm_panic_gem_get_scanout_buffer(struct drm_plane *plane, - struct drm_scanout_buffer *sb); +int drm_fb_dma_get_scanout_buffer(struct drm_plane *plane, + struct drm_scanout_buffer *sb); #endif -- cgit v1.2.3 From 44e030d8a5a1be503301a0f095416c5ebb93c9e6 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 16 Apr 2024 12:19:54 +0300 Subject: drm/displayid: move drm_displayid.h to drm_displayd_internal.h There are no exported symbols for displayid, and it's all internal interfaces. Move the header to drivers/gpu/drm/drm_displayd_internal.h. Reviewed-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/220713d4e3cc364ac103ba689065ae96e075f1fa.1713259151.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/drm_displayid.c | 3 +- drivers/gpu/drm/drm_displayid_internal.h | 171 +++++++++++++++++++++++++++++++ drivers/gpu/drm/drm_edid.c | 2 +- include/drm/drm_displayid.h | 170 ------------------------------ 4 files changed, 174 insertions(+), 172 deletions(-) create mode 100644 drivers/gpu/drm/drm_displayid_internal.h delete mode 100644 include/drm/drm_displayid.h (limited to 'include/drm') diff --git a/drivers/gpu/drm/drm_displayid.c b/drivers/gpu/drm/drm_displayid.c index 9edc111be7ee..f72a893c7deb 100644 --- a/drivers/gpu/drm/drm_displayid.c +++ b/drivers/gpu/drm/drm_displayid.c @@ -3,10 +3,11 @@ * Copyright © 2021 Intel Corporation */ -#include #include #include +#include "drm_displayid_internal.h" + static const struct displayid_header * displayid_get_header(const u8 *displayid, int length, int index) { diff --git a/drivers/gpu/drm/drm_displayid_internal.h b/drivers/gpu/drm/drm_displayid_internal.h new file mode 100644 index 000000000000..56fd3bb0a779 --- /dev/null +++ b/drivers/gpu/drm/drm_displayid_internal.h @@ -0,0 +1,171 @@ +/* + * Copyright © 2014 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __DRM_DISPLAYID_INTERNAL_H__ +#define __DRM_DISPLAYID_INTERNAL_H__ + +#include +#include + +struct drm_edid; + +#define VESA_IEEE_OUI 0x3a0292 + +/* DisplayID Structure versions */ +#define DISPLAY_ID_STRUCTURE_VER_12 0x12 +#define DISPLAY_ID_STRUCTURE_VER_20 0x20 + +/* DisplayID Structure v1r2 Data Blocks */ +#define DATA_BLOCK_PRODUCT_ID 0x00 +#define DATA_BLOCK_DISPLAY_PARAMETERS 0x01 +#define DATA_BLOCK_COLOR_CHARACTERISTICS 0x02 +#define DATA_BLOCK_TYPE_1_DETAILED_TIMING 0x03 +#define DATA_BLOCK_TYPE_2_DETAILED_TIMING 0x04 +#define DATA_BLOCK_TYPE_3_SHORT_TIMING 0x05 +#define DATA_BLOCK_TYPE_4_DMT_TIMING 0x06 +#define DATA_BLOCK_VESA_TIMING 0x07 +#define DATA_BLOCK_CEA_TIMING 0x08 +#define DATA_BLOCK_VIDEO_TIMING_RANGE 0x09 +#define DATA_BLOCK_PRODUCT_SERIAL_NUMBER 0x0a +#define DATA_BLOCK_GP_ASCII_STRING 0x0b +#define DATA_BLOCK_DISPLAY_DEVICE_DATA 0x0c +#define DATA_BLOCK_INTERFACE_POWER_SEQUENCING 0x0d +#define DATA_BLOCK_TRANSFER_CHARACTERISTICS 0x0e +#define DATA_BLOCK_DISPLAY_INTERFACE 0x0f +#define DATA_BLOCK_STEREO_DISPLAY_INTERFACE 0x10 +#define DATA_BLOCK_TILED_DISPLAY 0x12 +#define DATA_BLOCK_VENDOR_SPECIFIC 0x7f +#define DATA_BLOCK_CTA 0x81 + +/* DisplayID Structure v2r0 Data Blocks */ +#define DATA_BLOCK_2_PRODUCT_ID 0x20 +#define DATA_BLOCK_2_DISPLAY_PARAMETERS 0x21 +#define DATA_BLOCK_2_TYPE_7_DETAILED_TIMING 0x22 +#define DATA_BLOCK_2_TYPE_8_ENUMERATED_TIMING 0x23 +#define DATA_BLOCK_2_TYPE_9_FORMULA_TIMING 0x24 +#define DATA_BLOCK_2_DYNAMIC_VIDEO_TIMING 0x25 +#define DATA_BLOCK_2_DISPLAY_INTERFACE_FEATURES 0x26 +#define DATA_BLOCK_2_STEREO_DISPLAY_INTERFACE 0x27 +#define DATA_BLOCK_2_TILED_DISPLAY_TOPOLOGY 0x28 +#define DATA_BLOCK_2_CONTAINER_ID 0x29 +#define DATA_BLOCK_2_VENDOR_SPECIFIC 0x7e +#define DATA_BLOCK_2_CTA_DISPLAY_ID 0x81 + +/* DisplayID Structure v1r2 Product Type */ +#define PRODUCT_TYPE_EXTENSION 0 +#define PRODUCT_TYPE_TEST 1 +#define PRODUCT_TYPE_PANEL 2 +#define PRODUCT_TYPE_MONITOR 3 +#define PRODUCT_TYPE_TV 4 +#define PRODUCT_TYPE_REPEATER 5 +#define PRODUCT_TYPE_DIRECT_DRIVE 6 + +/* DisplayID Structure v2r0 Display Product Primary Use Case (~Product Type) */ +#define PRIMARY_USE_EXTENSION 0 +#define PRIMARY_USE_TEST 1 +#define PRIMARY_USE_GENERIC 2 +#define PRIMARY_USE_TV 3 +#define PRIMARY_USE_DESKTOP_PRODUCTIVITY 4 +#define PRIMARY_USE_DESKTOP_GAMING 5 +#define PRIMARY_USE_PRESENTATION 6 +#define PRIMARY_USE_HEAD_MOUNTED_VR 7 +#define PRIMARY_USE_HEAD_MOUNTED_AR 8 + +struct displayid_header { + u8 rev; + u8 bytes; + u8 prod_id; + u8 ext_count; +} __packed; + +struct displayid_block { + u8 tag; + u8 rev; + u8 num_bytes; +} __packed; + +struct displayid_tiled_block { + struct displayid_block base; + u8 tile_cap; + u8 topo[3]; + u8 tile_size[4]; + u8 tile_pixel_bezel[5]; + u8 topology_id[8]; +} __packed; + +struct displayid_detailed_timings_1 { + u8 pixel_clock[3]; + u8 flags; + u8 hactive[2]; + u8 hblank[2]; + u8 hsync[2]; + u8 hsw[2]; + u8 vactive[2]; + u8 vblank[2]; + u8 vsync[2]; + u8 vsw[2]; +} __packed; + +struct displayid_detailed_timing_block { + struct displayid_block base; + struct displayid_detailed_timings_1 timings[]; +}; + +#define DISPLAYID_VESA_MSO_OVERLAP GENMASK(3, 0) +#define DISPLAYID_VESA_MSO_MODE GENMASK(6, 5) + +struct displayid_vesa_vendor_specific_block { + struct displayid_block base; + u8 oui[3]; + u8 data_structure_type; + u8 mso; +} __packed; + +/* + * DisplayID iteration. + * + * Do not access directly, this is private. + */ +struct displayid_iter { + const struct drm_edid *drm_edid; + + const u8 *section; + int length; + int idx; + int ext_index; + + u8 version; + u8 primary_use; +}; + +void displayid_iter_edid_begin(const struct drm_edid *drm_edid, + struct displayid_iter *iter); +const struct displayid_block * +__displayid_iter_next(struct displayid_iter *iter); +#define displayid_iter_for_each(__block, __iter) \ + while (((__block) = __displayid_iter_next(__iter))) +void displayid_iter_end(struct displayid_iter *iter); + +u8 displayid_version(const struct displayid_iter *iter); +u8 displayid_primary_use(const struct displayid_iter *iter); + +#endif diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 1400722ae3fe..c4f799059522 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -40,7 +40,6 @@ #include #include -#include #include #include #include @@ -48,6 +47,7 @@ #include #include "drm_crtc_internal.h" +#include "drm_displayid_internal.h" #include "drm_internal.h" static int oui(u8 first, u8 second, u8 third) diff --git a/include/drm/drm_displayid.h b/include/drm/drm_displayid.h deleted file mode 100644 index 566497eeb3b8..000000000000 --- a/include/drm/drm_displayid.h +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright © 2014 Red Hat Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ -#ifndef DRM_DISPLAYID_H -#define DRM_DISPLAYID_H - -#include -#include - -struct drm_edid; - -#define VESA_IEEE_OUI 0x3a0292 - -/* DisplayID Structure versions */ -#define DISPLAY_ID_STRUCTURE_VER_12 0x12 -#define DISPLAY_ID_STRUCTURE_VER_20 0x20 - -/* DisplayID Structure v1r2 Data Blocks */ -#define DATA_BLOCK_PRODUCT_ID 0x00 -#define DATA_BLOCK_DISPLAY_PARAMETERS 0x01 -#define DATA_BLOCK_COLOR_CHARACTERISTICS 0x02 -#define DATA_BLOCK_TYPE_1_DETAILED_TIMING 0x03 -#define DATA_BLOCK_TYPE_2_DETAILED_TIMING 0x04 -#define DATA_BLOCK_TYPE_3_SHORT_TIMING 0x05 -#define DATA_BLOCK_TYPE_4_DMT_TIMING 0x06 -#define DATA_BLOCK_VESA_TIMING 0x07 -#define DATA_BLOCK_CEA_TIMING 0x08 -#define DATA_BLOCK_VIDEO_TIMING_RANGE 0x09 -#define DATA_BLOCK_PRODUCT_SERIAL_NUMBER 0x0a -#define DATA_BLOCK_GP_ASCII_STRING 0x0b -#define DATA_BLOCK_DISPLAY_DEVICE_DATA 0x0c -#define DATA_BLOCK_INTERFACE_POWER_SEQUENCING 0x0d -#define DATA_BLOCK_TRANSFER_CHARACTERISTICS 0x0e -#define DATA_BLOCK_DISPLAY_INTERFACE 0x0f -#define DATA_BLOCK_STEREO_DISPLAY_INTERFACE 0x10 -#define DATA_BLOCK_TILED_DISPLAY 0x12 -#define DATA_BLOCK_VENDOR_SPECIFIC 0x7f -#define DATA_BLOCK_CTA 0x81 - -/* DisplayID Structure v2r0 Data Blocks */ -#define DATA_BLOCK_2_PRODUCT_ID 0x20 -#define DATA_BLOCK_2_DISPLAY_PARAMETERS 0x21 -#define DATA_BLOCK_2_TYPE_7_DETAILED_TIMING 0x22 -#define DATA_BLOCK_2_TYPE_8_ENUMERATED_TIMING 0x23 -#define DATA_BLOCK_2_TYPE_9_FORMULA_TIMING 0x24 -#define DATA_BLOCK_2_DYNAMIC_VIDEO_TIMING 0x25 -#define DATA_BLOCK_2_DISPLAY_INTERFACE_FEATURES 0x26 -#define DATA_BLOCK_2_STEREO_DISPLAY_INTERFACE 0x27 -#define DATA_BLOCK_2_TILED_DISPLAY_TOPOLOGY 0x28 -#define DATA_BLOCK_2_CONTAINER_ID 0x29 -#define DATA_BLOCK_2_VENDOR_SPECIFIC 0x7e -#define DATA_BLOCK_2_CTA_DISPLAY_ID 0x81 - -/* DisplayID Structure v1r2 Product Type */ -#define PRODUCT_TYPE_EXTENSION 0 -#define PRODUCT_TYPE_TEST 1 -#define PRODUCT_TYPE_PANEL 2 -#define PRODUCT_TYPE_MONITOR 3 -#define PRODUCT_TYPE_TV 4 -#define PRODUCT_TYPE_REPEATER 5 -#define PRODUCT_TYPE_DIRECT_DRIVE 6 - -/* DisplayID Structure v2r0 Display Product Primary Use Case (~Product Type) */ -#define PRIMARY_USE_EXTENSION 0 -#define PRIMARY_USE_TEST 1 -#define PRIMARY_USE_GENERIC 2 -#define PRIMARY_USE_TV 3 -#define PRIMARY_USE_DESKTOP_PRODUCTIVITY 4 -#define PRIMARY_USE_DESKTOP_GAMING 5 -#define PRIMARY_USE_PRESENTATION 6 -#define PRIMARY_USE_HEAD_MOUNTED_VR 7 -#define PRIMARY_USE_HEAD_MOUNTED_AR 8 - -struct displayid_header { - u8 rev; - u8 bytes; - u8 prod_id; - u8 ext_count; -} __packed; - -struct displayid_block { - u8 tag; - u8 rev; - u8 num_bytes; -} __packed; - -struct displayid_tiled_block { - struct displayid_block base; - u8 tile_cap; - u8 topo[3]; - u8 tile_size[4]; - u8 tile_pixel_bezel[5]; - u8 topology_id[8]; -} __packed; - -struct displayid_detailed_timings_1 { - u8 pixel_clock[3]; - u8 flags; - u8 hactive[2]; - u8 hblank[2]; - u8 hsync[2]; - u8 hsw[2]; - u8 vactive[2]; - u8 vblank[2]; - u8 vsync[2]; - u8 vsw[2]; -} __packed; - -struct displayid_detailed_timing_block { - struct displayid_block base; - struct displayid_detailed_timings_1 timings[]; -}; - -#define DISPLAYID_VESA_MSO_OVERLAP GENMASK(3, 0) -#define DISPLAYID_VESA_MSO_MODE GENMASK(6, 5) - -struct displayid_vesa_vendor_specific_block { - struct displayid_block base; - u8 oui[3]; - u8 data_structure_type; - u8 mso; -} __packed; - -/* - * DisplayID iteration. - * - * Do not access directly, this is private. - */ -struct displayid_iter { - const struct drm_edid *drm_edid; - - const u8 *section; - int length; - int idx; - int ext_index; - - u8 version; - u8 primary_use; -}; - -void displayid_iter_edid_begin(const struct drm_edid *drm_edid, - struct displayid_iter *iter); -const struct displayid_block * -__displayid_iter_next(struct displayid_iter *iter); -#define displayid_iter_for_each(__block, __iter) \ - while (((__block) = __displayid_iter_next(__iter))) -void displayid_iter_end(struct displayid_iter *iter); - -u8 displayid_version(const struct displayid_iter *iter); -u8 displayid_primary_use(const struct displayid_iter *iter); - -#endif -- cgit v1.2.3 From 4e765920eeb91861a42cbc89036dedd3f7d27eef Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 16 Apr 2024 12:19:55 +0300 Subject: drm/edid: move all internal declarations to drm_crtc_internal.h The declarations for internal EDID functions are a bit scattered. Put them all in drm_crtc_internal.h. Reviewed-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/9ae137ea51f9cc2ccb3899b0acda553e6a8ce2db.1713259151.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/drm_crtc_internal.h | 6 ++++++ drivers/gpu/drm/drm_displayid.c | 1 + drivers/gpu/drm/drm_eld.c | 4 +++- drivers/gpu/drm/drm_internal.h | 5 ----- include/drm/drm_edid.h | 3 --- 5 files changed, 10 insertions(+), 9 deletions(-) (limited to 'include/drm') diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index 0c693229a1c9..2256893d7d67 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -43,12 +43,14 @@ enum drm_color_range; enum drm_connector_force; enum drm_mode_status; +struct cea_sad; struct drm_atomic_state; struct drm_bridge; struct drm_connector; struct drm_crtc; struct drm_device; struct drm_display_mode; +struct drm_edid; struct drm_file; struct drm_framebuffer; struct drm_mode_create_dumb; @@ -297,6 +299,10 @@ void drm_mode_fixup_1366x768(struct drm_display_mode *mode); int drm_edid_override_show(struct drm_connector *connector, struct seq_file *m); int drm_edid_override_set(struct drm_connector *connector, const void *edid, size_t size); int drm_edid_override_reset(struct drm_connector *connector); +const u8 *drm_find_edid_extension(const struct drm_edid *drm_edid, + int ext_id, int *ext_index); +void drm_edid_cta_sad_get(const struct cea_sad *cta_sad, u8 *sad); +void drm_edid_cta_sad_set(struct cea_sad *cta_sad, const u8 *sad); /* drm_edid_load.c */ #ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE diff --git a/drivers/gpu/drm/drm_displayid.c b/drivers/gpu/drm/drm_displayid.c index f72a893c7deb..f800dc0906d5 100644 --- a/drivers/gpu/drm/drm_displayid.c +++ b/drivers/gpu/drm/drm_displayid.c @@ -6,6 +6,7 @@ #include #include +#include "drm_crtc_internal.h" #include "drm_displayid_internal.h" static const struct displayid_header * diff --git a/drivers/gpu/drm/drm_eld.c b/drivers/gpu/drm/drm_eld.c index 5177991aa272..c0428d07de53 100644 --- a/drivers/gpu/drm/drm_eld.c +++ b/drivers/gpu/drm/drm_eld.c @@ -3,10 +3,12 @@ * Copyright © 2023 Intel Corporation */ +#include + #include #include -#include "drm_internal.h" +#include "drm_crtc_internal.h" /** * drm_eld_sad_get - get SAD from ELD to struct cea_sad diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index 2215baef9a3e..690505a1f7a5 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h @@ -35,7 +35,6 @@ #define DRM_IF_VERSION(maj, min) (maj << 16 | min) -struct cea_sad; struct dentry; struct dma_buf; struct iosys_map; @@ -278,8 +277,4 @@ void drm_framebuffer_print_info(struct drm_printer *p, unsigned int indent, const struct drm_framebuffer *fb); void drm_framebuffer_debugfs_init(struct drm_device *dev); -/* drm_edid.c */ -void drm_edid_cta_sad_get(const struct cea_sad *cta_sad, u8 *sad); -void drm_edid_cta_sad_set(struct cea_sad *cta_sad, const u8 *sad); - #endif /* __DRM_INTERNAL_H__ */ diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 8e0e32349332..324e900cc287 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -485,7 +485,4 @@ void drm_edid_get_product_id(const struct drm_edid *drm_edid, void drm_edid_print_product_id(struct drm_printer *p, const struct drm_edid_product_id *id, bool raw); -const u8 *drm_find_edid_extension(const struct drm_edid *drm_edid, - int ext_id, int *ext_index); - #endif /* __DRM_EDID_H__ */ -- cgit v1.2.3 From 2d798ccc89e7233f48bd7d552d95aad3de50acb1 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 16 Apr 2024 12:19:56 +0300 Subject: drm/edid: group struct drm_edid based declarations together Keep the declarations for struct drm_edid based functions together. Reviewed-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/2634de73734dfbf0a772511a80eab966c8206cf2.1713259151.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- include/drm/drm_edid.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'include/drm') diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 324e900cc287..92fff199aa78 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -431,10 +431,6 @@ struct edid *drm_do_get_edid(struct drm_connector *connector, void *data); struct edid *drm_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter); -const struct drm_edid *drm_edid_read_base_block(struct i2c_adapter *adapter); -u32 drm_edid_get_panel_id(const struct drm_edid *drm_edid); -bool drm_edid_match(const struct drm_edid *drm_edid, - const struct drm_edid_ident *ident); struct edid *drm_get_edid_switcheroo(struct drm_connector *connector, struct i2c_adapter *adapter); struct edid *drm_edid_duplicate(const struct edid *edid); @@ -474,6 +470,7 @@ const struct drm_edid *drm_edid_read_ddc(struct drm_connector *connector, const struct drm_edid *drm_edid_read_custom(struct drm_connector *connector, int (*read_block)(void *context, u8 *buf, unsigned int block, size_t len), void *context); +const struct drm_edid *drm_edid_read_base_block(struct i2c_adapter *adapter); const struct drm_edid *drm_edid_read_switcheroo(struct drm_connector *connector, struct i2c_adapter *adapter); int drm_edid_connector_update(struct drm_connector *connector, @@ -484,5 +481,8 @@ void drm_edid_get_product_id(const struct drm_edid *drm_edid, struct drm_edid_product_id *id); void drm_edid_print_product_id(struct drm_printer *p, const struct drm_edid_product_id *id, bool raw); +u32 drm_edid_get_panel_id(const struct drm_edid *drm_edid); +bool drm_edid_match(const struct drm_edid *drm_edid, + const struct drm_edid_ident *ident); #endif /* __DRM_EDID_H__ */ -- cgit v1.2.3 From d7bf5fcc2f8212b91cd33d91415f6a887761c32a Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 16 Apr 2024 12:19:59 +0300 Subject: drm/edid: make drm_edid_are_equal() static drm_edid_are_equal() is only used within drm_edid.c. Make it static. Do not encourage more uses of struct edid. Reviewed-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/aa79be9a5d0b08c71b82b86b5a8ff0f332e13c6a.1713259151.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/drm_edid.c | 3 +-- include/drm/drm_edid.h | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) (limited to 'include/drm') diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 4b3ad42a8f95..463fbad85d90 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -1827,7 +1827,7 @@ static bool edid_block_is_zero(const void *edid) * This helper can be used during probing to determine if * edid had changed. */ -bool drm_edid_are_equal(const struct edid *edid1, const struct edid *edid2) +static bool drm_edid_are_equal(const struct edid *edid1, const struct edid *edid2) { int edid1_len, edid2_len; bool edid1_present = edid1 != NULL; @@ -1849,7 +1849,6 @@ bool drm_edid_are_equal(const struct edid *edid1, const struct edid *edid2) return true; } -EXPORT_SYMBOL(drm_edid_are_equal); enum edid_block_status { EDID_BLOCK_OK = 0, diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 92fff199aa78..b085525e53e2 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -348,8 +348,6 @@ int drm_edid_to_speaker_allocation(const struct edid *edid, u8 **sadb); int drm_av_sync_delay(struct drm_connector *connector, const struct drm_display_mode *mode); -bool drm_edid_are_equal(const struct edid *edid1, const struct edid *edid2); - int drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame, const struct drm_connector *connector, -- cgit v1.2.3 From d12e36494dc2bf221867ecbfa7059e1e231f6ac2 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 8 Apr 2024 22:06:07 +0300 Subject: drm/vblank: Introduce drm_crtc_vblank_crtc() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make life easier by providing a function that hands out the correct drm_vblank_crtc for a given a drm_crtc. Also abstract the lower level internals of the vblank code in a similar fashion. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20240408190611.24914-1-ville.syrjala@linux.intel.com Reviewed-by: Dmitry Baryshkov --- drivers/gpu/drm/drm_vblank.c | 58 +++++++++++++++++++++++---------------- drivers/gpu/drm/drm_vblank_work.c | 2 +- include/drm/drm_vblank.h | 1 + 3 files changed, 36 insertions(+), 25 deletions(-) (limited to 'include/drm') diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c index 702a12bc93bd..cc3571e25a9a 100644 --- a/drivers/gpu/drm/drm_vblank.c +++ b/drivers/gpu/drm/drm_vblank.c @@ -166,11 +166,24 @@ module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600) MODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs] (0: never disable, <0: disable immediately)"); MODULE_PARM_DESC(timestamp_precision_usec, "Max. error on timestamps [usecs]"); +static struct drm_vblank_crtc * +drm_vblank_crtc(struct drm_device *dev, unsigned int pipe) +{ + return &dev->vblank[pipe]; +} + +struct drm_vblank_crtc * +drm_crtc_vblank_crtc(struct drm_crtc *crtc) +{ + return drm_vblank_crtc(crtc->dev, drm_crtc_index(crtc)); +} +EXPORT_SYMBOL(drm_crtc_vblank_crtc); + static void store_vblank(struct drm_device *dev, unsigned int pipe, u32 vblank_count_inc, ktime_t t_vblank, u32 last) { - struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; + struct drm_vblank_crtc *vblank = drm_vblank_crtc(dev, pipe); assert_spin_locked(&dev->vblank_time_lock); @@ -184,7 +197,7 @@ static void store_vblank(struct drm_device *dev, unsigned int pipe, static u32 drm_max_vblank_count(struct drm_device *dev, unsigned int pipe) { - struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; + struct drm_vblank_crtc *vblank = drm_vblank_crtc(dev, pipe); return vblank->max_vblank_count ?: dev->max_vblank_count; } @@ -273,7 +286,7 @@ static void drm_reset_vblank_timestamp(struct drm_device *dev, unsigned int pipe static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe, bool in_vblank_irq) { - struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; + struct drm_vblank_crtc *vblank = drm_vblank_crtc(dev, pipe); u32 cur_vblank, diff; bool rc; ktime_t t_vblank; @@ -364,7 +377,7 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe, u64 drm_vblank_count(struct drm_device *dev, unsigned int pipe) { - struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; + struct drm_vblank_crtc *vblank = drm_vblank_crtc(dev, pipe); u64 count; if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) @@ -438,7 +451,7 @@ static void __disable_vblank(struct drm_device *dev, unsigned int pipe) */ void drm_vblank_disable_and_save(struct drm_device *dev, unsigned int pipe) { - struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; + struct drm_vblank_crtc *vblank = drm_vblank_crtc(dev, pipe); unsigned long irqflags; assert_spin_locked(&dev->vbl_lock); @@ -600,7 +613,7 @@ void drm_calc_timestamping_constants(struct drm_crtc *crtc, { struct drm_device *dev = crtc->dev; unsigned int pipe = drm_crtc_index(crtc); - struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; + struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc); int linedur_ns = 0, framedur_ns = 0; int dotclock = mode->crtc_clock; @@ -930,7 +943,7 @@ EXPORT_SYMBOL(drm_crtc_vblank_count); static u64 drm_vblank_count_and_time(struct drm_device *dev, unsigned int pipe, ktime_t *vblanktime) { - struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; + struct drm_vblank_crtc *vblank = drm_vblank_crtc(dev, pipe); u64 vblank_count; unsigned int seq; @@ -985,7 +998,6 @@ EXPORT_SYMBOL(drm_crtc_vblank_count_and_time); */ int drm_crtc_next_vblank_start(struct drm_crtc *crtc, ktime_t *vblanktime) { - unsigned int pipe = drm_crtc_index(crtc); struct drm_vblank_crtc *vblank; struct drm_display_mode *mode; u64 vblank_start; @@ -993,7 +1005,7 @@ int drm_crtc_next_vblank_start(struct drm_crtc *crtc, ktime_t *vblanktime) if (!drm_dev_has_vblank(crtc->dev)) return -EINVAL; - vblank = &crtc->dev->vblank[pipe]; + vblank = drm_crtc_vblank_crtc(crtc); mode = &vblank->hwmode; if (!vblank->framedur_ns || !vblank->linedur_ns) @@ -1147,7 +1159,7 @@ static int __enable_vblank(struct drm_device *dev, unsigned int pipe) static int drm_vblank_enable(struct drm_device *dev, unsigned int pipe) { - struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; + struct drm_vblank_crtc *vblank = drm_vblank_crtc(dev, pipe); int ret = 0; assert_spin_locked(&dev->vbl_lock); @@ -1185,7 +1197,7 @@ static int drm_vblank_enable(struct drm_device *dev, unsigned int pipe) int drm_vblank_get(struct drm_device *dev, unsigned int pipe) { - struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; + struct drm_vblank_crtc *vblank = drm_vblank_crtc(dev, pipe); unsigned long irqflags; int ret = 0; @@ -1228,7 +1240,7 @@ EXPORT_SYMBOL(drm_crtc_vblank_get); void drm_vblank_put(struct drm_device *dev, unsigned int pipe) { - struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; + struct drm_vblank_crtc *vblank = drm_vblank_crtc(dev, pipe); if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) return; @@ -1274,7 +1286,7 @@ EXPORT_SYMBOL(drm_crtc_vblank_put); */ void drm_wait_one_vblank(struct drm_device *dev, unsigned int pipe) { - struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; + struct drm_vblank_crtc *vblank = drm_vblank_crtc(dev, pipe); int ret; u64 last; @@ -1327,7 +1339,7 @@ void drm_crtc_vblank_off(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; unsigned int pipe = drm_crtc_index(crtc); - struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; + struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc); struct drm_pending_vblank_event *e, *t; ktime_t now; u64 seq; @@ -1405,8 +1417,7 @@ EXPORT_SYMBOL(drm_crtc_vblank_off); void drm_crtc_vblank_reset(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; - unsigned int pipe = drm_crtc_index(crtc); - struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; + struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc); spin_lock_irq(&dev->vbl_lock); /* @@ -1445,8 +1456,7 @@ void drm_crtc_set_max_vblank_count(struct drm_crtc *crtc, u32 max_vblank_count) { struct drm_device *dev = crtc->dev; - unsigned int pipe = drm_crtc_index(crtc); - struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; + struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc); drm_WARN_ON(dev, dev->max_vblank_count); drm_WARN_ON(dev, !READ_ONCE(vblank->inmodeset)); @@ -1469,7 +1479,7 @@ void drm_crtc_vblank_on(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; unsigned int pipe = drm_crtc_index(crtc); - struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; + struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc); if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) return; @@ -1512,7 +1522,7 @@ static void drm_vblank_restore(struct drm_device *dev, unsigned int pipe) assert_spin_locked(&dev->vbl_lock); assert_spin_locked(&dev->vblank_time_lock); - vblank = &dev->vblank[pipe]; + vblank = drm_vblank_crtc(dev, pipe); drm_WARN_ONCE(dev, drm_debug_enabled(DRM_UT_VBL) && !vblank->framedur_ns, "Cannot compute missed vblanks without frame duration\n"); @@ -1564,7 +1574,7 @@ static int drm_queue_vblank_event(struct drm_device *dev, unsigned int pipe, union drm_wait_vblank *vblwait, struct drm_file *file_priv) { - struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; + struct drm_vblank_crtc *vblank = drm_vblank_crtc(dev, pipe); struct drm_pending_vblank_event *e; ktime_t now; u64 seq; @@ -1872,7 +1882,7 @@ static void drm_handle_vblank_events(struct drm_device *dev, unsigned int pipe) */ bool drm_handle_vblank(struct drm_device *dev, unsigned int pipe) { - struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; + struct drm_vblank_crtc *vblank = drm_vblank_crtc(dev, pipe); unsigned long irqflags; bool disable_irq; @@ -1981,7 +1991,7 @@ int drm_crtc_get_sequence_ioctl(struct drm_device *dev, void *data, pipe = drm_crtc_index(crtc); - vblank = &dev->vblank[pipe]; + vblank = drm_crtc_vblank_crtc(crtc); vblank_enabled = dev->vblank_disable_immediate && READ_ONCE(vblank->enabled); if (!vblank_enabled) { @@ -2046,7 +2056,7 @@ int drm_crtc_queue_sequence_ioctl(struct drm_device *dev, void *data, pipe = drm_crtc_index(crtc); - vblank = &dev->vblank[pipe]; + vblank = drm_crtc_vblank_crtc(crtc); e = kzalloc(sizeof(*e), GFP_KERNEL); if (e == NULL) diff --git a/drivers/gpu/drm/drm_vblank_work.c b/drivers/gpu/drm/drm_vblank_work.c index 43cd5c0f4f6f..4fe9b1d3b00f 100644 --- a/drivers/gpu/drm/drm_vblank_work.c +++ b/drivers/gpu/drm/drm_vblank_work.c @@ -245,7 +245,7 @@ void drm_vblank_work_init(struct drm_vblank_work *work, struct drm_crtc *crtc, { kthread_init_work(&work->base, func); INIT_LIST_HEAD(&work->node); - work->vblank = &crtc->dev->vblank[drm_crtc_index(crtc)]; + work->vblank = drm_crtc_vblank_crtc(crtc); } EXPORT_SYMBOL(drm_vblank_work_init); diff --git a/include/drm/drm_vblank.h b/include/drm/drm_vblank.h index 7f3957943dd1..c8f829b4307c 100644 --- a/include/drm/drm_vblank.h +++ b/include/drm/drm_vblank.h @@ -225,6 +225,7 @@ struct drm_vblank_crtc { wait_queue_head_t work_wait_queue; }; +struct drm_vblank_crtc *drm_crtc_vblank_crtc(struct drm_crtc *crtc); int drm_vblank_init(struct drm_device *dev, unsigned int num_crtcs); bool drm_dev_has_vblank(const struct drm_device *dev); u64 drm_crtc_vblank_count(struct drm_crtc *crtc); -- cgit v1.2.3 From de1c705c50326acaceaf1f02bc5bf6f267c572bd Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 8 Apr 2024 02:53:51 +0300 Subject: drm/mipi-dsi: use correct return type for the DSC functions The functions mipi_dsi_compression_mode() and mipi_dsi_picture_parameter_set() return 0-or-error rather than a buffer size. Follow example of other similar MIPI DSI functions and use int return type instead of size_t. Fixes: f4dea1aaa9a1 ("drm/dsi: add helpers for DSI compression mode and PPS packets") Reviewed-by: Marijn Suijten Reviewed-by: Jessica Zhang Signed-off-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20240408-lg-sw43408-panel-v5-2-4e092da22991@linaro.org --- drivers/gpu/drm/drm_mipi_dsi.c | 6 +++--- include/drm/drm_mipi_dsi.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'include/drm') diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index ef6e416522f8..9874ff6d4718 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -654,7 +654,7 @@ EXPORT_SYMBOL(mipi_dsi_set_maximum_return_packet_size); * * Return: 0 on success or a negative error code on failure. */ -ssize_t mipi_dsi_compression_mode(struct mipi_dsi_device *dsi, bool enable) +int mipi_dsi_compression_mode(struct mipi_dsi_device *dsi, bool enable) { /* Note: Needs updating for non-default PPS or algorithm */ u8 tx[2] = { enable << 0, 0 }; @@ -679,8 +679,8 @@ EXPORT_SYMBOL(mipi_dsi_compression_mode); * * Return: 0 on success or a negative error code on failure. */ -ssize_t mipi_dsi_picture_parameter_set(struct mipi_dsi_device *dsi, - const struct drm_dsc_picture_parameter_set *pps) +int mipi_dsi_picture_parameter_set(struct mipi_dsi_device *dsi, + const struct drm_dsc_picture_parameter_set *pps) { struct mipi_dsi_msg msg = { .channel = dsi->channel, diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index c0aec0d4d664..3011d33eccbd 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -241,9 +241,9 @@ int mipi_dsi_shutdown_peripheral(struct mipi_dsi_device *dsi); int mipi_dsi_turn_on_peripheral(struct mipi_dsi_device *dsi); int mipi_dsi_set_maximum_return_packet_size(struct mipi_dsi_device *dsi, u16 value); -ssize_t mipi_dsi_compression_mode(struct mipi_dsi_device *dsi, bool enable); -ssize_t mipi_dsi_picture_parameter_set(struct mipi_dsi_device *dsi, - const struct drm_dsc_picture_parameter_set *pps); +int mipi_dsi_compression_mode(struct mipi_dsi_device *dsi, bool enable); +int mipi_dsi_picture_parameter_set(struct mipi_dsi_device *dsi, + const struct drm_dsc_picture_parameter_set *pps); ssize_t mipi_dsi_generic_write(struct mipi_dsi_device *dsi, const void *payload, size_t size); -- cgit v1.2.3 From b724455e89ea9be900b81492897aadebcdc5ba92 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 8 Apr 2024 02:53:52 +0300 Subject: drm/mipi-dsi: add mipi_dsi_compression_mode_ext() Add the extended version of mipi_dsi_compression_mode(). It provides a way to specify the algorithm and PPS selector. Reviewed-by: Marijn Suijten Signed-off-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20240408-lg-sw43408-panel-v5-3-4e092da22991@linaro.org --- drivers/gpu/drm/drm_mipi_dsi.c | 41 ++++++++++++++++++++++++++++++++++------- include/drm/drm_mipi_dsi.h | 9 +++++++++ 2 files changed, 43 insertions(+), 7 deletions(-) (limited to 'include/drm') diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 9874ff6d4718..795001bb7ff1 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -645,29 +645,56 @@ int mipi_dsi_set_maximum_return_packet_size(struct mipi_dsi_device *dsi, EXPORT_SYMBOL(mipi_dsi_set_maximum_return_packet_size); /** - * mipi_dsi_compression_mode() - enable/disable DSC on the peripheral + * mipi_dsi_compression_mode_ext() - enable/disable DSC on the peripheral * @dsi: DSI peripheral device * @enable: Whether to enable or disable the DSC + * @algo: Selected compression algorithm + * @pps_selector: Select PPS from the table of pre-stored or uploaded PPS entries * - * Enable or disable Display Stream Compression on the peripheral using the - * default Picture Parameter Set and VESA DSC 1.1 algorithm. + * Enable or disable Display Stream Compression on the peripheral. * * Return: 0 on success or a negative error code on failure. */ -int mipi_dsi_compression_mode(struct mipi_dsi_device *dsi, bool enable) +int mipi_dsi_compression_mode_ext(struct mipi_dsi_device *dsi, bool enable, + enum mipi_dsi_compression_algo algo, + unsigned int pps_selector) { - /* Note: Needs updating for non-default PPS or algorithm */ - u8 tx[2] = { enable << 0, 0 }; + u8 tx[2] = { }; struct mipi_dsi_msg msg = { .channel = dsi->channel, .type = MIPI_DSI_COMPRESSION_MODE, .tx_len = sizeof(tx), .tx_buf = tx, }; - int ret = mipi_dsi_device_transfer(dsi, &msg); + int ret; + + if (algo > 3 || pps_selector > 3) + return -EINVAL; + + tx[0] = (enable << 0) | + (algo << 1) | + (pps_selector << 4); + + ret = mipi_dsi_device_transfer(dsi, &msg); return (ret < 0) ? ret : 0; } +EXPORT_SYMBOL(mipi_dsi_compression_mode_ext); + +/** + * mipi_dsi_compression_mode() - enable/disable DSC on the peripheral + * @dsi: DSI peripheral device + * @enable: Whether to enable or disable the DSC + * + * Enable or disable Display Stream Compression on the peripheral using the + * default Picture Parameter Set and VESA DSC 1.1 algorithm. + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_compression_mode(struct mipi_dsi_device *dsi, bool enable) +{ + return mipi_dsi_compression_mode_ext(dsi, enable, MIPI_DSI_COMPRESSION_DSC, 0); +} EXPORT_SYMBOL(mipi_dsi_compression_mode); /** diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index 3011d33eccbd..82b1cc434ea3 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -226,6 +226,12 @@ static inline int mipi_dsi_pixel_format_to_bpp(enum mipi_dsi_pixel_format fmt) return -EINVAL; } +enum mipi_dsi_compression_algo { + MIPI_DSI_COMPRESSION_DSC = 0, + MIPI_DSI_COMPRESSION_VENDOR = 3, + /* other two values are reserved, DSI 1.3 */ +}; + struct mipi_dsi_device * mipi_dsi_device_register_full(struct mipi_dsi_host *host, const struct mipi_dsi_device_info *info); @@ -242,6 +248,9 @@ int mipi_dsi_turn_on_peripheral(struct mipi_dsi_device *dsi); int mipi_dsi_set_maximum_return_packet_size(struct mipi_dsi_device *dsi, u16 value); int mipi_dsi_compression_mode(struct mipi_dsi_device *dsi, bool enable); +int mipi_dsi_compression_mode_ext(struct mipi_dsi_device *dsi, bool enable, + enum mipi_dsi_compression_algo algo, + unsigned int pps_selector); int mipi_dsi_picture_parameter_set(struct mipi_dsi_device *dsi, const struct drm_dsc_picture_parameter_set *pps); -- cgit v1.2.3