diff --git a/rust/kernel/drm/kms/crtc.rs b/rust/kernel/drm/kms/crtc.rs
index 14e0822db73fd1f7110b03a91d65746d20471695..815c6fae398efad0f811ba58813e204c5ffd3036 100644
--- a/rust/kernel/drm/kms/crtc.rs
+++ b/rust/kernel/drm/kms/crtc.rs
@@ -120,6 +120,13 @@ pub trait DriverCrtc: Send + Sync + Sized {
     /// [`PhantomData<Self>`].
     type VblankImpl: VblankImpl<Crtc = Self>;
 
+    /// The optional data type for this driver's ephemeral mutable state
+    ///
+    /// This can be used for storing private driver data that persists between atomic commits. It
+    /// can only be mutated and accessed from the context of an atomic commit. Drivers which don't
+    /// care about this can just pass `()` here
+    type EphemeralState: DriverCrtcEphemeralState<Crtc = Self>;
+
     /// The constructor for creating a [`Crtc`] using this [`DriverCrtc`] implementation.
     ///
     /// Drivers may use this to instantiate their [`DriverCrtc`] object.
@@ -199,6 +206,35 @@ pub trait DriverCrtc: Send + Sync + Sized {
     }
 }
 
+/// A trait implemented by a driver's private ephemeral modesetting state
+///
+/// Drivers which don't need this should simply use [`NoCrtcEphemeralState`] instead of implementing
+/// this
+pub trait DriverCrtcEphemeralState {
+    /// The type of the parent [`DriverCrtc`]
+    type Crtc: DriverCrtc;
+
+    /// Create a new instance of [`Self`] for this CRTC
+    fn new(
+        dev: &Device<<Self::Crtc as DriverCrtc>::Driver>,
+        args: &<Self::Crtc as DriverCrtc>::Args,
+    ) -> Result<Self> where Self: Sized;
+}
+
+impl<T: DriverCrtc> DriverCrtcEphemeralState for PhantomData<T> {
+    type Crtc = T;
+
+    fn new(
+        dev: &Device<<Self::Crtc as DriverCrtc>::Driver>,
+        args: &<Self::Crtc as DriverCrtc>::Args,
+    ) -> Result<Self>
+    where
+        Self: Sized
+    {
+        Ok(PhantomData)
+    }
+}
+
 /// The generated C vtable for a [`DriverCrtc`].
 ///
 /// This type is created internally by DRM.
@@ -228,6 +264,8 @@ pub struct Crtc<T: DriverCrtc> {
     /// The driver's private inner data
     #[pin]
     inner: T,
+    /// The driver's optional private ephemeral modeset state
+    ephemeral_state: UnsafeCell<T::EphemeralState>,
     #[pin]
     _p: PhantomPinned,
 }
@@ -292,6 +330,10 @@ impl<T: DriverCrtc> Crtc<T> {
             dev.has_vblanks.set(true)
         }
 
+        // try_pin_init!() has a move closure, so get our pointers beforehand so we don't upset the
+        // borrow checker
+        let dev_ptr = dev.as_raw();
+
         let this = Box::try_pin_init(
             try_pin_init!(Self {
                 crtc: Opaque::new(bindings::drm_crtc {
@@ -299,6 +341,9 @@ impl<T: DriverCrtc> Crtc<T> {
                     ..Default::default()
                 }),
                 inner <- T::new(dev, &args),
+                ephemeral_state: UnsafeCell::new(
+                    <T::EphemeralState as DriverCrtcEphemeralState>::new(dev, &args)?
+                ),
                 _p: PhantomPinned,
             }),
             GFP_KERNEL
@@ -306,7 +351,7 @@ impl<T: DriverCrtc> Crtc<T> {
 
         to_result(unsafe {
             bindings::drm_crtc_init_with_planes(
-                dev.as_raw(),
+                dev_ptr,
                 this.as_raw(),
                 primary.as_raw(),
                 cursor.map_or(null_mut(), |c| c.as_raw()),