From: Lyude Paul <lyude@redhat.com>
To: dri-devel@lists.freedesktop.org, rust-for-linux@vger.kernel.org
Cc: "Asahi Lina" <lina@asahilina.net>,
"Danilo Krummrich" <dakr@kernel.org>,
mcanal@igalia.com, airlied@redhat.com, zhiw@nvidia.com,
cjia@nvidia.com, jhubbard@nvidia.com,
"Miguel Ojeda" <ojeda@kernel.org>,
"Alex Gaynor" <alex.gaynor@gmail.com>,
"Wedson Almeida Filho" <wedsonaf@gmail.com>,
"Boqun Feng" <boqun.feng@gmail.com>,
"Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Benno Lossin" <benno.lossin@proton.me>,
"Andreas Hindborg" <a.hindborg@samsung.com>,
"Alice Ryhl" <aliceryhl@google.com>,
"Trevor Gross" <tmgross@umich.edu>,
linux-kernel@vger.kernel.org (open list)
Subject: [WIP RFC v2 08/35] rust: drm/kms: Add bindings for drm_encoder
Date: Mon, 30 Sep 2024 19:09:51 -0400 [thread overview]
Message-ID: <20240930233257.1189730-9-lyude@redhat.com> (raw)
In-Reply-To: <20240930233257.1189730-1-lyude@redhat.com>
The last thing we need to be able to register a KMS driver is the ability
to create DRM encoders, so let's add bindings for that. Again, these
bindings follow the same general pattern as CRTCs, planes, and connector
with one difference: encoders don't have an atomic state.
Note that not having an atomic state doesn't mean there aren't plenty of
valid usecases for a driver to stick private data within a DRM encoder,
hence why we reuse the aforementioned pattern.
Signed-off-by: Lyude Paul <lyude@redhat.com>
---
rust/kernel/drm/kms.rs | 1 +
rust/kernel/drm/kms/encoder.rs | 248 +++++++++++++++++++++++++++++++++
2 files changed, 249 insertions(+)
create mode 100644 rust/kernel/drm/kms/encoder.rs
diff --git a/rust/kernel/drm/kms.rs b/rust/kernel/drm/kms.rs
index 4b54611fdba8b..d5cad598f016f 100644
--- a/rust/kernel/drm/kms.rs
+++ b/rust/kernel/drm/kms.rs
@@ -4,6 +4,7 @@
pub mod connector;
pub mod crtc;
+pub mod encoder;
pub mod fbdev;
pub mod plane;
diff --git a/rust/kernel/drm/kms/encoder.rs b/rust/kernel/drm/kms/encoder.rs
new file mode 100644
index 0000000000000..3ae597093645e
--- /dev/null
+++ b/rust/kernel/drm/kms/encoder.rs
@@ -0,0 +1,248 @@
+// SPDX-License-Identifier: GPL-2.0 OR MIT
+
+//! drm_encoder abstractions for rust
+
+use crate::{
+ drm::{
+ device::Device,
+ drv::Driver,
+ },
+ prelude::*,
+ sync::Arc,
+ types::Opaque,
+ init::Zeroable,
+ error::to_result,
+ private::Sealed,
+};
+use core::{
+ marker::*,
+ ptr::{null, addr_of_mut},
+ ops::Deref,
+};
+use super::{ModeObject, StaticModeObject, KmsDriver, UnregisteredKmsDevice};
+use bindings;
+
+// TODO: We should alias all of these types with shorter names
+pub use bindings::{
+ DRM_MODE_ENCODER_NONE,
+ DRM_MODE_ENCODER_DAC,
+ DRM_MODE_ENCODER_TMDS,
+ DRM_MODE_ENCODER_LVDS,
+ DRM_MODE_ENCODER_TVDAC,
+ DRM_MODE_ENCODER_VIRTUAL,
+ DRM_MODE_ENCODER_DSI,
+ DRM_MODE_ENCODER_DPMST,
+ DRM_MODE_ENCODER_DPI,
+};
+
+/// The main trait for implementing the [`struct drm_encoder`] API for [`Encoder`].
+///
+/// Any KMS driver should have at least one implementation of this type, which allows them to create
+/// [`Encoder`] objects. Additionally, a driver may store driver-private data within the type that
+/// implements [`DriverEncoder`] - and it will be made available when using a fully typed
+/// [`Encoder`] object.
+///
+/// # Invariants
+///
+/// - Any C FFI callbacks generated using this trait are guaranteed that passed-in
+/// [`struct drm_encoder`] pointers are contained within a [`Encoder<Self>`].
+///
+/// [`struct drm_encoder`]: srctree/include/drm/drm_encoder.h
+#[vtable]
+pub trait DriverEncoder: Send + Sync + Sized {
+ /// The generated C vtable for this [`DriverEncoder`] implementation.
+ #[unique]
+ const OPS: &'static DriverEncoderOps = &DriverEncoderOps {
+ funcs: bindings::drm_encoder_funcs {
+ reset: None,
+ destroy: Some(encoder_destroy_callback::<Self>),
+ late_register: None,
+ early_unregister: None,
+ debugfs_init: None,
+ },
+ helper_funcs: bindings::drm_encoder_helper_funcs {
+ dpms: None,
+ mode_valid: None,
+ mode_fixup: None,
+ prepare: None,
+ mode_set: None,
+ commit: None,
+ detect: None,
+ enable: None,
+ disable: None,
+ atomic_check: None,
+ atomic_enable: None,
+ atomic_disable: None,
+ atomic_mode_set: None,
+ },
+ };
+
+ /// The parent driver for this drm_encoder implementation
+ type Driver: KmsDriver;
+
+ /// The type to pass to the `args` field of [`Encoder::new`].
+ ///
+ /// This type will be made available in in the `args` argument of [`Self::new`]. Drivers which
+ /// don't need this can simply pass [`()`] here.
+ type Args;
+
+ /// The constructor for creating a [`Encoder`] using this [`DriverEncoder`] implementation.
+ ///
+ /// Drivers may use this to instantiate their [`DriverEncoder`] object.
+ fn new(device: &Device<Self::Driver>, args: Self::Args) -> impl PinInit<Self, Error>;
+}
+
+/// The generated C vtable for a [`DriverEncoder`].
+///
+/// This type is created internally by DRM.
+pub struct DriverEncoderOps {
+ funcs: bindings::drm_encoder_funcs,
+ helper_funcs: bindings::drm_encoder_helper_funcs,
+}
+
+/// A trait implemented by any type that acts as a [`struct drm_encoder`] interface.
+///
+/// This is implemented internally by DRM.
+///
+/// [`struct drm_encoder`]: srctree/include/drm/drm_encoder.h
+pub trait AsRawEncoder: StaticModeObject {
+ /// Return the raw `bindings::drm_encoder` for this DRM encoder.
+ ///
+ /// Drivers should never use this directly
+ fn as_raw(&self) -> *mut bindings::drm_encoder;
+
+ /// Convert a raw `bindings::drm_encoder` pointer into an object of this type.
+ ///
+ /// SAFETY: Callers promise that `ptr` points to a valid instance of this type
+ unsafe fn from_raw<'a>(ptr: *mut bindings::drm_encoder) -> &'a Self;
+}
+
+/// The main interface for a [`struct drm_encoder`].
+///
+/// This type is the main interface for dealing with DRM encoders. In addition, it also allows
+/// immutable access to whatever private data is contained within an implementor's
+/// [`DriverEncoder`] type.
+///
+/// # Invariants
+///
+/// - `encoder` and `inner` are initialized for as long as this object is made available to users.
+/// - The data layout of this structure begins with [`struct drm_encoder`].
+///
+/// [`struct drm_encoder`]: srctree/include/drm/drm_encoder.h
+#[repr(C)]
+#[pin_data]
+pub struct Encoder<T: DriverEncoder> {
+ /// The FFI drm_encoder object
+ encoder: Opaque<bindings::drm_encoder>,
+ /// The driver's private inner data
+ #[pin]
+ inner: T,
+ #[pin]
+ _p: PhantomPinned,
+}
+
+impl<T: DriverEncoder> Sealed for Encoder<T> {}
+
+// SAFETY: DRM expects this to be zero-initialized
+unsafe impl Zeroable for bindings::drm_encoder {}
+
+// SAFETY: Our interface is thread-safe.
+unsafe impl<T: DriverEncoder> Send for Encoder<T> { }
+// SAFETY: Our interface is thread-safe.
+unsafe impl<T: DriverEncoder> Sync for Encoder<T> { }
+
+impl<T: DriverEncoder> ModeObject for Encoder<T> {
+ type Driver = T::Driver;
+
+ fn drm_dev(&self) -> &Device<Self::Driver> {
+ // SAFETY: DRM encoders exist for as long as the device does, so this pointer is always
+ // valid
+ unsafe { Device::borrow((*self.encoder.get()).dev) }
+ }
+
+ fn raw_mode_obj(&self) -> *mut bindings::drm_mode_object {
+ // SAFETY: We don't expose Encoder<T> to users before it's initialized, so `base` is always
+ // initialized
+ unsafe { &mut (*self.encoder.get()).base }
+ }
+}
+
+// SAFETY: Encoders do not have a refcount
+unsafe impl<T: DriverEncoder> StaticModeObject for Encoder<T> { }
+
+impl<T: DriverEncoder> Deref for Encoder<T> {
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ &self.inner
+ }
+}
+
+impl<T: DriverEncoder> AsRawEncoder for Encoder<T> {
+ fn as_raw(&self) -> *mut bindings::drm_encoder {
+ self.encoder.get()
+ }
+
+ unsafe fn from_raw<'a>(ptr: *mut bindings::drm_encoder) -> &'a Self {
+ // SAFETY: Our data layout is starts with to `bindings::drm_encoder`
+ unsafe { &*ptr.cast() }
+ }
+}
+
+impl<T: DriverEncoder> Encoder<T> {
+ /// Construct a new [`Encoder`].
+ ///
+ /// A driver may use this from their [`Kms::create_objects`] callback in order to construct new
+ /// [`Encoder`] objects.
+ ///
+ /// [`Kms::create_objects`]: kernel::drm::kms::Kms::create_objects
+ pub fn new<'a, 'b: 'a>(
+ dev: &'a UnregisteredKmsDevice<'a, T::Driver>,
+ type_: u32,
+ possible_crtcs: u32,
+ possible_clones: u32,
+ name: Option<&CStr>,
+ args: T::Args,
+ ) -> Result<&'b Self> {
+ let this: Pin<Box<Self>> = Box::try_pin_init(
+ try_pin_init!(Self {
+ encoder: Opaque::new(bindings::drm_encoder {
+ helper_private: &T::OPS.helper_funcs,
+ possible_crtcs,
+ possible_clones,
+ ..Default::default()
+ }),
+ inner <- T::new(dev, args),
+ _p: PhantomPinned
+ }),
+ GFP_KERNEL
+ )?;
+
+ // SAFETY: FFI call with no special requirements
+ to_result(unsafe {
+ bindings::drm_encoder_init(
+ dev.as_raw(),
+ this.as_raw(),
+ &T::OPS.funcs,
+ type_ as _,
+ name.map_or(null(), |n| n.as_char_ptr())
+ )
+ })?;
+
+ // Convert the box into a raw pointer, we'll re-assemble it in encoder_destroy_callback()
+ // SAFETY: We don't move anything
+ Ok(unsafe { &*Box::into_raw(Pin::into_inner_unchecked(this)) })
+ }
+}
+
+unsafe extern "C" fn encoder_destroy_callback<T: DriverEncoder>(
+ encoder: *mut bindings::drm_encoder
+) {
+ // SAFETY: DRM guarantees that `encoder` points to a valid initialized `drm_encoder`.
+ unsafe { bindings::drm_encoder_cleanup(encoder) };
+
+ // SAFETY:
+ // - DRM guarantees we are now the only one with access to this [`drm_encoder`].
+ // - This cast is safe via `DriverEncoder`s type invariants.
+ unsafe { drop(Box::from_raw(encoder as *mut Encoder<T>)) };
+}
--
2.46.1
next prev parent reply other threads:[~2024-09-30 23:38 UTC|newest]
Thread overview: 109+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20240930233257.1189730-1-lyude@redhat.com>
2024-09-30 23:09 ` [WIP RFC v2 01/35] WIP: rust/drm: Add fourcc bindings Lyude Paul
2024-10-01 9:25 ` Jani Nikula
2024-10-01 15:18 ` Miguel Ojeda
2024-10-03 8:33 ` Louis Chauvet
2024-10-03 20:16 ` Lyude Paul
2024-11-26 17:40 ` Daniel Almeida
2024-11-27 21:11 ` Lyude Paul
2025-01-14 18:54 ` Daniel Almeida
2024-09-30 23:09 ` [WIP RFC v2 02/35] WIP: rust: drm: Add traits for registering KMS devices Lyude Paul
2024-11-26 18:18 ` Daniel Almeida
2024-11-27 21:21 ` Lyude Paul
2024-12-05 14:03 ` Daniel Almeida
2024-12-03 22:41 ` Lyude Paul
2024-12-05 13:43 ` Daniel Almeida
2024-12-06 15:23 ` Alice Ryhl
2024-12-09 23:20 ` Lyude Paul
2024-09-30 23:09 ` [WIP RFC v2 03/35] rust: drm/kms/fbdev: Add FbdevShmem Lyude Paul
2024-11-26 19:58 ` Daniel Almeida
2024-09-30 23:09 ` [WIP RFC v2 04/35] rust: drm/kms: Introduce the main ModeConfigObject traits Lyude Paul
2024-11-26 20:34 ` Daniel Almeida
2024-09-30 23:09 ` [WIP RFC v2 05/35] rust: drm/kms: Add bindings for drm_connector Lyude Paul
2024-11-26 21:25 ` Daniel Almeida
2024-12-04 21:16 ` Lyude Paul
2024-12-04 21:18 ` Lyude Paul
2024-12-10 23:41 ` Lyude Paul
2024-12-11 8:43 ` Simona Vetter
2024-12-12 0:34 ` Lyude Paul
2024-12-12 10:03 ` Simona Vetter
2024-09-30 23:09 ` [WIP RFC v2 06/35] rust: drm/kms: Add drm_plane bindings Lyude Paul
2024-10-03 8:30 ` Louis Chauvet
2024-10-03 20:06 ` Lyude Paul
2024-11-27 14:05 ` Daniel Almeida
2024-12-12 21:28 ` Lyude Paul
2024-09-30 23:09 ` [WIP RFC v2 07/35] WIP: rust: drm/kms: Add drm_crtc bindings Lyude Paul
2024-11-27 14:36 ` Daniel Almeida
2024-12-12 22:25 ` Lyude Paul
2024-09-30 23:09 ` Lyude Paul [this message]
2024-09-30 23:09 ` [WIP RFC v2 09/35] WIP: rust: drm/kms: Add Connector.attach_encoder() Lyude Paul
2024-11-27 14:43 ` Daniel Almeida
2024-09-30 23:09 ` [WIP RFC v2 10/35] rust: drm/kms: Add DriverConnector::get_mode callback Lyude Paul
2024-11-27 15:03 ` Daniel Almeida
2024-12-12 22:37 ` Lyude Paul
2024-09-30 23:09 ` [WIP RFC v2 11/35] rust: drm/kms: Add ConnectorGuard::add_modes_noedid() Lyude Paul
2024-11-27 15:06 ` Daniel Almeida
2024-09-30 23:09 ` [WIP RFC v2 12/35] rust: drm/kms: Add ConnectorGuard::set_preferred_mode Lyude Paul
2024-11-27 15:11 ` Daniel Almeida
2024-09-30 23:09 ` [WIP RFC v2 13/35] WIP: rust: drm/kms: Add OpaqueConnector and OpaqueConnectorState Lyude Paul
2024-11-27 15:51 ` Daniel Almeida
2024-12-05 23:25 ` Lyude Paul
2024-09-30 23:09 ` [WIP RFC v2 14/35] WIP: rust: drm/kms: Add OpaqueCrtc and OpaqueCrtcState Lyude Paul
2024-11-27 16:00 ` Daniel Almeida
2024-12-12 23:01 ` Lyude Paul
2024-09-30 23:09 ` [WIP RFC v2 15/35] WIP: rust: drm/kms: Add OpaquePlane and OpaquePlaneState Lyude Paul
2024-11-27 17:03 ` Daniel Almeida
2024-09-30 23:09 ` [WIP RFC v2 16/35] rust: drm/kms: Add RawConnector and RawConnectorState Lyude Paul
2024-11-27 19:26 ` Daniel Almeida
2024-09-30 23:10 ` [WIP RFC v2 17/35] rust: drm/kms: Add RawCrtc and RawCrtcState Lyude Paul
2024-11-27 19:29 ` Daniel Almeida
2024-09-30 23:10 ` [WIP RFC v2 18/35] rust: drm/kms: Add RawPlane and RawPlaneState Lyude Paul
2024-11-27 19:30 ` Daniel Almeida
2024-09-30 23:10 ` [WIP RFC v2 19/35] WIP: rust: drm/kms: Add OpaqueEncoder Lyude Paul
2024-11-27 19:35 ` Daniel Almeida
2024-09-30 23:10 ` [WIP RFC v2 20/35] WIP: rust: drm/kms: Add drm_atomic_state bindings Lyude Paul
2024-11-27 20:54 ` Daniel Almeida
2024-12-12 23:37 ` Lyude Paul
2024-09-30 23:10 ` [WIP RFC v2 21/35] rust: drm/kms: Introduce DriverCrtc::atomic_check() Lyude Paul
2024-11-28 13:37 ` Daniel Almeida
2025-01-13 23:43 ` Lyude Paul
2024-09-30 23:10 ` [WIP RFC v2 22/35] rust: drm/kms: Add DriverPlane::atomic_update() Lyude Paul
2024-11-28 13:38 ` Daniel Almeida
2025-01-13 23:47 ` Lyude Paul
2024-11-28 13:51 ` Daniel Almeida
2025-01-13 23:53 ` Lyude Paul
2024-09-30 23:10 ` [WIP RFC v2 23/35] rust: drm/kms: Add DriverPlane::atomic_check() Lyude Paul
2024-11-28 13:49 ` Daniel Almeida
2025-01-13 23:51 ` Lyude Paul
2024-09-30 23:10 ` [WIP RFC v2 24/35] rust: drm/kms: Add RawCrtcState::active() Lyude Paul
2024-11-28 13:54 ` Daniel Almeida
2024-09-30 23:10 ` [WIP RFC v2 25/35] rust: drm/kms: Add RawPlaneState::crtc() Lyude Paul
2024-11-28 13:58 ` Daniel Almeida
2024-09-30 23:10 ` [WIP RFC v2 26/35] WIP: rust: drm/kms: Add RawPlaneState::atomic_helper_check() Lyude Paul
2024-11-28 14:04 ` Daniel Almeida
2025-01-13 23:57 ` Lyude Paul
2025-01-14 14:07 ` Simona Vetter
2024-09-30 23:10 ` [WIP RFC v2 27/35] rust: drm/kms: Add drm_framebuffer bindings Lyude Paul
2024-11-28 14:26 ` Daniel Almeida
2024-09-30 23:10 ` [WIP RFC v2 28/35] rust: drm/kms: Add RawPlane::framebuffer() Lyude Paul
2024-11-28 14:29 ` Daniel Almeida
2025-01-14 0:03 ` Lyude Paul
2025-01-14 14:09 ` Simona Vetter
2024-09-30 23:10 ` [WIP RFC v2 29/35] rust: drm/kms: Add DriverCrtc::atomic_begin() and atomic_flush() Lyude Paul
2024-11-28 14:31 ` Daniel Almeida
2024-09-30 23:10 ` [WIP RFC v2 30/35] rust: drm/kms: Add DriverCrtc::atomic_enable() and atomic_disable() Lyude Paul
2024-11-28 14:33 ` Daniel Almeida
2024-09-30 23:10 ` [WIP RFC v2 31/35] rust: drm: Add Device::event_lock() Lyude Paul
2024-11-28 14:35 ` Daniel Almeida
2024-09-30 23:10 ` [WIP RFC v2 32/35] rust: drm/kms: Add Device::num_crtcs() Lyude Paul
2024-11-28 14:38 ` Daniel Almeida
2025-01-14 0:05 ` Lyude Paul
2024-09-30 23:10 ` [WIP RFC v2 33/35] WIP: rust: drm/kms: Add VblankSupport Lyude Paul
2024-12-05 15:29 ` Daniel Almeida
2025-01-14 0:43 ` Lyude Paul
2025-01-14 14:24 ` Simona Vetter
2025-01-14 15:04 ` Miguel Ojeda
2025-01-14 15:38 ` Simona Vetter
2024-09-30 23:10 ` [WIP RFC v2 34/35] WIP: rust: drm/kms: Add Kms::atomic_commit_tail Lyude Paul
2024-12-05 16:09 ` Daniel Almeida
2024-09-30 23:10 ` [WIP RFC v2 35/35] WIP: drm: Introduce RVKMS! Lyude Paul
2024-12-05 16:36 ` Daniel Almeida
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240930233257.1189730-9-lyude@redhat.com \
--to=lyude@redhat.com \
--cc=a.hindborg@samsung.com \
--cc=airlied@redhat.com \
--cc=alex.gaynor@gmail.com \
--cc=aliceryhl@google.com \
--cc=benno.lossin@proton.me \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=cjia@nvidia.com \
--cc=dakr@kernel.org \
--cc=dri-devel@lists.freedesktop.org \
--cc=gary@garyguo.net \
--cc=jhubbard@nvidia.com \
--cc=lina@asahilina.net \
--cc=linux-kernel@vger.kernel.org \
--cc=mcanal@igalia.com \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=tmgross@umich.edu \
--cc=wedsonaf@gmail.com \
--cc=zhiw@nvidia.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox