From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-wr1-f45.google.com (mail-wr1-f45.google.com [209.85.221.45]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 15ECB30C152 for ; Fri, 3 Jul 2026 03:02:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.45 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783047734; cv=none; b=RnuYQed2ARwbsIBv7BwRJlSsVSfEP39XJvJbl+xy26Zov6xHEK1J15eymo0XmcGfDlesbcQI+kNhAONsMZwlXvGyIZCBxv5LHx6FKTtSkAlB6bm0iBKCgvjZsNmDFtsf2hr/C/8efmklpWk0Xtb8ugqldJWoidI0bbZqsqWs4gA= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783047734; c=relaxed/simple; bh=1uqvohIdAq62wj82E4SBuODnbfJ/O9m3po4KKTfsvrc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=GcE8vfw3MNq1PvPn+QM+yTAQdNEBJTEjQy2aRS1aMUW7+zlhtcLB19gNxY1OgcWUR86raRzlWDot75c/bgzIOqknKHScNPk9B9SJs3IV0Vjx93tnPgdPtlK79o59cmHF1UNzQuoVJV4U9yPZZAq4t4kCx6Ee/gH1ypAt8flFt1Y= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=fireburn.co.uk; spf=none smtp.mailfrom=fireburn.co.uk; dkim=pass (2048-bit key) header.d=fireburn-co-uk.20251104.gappssmtp.com header.i=@fireburn-co-uk.20251104.gappssmtp.com header.b=ItIRHacD; arc=none smtp.client-ip=209.85.221.45 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=fireburn.co.uk Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=fireburn.co.uk Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=fireburn-co-uk.20251104.gappssmtp.com header.i=@fireburn-co-uk.20251104.gappssmtp.com header.b="ItIRHacD" Received: by mail-wr1-f45.google.com with SMTP id ffacd0b85a97d-4758bd3731bso58492f8f.0 for ; Thu, 02 Jul 2026 20:02:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fireburn-co-uk.20251104.gappssmtp.com; s=20251104; t=1783047731; x=1783652531; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=4TbX8MznRE/lSK8zDxNF2GQ6yML1Vz7QFki+Q6IYGOU=; b=ItIRHacDuZmlj03OnZ7vTpiIpCun5PYxy+8oQ9OhxHvIsbVZUaHBxEl40g6a0zlgTJ SnQ+rp4GPy6wf+XShMlWfDhHWaB8DgZUZocDe3sPofBd/b0qMyORlu1Y7BgaDalG2KGH jVPn7WoiGx2cTPwBFPq5pEW6JDqqUXb4n4e2on2Q3rBvfCcrhv0qvGAzvO+tblZHW508 9eDvQPboA/PmYMJGoKI9h4Qc4uSuLWxwXuy7haKVMkfK9ssgSXI6lx7NGm7dIbtjmFJ5 v3O2kAY6mFLM1+aNYTTOmJBx1qY3gQYABBYrpExkwwIgdsFDsPtuzECozk5Ng12mpcMR cc4w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1783047731; x=1783652531; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=4TbX8MznRE/lSK8zDxNF2GQ6yML1Vz7QFki+Q6IYGOU=; b=s/BqR+PlDYuRNshsXW9Jftk1UH95cJ3krxyVtV6vB+Zp6RyGT+GGXmRTFiZrquDApT r25Ha5LCVg+F+d4wOziEgY/2Y9LSBfIm86dYUPdowk19iAz4s/n2uVfs2yS4yDC4h4Fv cVxZMZAfQHr/F0lT2nZUnHyfsC00qcb6fAZfrImYPB5Hvmat01BAn+Mp6sPUQHoqSbDM NZT+R808v2UMWcDCHrVWXCOaIcL3RhG733J8aY4mjuuZPpr4As5yhcoCFuu6X7V1Y7i/ CoHKU7FRotFeF11WB0LmrwfOjdiSbB2QU8+MZB0CvG983IH6Zznt/lrIMNnzsLQDq2H8 Nvwg== X-Forwarded-Encrypted: i=1; AHgh+Rpg+qjOceEfVn60DCGKJb3EYWaB1br4TqXD6Zm+e8irBQgUaEQMIwSi2hzRfUZ1MWlC/SPrReDFjNGfRbQ=@vger.kernel.org X-Gm-Message-State: AOJu0YzFknD+EDxZP0b63L3QsY1Ycd08gahGqxkH51y7I4pxSFoZkTez qf4juMgRW4WHzjhDN4RFPjMuZ/bn1QtnfVlN3bHGJerebdnUUozgGht8M4SNANVBFQ== X-Gm-Gg: AfdE7cnthbY88gHuL4snEPzVvteoxJunLw67ZxngxAG+V2UD7YBqi8KYinaJw/EPH2R 0FeLF02/OxtKnvz+9vYL5q9xUeFbc0KBbXUWBr3Bs5OKbfCkYn48TXnWmaNjOauBfTn32Fis6t/ 4CIAVtUMp9ph21a1Sajxbdyz3gXVEB6ETqm3hnXxDhHcHqz9Lc8Vkt22UoHQ2gyDa4tHFhxghKj bULTSri1lJ2bLOyRyygQBEqmRSxT9iIBlV/3c/WxGXuKntbWm90idy//AKFHVXPR1w+y0PGx2Cg xS/GqSRR0L4QagENUvj/HKUqoSY6sZbOyWi0nf770WtDHlyO+Mmzn7VLdW6lqDvNsGSo3hwy6JH 4WiJsecEXyD6TbF81sFsWi+mx9uhIx5rkakH2iYU2pkmPdfB63NpoYaFfK0gQVlY/4cLbHvyFp7 2VE+GClNiBgUO8ViAmJvE0aVL0O18cwMqujjh5i/MLj77wjDSeXJhAeiTl X-Received: by 2002:a05:6000:41fe:b0:46f:8561:fe60 with SMTP id ffacd0b85a97d-4793685fe58mr3081792f8f.17.1783047731472; Thu, 02 Jul 2026 20:02:11 -0700 (PDT) Received: from axion.fireburn.co.uk ([137.220.119.72]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-477db3dbacbsm14466500f8f.4.2026.07.02.20.02.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 02 Jul 2026 20:02:09 -0700 (PDT) From: Mike Lothian To: rust-for-linux@vger.kernel.org Cc: dri-devel@lists.freedesktop.org, David Airlie , Simona Vetter , Danilo Krummrich , Lyude Paul , Miguel Ojeda , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , linux-kernel@vger.kernel.org, Mike Lothian Subject: [RFC PATCH v2 16/18] rust: drm: add CRTC gamma LUT and plane rotation property bindings Date: Fri, 3 Jul 2026 04:01:03 +0100 Message-ID: <20260703030123.2814-17-mike@fireburn.co.uk> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260703030123.2814-1-mike@fireburn.co.uk> References: <20260617150232.2210-1-mike@fireburn.co.uk> <20260703030123.2814-1-mike@fireburn.co.uk> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 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 , so add that to bindings_helper.h. Signed-off-by: Mike Lothian 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 #include #include +#include #include #include #include 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::(); + 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::(), n) }) + } } impl 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> where -- 2.55.0