Two more mode-object properties a real driver reaches for, and the last
the DisplayLink vino driver needs to match its pre-safe-KMS feature set:
- CRTC gamma: UnregisteredCrtc::enable_gamma()
(drm_crtc_enable_color_mgmt, creating a GAMMA_LUT property) and
RawCrtcState::gamma_lut() to read the set ramp back as a
&[drm_color_lut].
- Plane rotation: UnregisteredPlane::create_rotation_property()
(drm_plane_create_rotation_property) and RawPlaneState::rotation() /
crtc_x()/crtc_y()/hotspot_x()/hotspot_y() to read the plane's
placement and orientation.
drm_plane_create_rotation_property lives in <drm/drm_blend.h>, so add
that to bindings_helper.h.
Signed-off-by: Mike Lothian <[email protected]>
Assisted-by: Claude:claude-opus-4-8 [Claude-Code]
---
rust/bindings/bindings_helper.h | 1 +
rust/kernel/drm/kms/crtc.rs | 33 +++++++++++++++++++++++++++++++++
rust/kernel/drm/kms/plane.rs | 29 +++++++++++++++++++++++++++++
3 files changed, 63 insertions(+)
diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index e5cfda610781..7d04abec1215 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -39,6 +39,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_connector.h>
#include <drm/drm_crtc.h>
+#include <drm/drm_blend.h>
#include <drm/drm_edid.h>
#include <drm/drm_encoder.h>
#include <drm/drm_framebuffer.h>
diff --git a/rust/kernel/drm/kms/crtc.rs b/rust/kernel/drm/kms/crtc.rs
index fbe113676e2f..b5128ae1ca95 100644
--- a/rust/kernel/drm/kms/crtc.rs
+++ b/rust/kernel/drm/kms/crtc.rs
@@ -356,6 +356,17 @@ pub fn new<'a, 'b: 'a, PrimaryData, CursorData>(
// SAFETY: We just allocated the crtc above, so this pointer must be
valid
Ok(unsafe { &*this })
}
+
+ /// Enable colour management on this CRTC, creating a `GAMMA_LUT` property
of `gamma_size`
+ /// entries that userspace can program (no degamma LUT, no CTM). The set
LUT is then readable
+ /// from the CRTC state via [`RawCrtcState::gamma_lut`].
+ ///
+ /// Call this during
[`KmsDriver::probe`](crate::drm::kms::KmsDriver::probe), before the device
+ /// is registered.
+ pub fn enable_gamma(&self, gamma_size: u32) {
+ // SAFETY: `as_raw()` is a valid, not-yet-registered CRTC.
+ unsafe { bindings::drm_crtc_enable_color_mgmt(self.as_raw(), 0, false,
gamma_size) };
+ }
}
// SAFETY: We inherit all relevant invariants of `Crtc`
@@ -686,6 +697,28 @@ fn mode(&self) -> &DisplayMode {
// interface can ensure this access is serialized.
unsafe { DisplayMode::as_ref(&(*self.as_raw()).mode) }
}
+
+ /// Returns the CRTC's gamma LUT for this state as an array of
[`drm_color_lut`] entries, or
+ /// [`None`] if no gamma LUT is programmed. Requires gamma to have been
enabled on the CRTC
+ /// (see [`UnregisteredCrtc::enable_gamma`]).
+ ///
+ /// [`drm_color_lut`]: bindings::drm_color_lut
+ fn gamma_lut(&self) -> Option<&[bindings::drm_color_lut]> {
+ // SAFETY: `as_raw()` is a valid `drm_crtc_state`.
+ let blob = unsafe { (*self.as_raw()).gamma_lut };
+ if blob.is_null() {
+ return None;
+ }
+ // SAFETY: a non-null gamma_lut blob is valid for the state's lifetime.
+ let (data, length) = unsafe { ((*blob).data, (*blob).length) };
+ let n = length / core::mem::size_of::<bindings::drm_color_lut>();
+ if data.is_null() || n == 0 {
+ return None;
+ }
+ // SAFETY: the blob's `data` holds `n` contiguous `drm_color_lut`
entries (the blob length
+ // is a multiple of the entry size), valid for the state's lifetime.
+ Some(unsafe {
core::slice::from_raw_parts(data.cast::<bindings::drm_color_lut>(), n) })
+ }
}
impl<T: AsRawCrtcState> RawCrtcState for T {}
diff --git a/rust/kernel/drm/kms/plane.rs b/rust/kernel/drm/kms/plane.rs
index fcaa8ba550fe..ead875316829 100644
--- a/rust/kernel/drm/kms/plane.rs
+++ b/rust/kernel/drm/kms/plane.rs
@@ -328,6 +328,28 @@ pub fn new<'a, 'b: 'a>(
// SAFETY: We just allocated the plane above, so this pointer must be
valid
Ok(unsafe { &*this })
}
+
+ /// Attach a rotation property to this plane, advertising
`supported_rotations` (a bitmask of
+ /// `DRM_MODE_ROTATE_*` | `DRM_MODE_REFLECT_*`) with initial value
`default_rotation`. The
+ /// selected value is then readable from the plane state via
+ ///
[`RawPlaneState::rotation`](crate::drm::kms::plane::RawPlaneState::rotation).
+ ///
+ /// Call this during
[`KmsDriver::probe`](crate::drm::kms::KmsDriver::probe), before the device
+ /// is registered.
+ pub fn create_rotation_property(
+ &self,
+ default_rotation: u32,
+ supported_rotations: u32,
+ ) -> Result {
+ // SAFETY: `as_raw()` is a valid, not-yet-registered plane.
+ to_result(unsafe {
+ bindings::drm_plane_create_rotation_property(
+ self.as_raw(),
+ default_rotation,
+ supported_rotations,
+ )
+ })
+ }
}
/// A trait implemented by any type that acts as a [`struct drm_plane`]
interface.
@@ -625,6 +647,13 @@ fn hotspot_y(&self) -> i32 {
self.as_raw().hotspot_y
}
+ /// The plane's rotation/reflection (`DRM_MODE_ROTATE_*` |
`DRM_MODE_REFLECT_*` bitmask), for a
+ /// plane with a rotation property (see
+ /// [`UnregisteredPlane::create_rotation_property`]). Defaults to
`DRM_MODE_ROTATE_0`.
+ fn rotation(&self) -> u32 {
+ self.as_raw().rotation
+ }
+
/// Return the current [`OpaqueCrtc`] assigned to this plane, if there is
one.
fn crtc<'a, 'b: 'a, D>(&'a self) -> Option<&'b OpaqueCrtc<D>>
where
--
2.55.0