@@ -275,6 +275,8 @@ source "drivers/gpu/drm/amd/amdgpu/Kconfig"
source "drivers/gpu/drm/nouveau/Kconfig"
+source "drivers/gpu/drm/rvkms/Kconfig"
+
source "drivers/gpu/drm/i915/Kconfig"
source "drivers/gpu/drm/xe/Kconfig"
@@ -143,6 +143,7 @@ obj-$(CONFIG_DRM_VMWGFX)+= vmwgfx/
obj-$(CONFIG_DRM_VGEM) += vgem/
obj-$(CONFIG_DRM_VKMS) += vkms/
obj-$(CONFIG_DRM_NOUVEAU) +=nouveau/
+obj-$(CONFIG_DRM_RVKMS) += rvkms/
obj-$(CONFIG_DRM_EXYNOS) +=exynos/
obj-$(CONFIG_DRM_ROCKCHIP) +=rockchip/
obj-$(CONFIG_DRM_GMA500) += gma500/
new file mode 100644
@@ -0,0 +1,3 @@
+config DRM_RVKMS
+ tristate "Rust VKMS PoC driver (EXPERIMENTAL)"
+ depends on RUST && DRM && DRM_GEM_SHMEM_HELPER
new file mode 100644
@@ -0,0 +1 @@
+obj-$(CONFIG_DRM_RVKMS) += rvkms.o
new file mode 100644
@@ -0,0 +1,55 @@
+// TODO: License and stuff
+// Contain's rvkms's drm_connector implementation
+
+use super::{RvkmsDriver, RvkmsDevice, MAX_RES, DEFAULT_RES};
+use kernel::{
+ prelude::*,
+ drm::{
+ device::Device,
+ kms::{
+ connector::{self, ConnectorGuard},
+ ModeConfigGuard
+ }
+ },
+ prelude::*
+};
+use core::marker::PhantomPinned;
+
+#[pin_data]
+pub(crate) struct DriverConnector {
+ #[pin]
+ _p: PhantomPinned
+}
+
+pub(crate) type Connector = connector::Connector<DriverConnector>;
+
+impl connector::DriverConnector for DriverConnector {
+ type Initializer = impl PinInit<Self, Error>;
+
+ type State = ConnectorState;
+
+ type Driver = RvkmsDriver;
+
+ type Args = ();
+
+ fn new(dev: &Device<Self::Driver>, args: Self::Args) -> Self::Initializer {
+ try_pin_init!(Self { _p: PhantomPinned })
+ }
+
+ fn get_modes(
+ connector: ConnectorGuard<'_, Self>,
+ _guard: &ModeConfigGuard<'_, Self::Driver>
+ ) -> i32 {
+ let count = connector.add_modes_noedid(MAX_RES);
+
+ connector.set_preferred_mode(DEFAULT_RES);
+ count
+ }
+}
+
+#[derive(Clone, Default)]
+pub(crate) struct ConnectorState;
+
+impl connector::DriverConnectorState for ConnectorState {
+ type Connector = DriverConnector;
+}
new file mode 100644
@@ -0,0 +1,40 @@
+// TODO: License and stuff
+// Contain's rvkms's drm_crtc implementation
+use core::marker::PhantomPinned;
+use super::RvkmsDriver;
+use kernel::{
+ prelude::*,
+ drm::{
+ device::Device,
+ kms::crtc,
+ },
+};
+
+pub(crate) type Crtc = crtc::Crtc<DriverCrtc>;
+
+#[pin_data]
+pub(crate) struct DriverCrtc {
+ #[pin]
+ _p: PhantomPinned
+}
+
+impl crtc::DriverCrtc for DriverCrtc {
+ type Initializer = impl PinInit<Self, Error>;
+
+ type Args = ();
+
+ type State = CrtcState;
+
+ type Driver = RvkmsDriver;
+
+ fn new(device: &Device<Self::Driver>, args: Self::Args) -> Self::Initializer {
+ try_pin_init!(Self { _p: PhantomPinned })
+ }
+}
+
+#[derive(Clone, Default)]
+pub(crate) struct CrtcState;
+
+impl crtc::DriverCrtcState for CrtcState {
+ type Crtc = DriverCrtc;
+}
new file mode 100644
@@ -0,0 +1,26 @@
+use core::marker::PhantomPinned;
+use kernel::{
+ drm::{device::Device, kms},
+ prelude::*
+};
+use crate::RvkmsDriver;
+
+#[pin_data]
+pub(crate) struct DriverEncoder {
+ #[pin]
+ _p: PhantomPinned,
+}
+
+pub(crate) type Encoder = kms::encoder::Encoder<DriverEncoder>;
+
+impl kms::encoder::DriverEncoder for DriverEncoder {
+ type Initializer = impl PinInit<Self, Error>;
+
+ type Driver = RvkmsDriver;
+
+ type Args = ();
+
+ fn new(device: &Device<Self::Driver>, args: Self::Args) -> Self::Initializer {
+ try_pin_init!(Self { _p: PhantomPinned })
+ }
+}
new file mode 100644
@@ -0,0 +1,22 @@
+use super::RvkmsDriver;
+
+use kernel::{
+ drm::{
+ self,
+ device::Device as DrmDevice
+ },
+ prelude::*,
+};
+use core::option::*;
+
+pub(crate) struct File();
+
+impl drm::file::DriverFile for File {
+ type Driver = RvkmsDriver;
+
+ fn open(device: &DrmDevice<Self::Driver>) -> Result<Pin<Box<Self>>> {
+ pr_info!("Someone opened a file! But I do not yet know which one...\n");
+
+ Ok(Box::into_pin(Box::try_new(Self())?))
+ }
+}
new file mode 100644
@@ -0,0 +1,32 @@
+use crate::{RvkmsDriver, RvkmsDevice};
+use core::sync::atomic::{AtomicU64, Ordering};
+use kernel::{
+ drm::{self, gem},
+ prelude::*,
+};
+
+static GEM_ID: AtomicU64 = AtomicU64::new(0);
+
+/// GEM Object implementation
+#[pin_data]
+pub(crate) struct DriverObject {
+ /// ID for debugging
+ id: u64,
+}
+
+pub(crate) type Object = gem::shmem::Object<DriverObject>;
+
+impl gem::BaseDriverObject<Object> for DriverObject {
+ type Initializer = impl PinInit<Self, Error>;
+
+ fn new(dev: &RvkmsDevice, size: usize) -> Self::Initializer {
+ let id = GEM_ID.fetch_add(1, Ordering::Relaxed);
+
+ pr_debug!("DriverObject::new id={id}\n");
+ DriverObject { id }
+ }
+}
+
+impl gem::shmem::DriverObject for DriverObject {
+ type Driver = RvkmsDriver;
+}
new file mode 100644
@@ -0,0 +1,72 @@
+use crate::{
+ crtc::Crtc,
+ plane::Plane,
+ connector::Connector,
+ encoder::Encoder,
+ RvkmsDevice
+};
+use kernel::{
+ drm::{
+ fourcc::Format,
+ kms::{
+ connector::DRM_MODE_CONNECTOR_VIRTUAL,
+ encoder::DRM_MODE_ENCODER_VIRTUAL,
+ plane::PlaneType,
+ KmsRef
+ },
+ },
+ sync::Arc,
+ prelude::*,
+ types::ARef,
+ drm_format_list,
+};
+
+pub(crate) struct Output {
+ crtc: KmsRef<Crtc>,
+ primary: KmsRef<Plane>,
+ // TODO: overlay, cursor
+ connector: ARef<Connector>,
+ encoder: KmsRef<Encoder>,
+}
+
+impl Output {
+ pub(crate) fn new(dev: &RvkmsDevice, index: u8) -> Result<Self> {
+ let primary = Plane::new(
+ dev,
+ 1 << index,
+ &drm_format_list![Format::XRGB888],
+ None,
+ PlaneType::PRIMARY,
+ None,
+ ()
+ )?;
+
+ let crtc = Crtc::new(
+ dev,
+ &primary,
+ Option::<&Plane>::None,
+ None,
+ ()
+ )?;
+
+ let connector = Connector::new(dev, DRM_MODE_CONNECTOR_VIRTUAL, ())?;
+
+ let encoder = Encoder::new(
+ dev,
+ DRM_MODE_ENCODER_VIRTUAL,
+ 1 << index,
+ 0,
+ None,
+ ()
+ )?;
+
+ connector.attach_encoder(&encoder)?;
+
+ Ok(Self {
+ crtc: crtc.into(),
+ primary: primary.into(),
+ connector,
+ encoder: encoder.into()
+ })
+ }
+}
new file mode 100644
@@ -0,0 +1,39 @@
+use core::marker::PhantomPinned;
+use super::RvkmsDriver;
+use kernel::{
+ prelude::*,
+ drm::{
+ device::Device,
+ kms::plane::{self, DriverPlaneState},
+ },
+};
+
+#[pin_data]
+pub(crate) struct DriverPlane {
+ #[pin]
+ _p: PhantomPinned,
+}
+
+pub(crate) type Plane = plane::Plane<DriverPlane>;
+pub(crate) type PlaneState = plane::PlaneState<RvkmsPlaneState>;
+
+impl plane::DriverPlane for DriverPlane {
+ type Initializer = impl PinInit<Self, Error>;
+
+ type State = RvkmsPlaneState;
+
+ type Driver = RvkmsDriver;
+
+ type Args = ();
+
+ fn new(device: &Device<Self::Driver>, args: Self::Args) -> Self::Initializer {
+ try_pin_init!(Self { _p: PhantomPinned })
+ }
+}
+
+#[derive(Clone, Default)]
+pub(crate) struct RvkmsPlaneState;
+
+impl DriverPlaneState for RvkmsPlaneState {
+ type Plane = DriverPlane;
+}
new file mode 100644
@@ -0,0 +1,146 @@
+// Rust VKMS Proof of Concept driver
+// Written by Lyude Paul
+// Enormous thanks to:
+// - Maira Canal
+// - Asahi Lina
+// - Probably lots of other wonderful people whose names aren't here
+
+mod connector;
+mod crtc;
+mod file;
+mod gem;
+mod plane;
+mod output;
+mod encoder;
+
+use alloc::boxed::Box;
+
+use core::option::*;
+
+use kernel::{
+ c_str,
+ str::CStr,
+ device::{self, RawDevice},
+ drm::{
+ self,
+ drv,
+ kms::{
+ KmsDriver,
+ ModeConfigInfo,
+ },
+ },
+ platform,
+ prelude::*,
+ sync::Arc,
+ types::ARef,
+};
+
+use crate::output::Output;
+
+pub(crate) struct RvkmsDriver;
+pub(crate) struct Resources;
+
+pub(crate) type DeviceData = device::Data<drv::Registration<RvkmsDriver>, Resources, Data>;
+
+/// Convienence type alias for the DRM device type for this driver
+pub(crate) type RvkmsDevice = drm::device::Device<RvkmsDriver>;
+
+/// Driver metadata
+const INFO: drv::DriverInfo = drv::DriverInfo {
+ major: 0,
+ minor: 0,
+ patchlevel: 0,
+ name: c_str!("rvkms"),
+ desc: c_str!("Rust VKMS PoC"),
+ date: c_str!("20240115"),
+};
+
+/// The minimum supported resolution
+const MIN_RES: (i32, i32) = (10, 10);
+
+/// The maximum supported resolution
+const MAX_RES: (i32, i32) = (8192, 8192);
+
+/// The "preferred" resolution
+const DEFAULT_RES: (i32, i32) = (1024, 768);
+
+pub(crate) struct Data {
+}
+
+/// DRM Driver implementation for `RvkmsDriver`
+#[vtable]
+impl drv::Driver for RvkmsDriver {
+ type Data = Arc<DeviceData>;
+ type Object = gem::Object;
+ type File = file::File;
+
+ const INFO: drv::DriverInfo = INFO;
+ const FEATURES:u32 = drv::FEAT_GEM | drv::FEAT_MODESET | drv::FEAT_ATOMIC;
+
+ kernel::declare_drm_ioctls! {}
+}
+
+impl KmsDriver for RvkmsDriver {}
+
+pub(crate) struct Rvkms {
+ output: Output,
+ drm: ARef<RvkmsDevice>,
+ _resource: device::Resource,
+ _pdev: platform::Device,
+}
+
+const MODE_CONFIG_INFO: ModeConfigInfo = ModeConfigInfo {
+ min_resolution: MIN_RES,
+ max_resolution: MAX_RES,
+ max_cursor: (512, 512),
+ preferred_depth: 0,
+};
+
+impl kernel::Module for Rvkms {
+ fn init(name: &'static CStr, module: &'static ThisModule) -> Result<Self> {
+ // We need to handle all of this from the true module_init, as we're a platform driver that
+ // binds to nothing - so we have to handle that portion of init ourselves like the real vkms
+ let mut pdev = platform::Device::register(c_str!("rvkms"), -1)?;
+ let dev = device::Device::from_dev(&pdev);
+
+ dev.pr_info(format_args!("Initializing RVKMS\n"));
+
+ // TODO: I wonder if there's any way we could get rid of having to pass raw pointers to
+ // this?
+ // no idea
+ let resource = dev.open_group(core::ptr::null_mut() as *mut core::ffi::c_void)?;
+
+ let reg: drv::Registration<RvkmsDriver> =
+ drv::Registration::new(&dev, Option::Some(MODE_CONFIG_INFO), module)?;
+ let drm_dev: ARef<RvkmsDevice> = ARef::from(reg.device());
+ let reg_info = reg.registration_info();
+ let output = Output::new(&drm_dev, 0)?;
+ let data = kernel::new_device_data!(
+ reg,
+ Resources,
+ Data { },
+ "RvkmsDeviceData"
+ )?;
+
+ drm_dev.mode_config_reset();
+
+ dev.dma_coerce_mask_and_coherent(kernel::dma::dma_bit_mask(64))?;
+
+ drv::Registration::register(reg_info, data.into(), 0, module)?;
+
+ Ok(Self {
+ drm: drm_dev,
+ output,
+ _resource: resource,
+ _pdev: pdev,
+ })
+ }
+}
+
+module! {
+ type: Rvkms,
+ name: "rvkms",
+ author: "Lyude Paul",
+ description: "Rust VKMS Proof of Concept driver",
+ license: "GPL v2",
+}
This introduces a work in progress port of the VKMS driver to rust to provide a user of the kernel's new rust bindings for KMS drivers! This driver is very incomplete, I'm not even sure if it loads right now without crashing (but it did at one point, and I'll be checking very soon!). Squash into rvkms introduction Signed-off-by: Lyude Paul <lyude@redhat.com> --- drivers/gpu/drm/Kconfig | 2 + drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/rvkms/Kconfig | 3 + drivers/gpu/drm/rvkms/Makefile | 1 + drivers/gpu/drm/rvkms/connector.rs | 55 +++++++++++ drivers/gpu/drm/rvkms/crtc.rs | 40 ++++++++ drivers/gpu/drm/rvkms/encoder.rs | 26 +++++ drivers/gpu/drm/rvkms/file.rs | 22 +++++ drivers/gpu/drm/rvkms/gem.rs | 32 +++++++ drivers/gpu/drm/rvkms/output.rs | 72 ++++++++++++++ drivers/gpu/drm/rvkms/plane.rs | 39 ++++++++ drivers/gpu/drm/rvkms/rvkms.rs | 146 +++++++++++++++++++++++++++++ 12 files changed, 439 insertions(+) create mode 100644 drivers/gpu/drm/rvkms/Kconfig create mode 100644 drivers/gpu/drm/rvkms/Makefile create mode 100644 drivers/gpu/drm/rvkms/connector.rs create mode 100644 drivers/gpu/drm/rvkms/crtc.rs create mode 100644 drivers/gpu/drm/rvkms/encoder.rs create mode 100644 drivers/gpu/drm/rvkms/file.rs create mode 100644 drivers/gpu/drm/rvkms/gem.rs create mode 100644 drivers/gpu/drm/rvkms/output.rs create mode 100644 drivers/gpu/drm/rvkms/plane.rs create mode 100644 drivers/gpu/drm/rvkms/rvkms.rs