mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
synced 2025-08-29 02:59:13 +00:00
drm: nova-drm: add initial driver skeleton
Add the initial nova-drm driver skeleton. nova-drm is connected to nova-core through the auxiliary bus and implements the DRM parts of the nova driver stack. For now, it implements the fundamental DRM abstractions, i.e. creates a DRM device and registers it, exposing a three sample IOCTLs. DRM_IOCTL_NOVA_GETPARAM - provides the PCI bar size from the bar that maps the GPUs VRAM from nova-core DRM_IOCTL_NOVA_GEM_CREATE - creates a new dummy DRM GEM object and returns a handle DRM_IOCTL_NOVA_GEM_INFO - provides metadata for the DRM GEM object behind a given handle I implemented a small userspace test suite [1] that utilizes this interface. Link: https://gitlab.freedesktop.org/dakr/drm-test [1] Reviewed-by: Maxime Ripard <mripard@kernel.org> Acked-by: Dave Airlie <airlied@redhat.com> Link: https://lore.kernel.org/r/20250424160452.8070-3-dakr@kernel.org [ Kconfig: depend on DRM=y rather than just DRM. - Danilo ] Signed-off-by: Danilo Krummrich <dakr@kernel.org>
This commit is contained in:
parent
e041d81a03
commit
cdeaeb9dd7
12
MAINTAINERS
12
MAINTAINERS
@ -7594,6 +7594,18 @@ T: git https://gitlab.freedesktop.org/drm/nova.git nova-next
|
||||
F: Documentation/gpu/nova/
|
||||
F: drivers/gpu/nova-core/
|
||||
|
||||
DRM DRIVER FOR NVIDIA GPUS [RUST]
|
||||
M: Danilo Krummrich <dakr@kernel.org>
|
||||
L: nouveau@lists.freedesktop.org
|
||||
S: Supported
|
||||
Q: https://patchwork.freedesktop.org/project/nouveau/
|
||||
B: https://gitlab.freedesktop.org/drm/nova/-/issues
|
||||
C: irc://irc.oftc.net/nouveau
|
||||
T: git https://gitlab.freedesktop.org/drm/nova.git nova-next
|
||||
F: Documentation/gpu/nova/
|
||||
F: drivers/gpu/drm/nova/
|
||||
F: include/uapi/drm/nova_drm.h
|
||||
|
||||
DRM DRIVER FOR OLIMEX LCD-OLINUXINO PANELS
|
||||
M: Stefan Mavrodiev <stefan@olimex.com>
|
||||
S: Maintained
|
||||
|
@ -343,6 +343,8 @@ source "drivers/gpu/drm/amd/amdgpu/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/nouveau/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/nova/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/i915/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/xe/Kconfig"
|
||||
|
@ -176,6 +176,7 @@ obj-$(CONFIG_DRM_VMWGFX)+= vmwgfx/
|
||||
obj-$(CONFIG_DRM_VGEM) += vgem/
|
||||
obj-$(CONFIG_DRM_VKMS) += vkms/
|
||||
obj-$(CONFIG_DRM_NOUVEAU) +=nouveau/
|
||||
obj-$(CONFIG_DRM_NOVA) += nova/
|
||||
obj-$(CONFIG_DRM_EXYNOS) +=exynos/
|
||||
obj-$(CONFIG_DRM_ROCKCHIP) +=rockchip/
|
||||
obj-$(CONFIG_DRM_GMA500) += gma500/
|
||||
|
14
drivers/gpu/drm/nova/Kconfig
Normal file
14
drivers/gpu/drm/nova/Kconfig
Normal file
@ -0,0 +1,14 @@
|
||||
config DRM_NOVA
|
||||
tristate "Nova DRM driver"
|
||||
depends on AUXILIARY_BUS
|
||||
depends on DRM=y
|
||||
depends on PCI
|
||||
depends on RUST
|
||||
default n
|
||||
help
|
||||
Choose this if you want to build the Nova DRM driver for Nvidia
|
||||
GSP-based GPUs.
|
||||
|
||||
This driver is work in progress and may not be functional.
|
||||
|
||||
If M is selected, the module will be called nova.
|
3
drivers/gpu/drm/nova/Makefile
Normal file
3
drivers/gpu/drm/nova/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
obj-$(CONFIG_DRM_NOVA) += nova.o
|
69
drivers/gpu/drm/nova/driver.rs
Normal file
69
drivers/gpu/drm/nova/driver.rs
Normal file
@ -0,0 +1,69 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
use kernel::{auxiliary, c_str, device::Core, drm, drm::gem, drm::ioctl, prelude::*, types::ARef};
|
||||
|
||||
use crate::file::File;
|
||||
use crate::gem::NovaObject;
|
||||
|
||||
pub(crate) struct NovaDriver {
|
||||
#[expect(unused)]
|
||||
drm: ARef<drm::Device<Self>>,
|
||||
}
|
||||
|
||||
/// Convienence type alias for the DRM device type for this driver
|
||||
pub(crate) type NovaDevice = drm::Device<NovaDriver>;
|
||||
|
||||
#[pin_data]
|
||||
pub(crate) struct NovaData {
|
||||
pub(crate) adev: ARef<auxiliary::Device>,
|
||||
}
|
||||
|
||||
const INFO: drm::DriverInfo = drm::DriverInfo {
|
||||
major: 0,
|
||||
minor: 0,
|
||||
patchlevel: 0,
|
||||
name: c_str!("nova"),
|
||||
desc: c_str!("Nvidia Graphics"),
|
||||
};
|
||||
|
||||
const NOVA_CORE_MODULE_NAME: &CStr = c_str!("NovaCore");
|
||||
const AUXILIARY_NAME: &CStr = c_str!("nova-drm");
|
||||
|
||||
kernel::auxiliary_device_table!(
|
||||
AUX_TABLE,
|
||||
MODULE_AUX_TABLE,
|
||||
<NovaDriver as auxiliary::Driver>::IdInfo,
|
||||
[(
|
||||
auxiliary::DeviceId::new(NOVA_CORE_MODULE_NAME, AUXILIARY_NAME),
|
||||
()
|
||||
)]
|
||||
);
|
||||
|
||||
impl auxiliary::Driver for NovaDriver {
|
||||
type IdInfo = ();
|
||||
const ID_TABLE: auxiliary::IdTable<Self::IdInfo> = &AUX_TABLE;
|
||||
|
||||
fn probe(adev: &auxiliary::Device<Core>, _info: &Self::IdInfo) -> Result<Pin<KBox<Self>>> {
|
||||
let data = try_pin_init!(NovaData { adev: adev.into() });
|
||||
|
||||
let drm = drm::Device::<Self>::new(adev.as_ref(), data)?;
|
||||
drm::Registration::new_foreign_owned(&drm, adev.as_ref(), 0)?;
|
||||
|
||||
Ok(KBox::new(Self { drm }, GFP_KERNEL)?.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[vtable]
|
||||
impl drm::Driver for NovaDriver {
|
||||
type Data = NovaData;
|
||||
type File = File;
|
||||
type Object = gem::Object<NovaObject>;
|
||||
|
||||
const INFO: drm::DriverInfo = INFO;
|
||||
|
||||
kernel::declare_drm_ioctls! {
|
||||
(NOVA_GETPARAM, drm_nova_getparam, ioctl::RENDER_ALLOW, File::get_param),
|
||||
(NOVA_GEM_CREATE, drm_nova_gem_create, ioctl::AUTH | ioctl::RENDER_ALLOW, File::gem_create),
|
||||
(NOVA_GEM_INFO, drm_nova_gem_info, ioctl::AUTH | ioctl::RENDER_ALLOW, File::gem_info),
|
||||
}
|
||||
}
|
74
drivers/gpu/drm/nova/file.rs
Normal file
74
drivers/gpu/drm/nova/file.rs
Normal file
@ -0,0 +1,74 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
use crate::driver::{NovaDevice, NovaDriver};
|
||||
use crate::gem::NovaObject;
|
||||
use crate::uapi::{GemCreate, GemInfo, Getparam};
|
||||
use kernel::{
|
||||
alloc::flags::*,
|
||||
drm::{self, gem::BaseObject},
|
||||
pci,
|
||||
prelude::*,
|
||||
types::Opaque,
|
||||
uapi,
|
||||
};
|
||||
|
||||
pub(crate) struct File;
|
||||
|
||||
impl drm::file::DriverFile for File {
|
||||
type Driver = NovaDriver;
|
||||
|
||||
fn open(_dev: &NovaDevice) -> Result<Pin<KBox<Self>>> {
|
||||
Ok(KBox::new(Self, GFP_KERNEL)?.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl File {
|
||||
/// IOCTL: get_param: Query GPU / driver metadata.
|
||||
pub(crate) fn get_param(
|
||||
dev: &NovaDevice,
|
||||
getparam: &Opaque<uapi::drm_nova_getparam>,
|
||||
_file: &drm::File<File>,
|
||||
) -> Result<u32> {
|
||||
let adev = &dev.adev;
|
||||
let parent = adev.parent().ok_or(ENOENT)?;
|
||||
let pdev: &pci::Device = parent.try_into()?;
|
||||
let getparam: &Getparam = getparam.into();
|
||||
|
||||
let value = match getparam.param() as u32 {
|
||||
uapi::NOVA_GETPARAM_VRAM_BAR_SIZE => pdev.resource_len(1)?,
|
||||
_ => return Err(EINVAL),
|
||||
};
|
||||
|
||||
getparam.set_value(value);
|
||||
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
/// IOCTL: gem_create: Create a new DRM GEM object.
|
||||
pub(crate) fn gem_create(
|
||||
dev: &NovaDevice,
|
||||
req: &Opaque<uapi::drm_nova_gem_create>,
|
||||
file: &drm::File<File>,
|
||||
) -> Result<u32> {
|
||||
let req: &GemCreate = req.into();
|
||||
let obj = NovaObject::new(dev, req.size().try_into()?)?;
|
||||
|
||||
req.set_handle(obj.create_handle(file)?);
|
||||
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
/// IOCTL: gem_info: Query GEM metadata.
|
||||
pub(crate) fn gem_info(
|
||||
_dev: &NovaDevice,
|
||||
req: &Opaque<uapi::drm_nova_gem_info>,
|
||||
file: &drm::File<File>,
|
||||
) -> Result<u32> {
|
||||
let req: &GemInfo = req.into();
|
||||
let bo = NovaObject::lookup_handle(file, req.handle())?;
|
||||
|
||||
req.set_size(bo.size().try_into()?);
|
||||
|
||||
Ok(0)
|
||||
}
|
||||
}
|
49
drivers/gpu/drm/nova/gem.rs
Normal file
49
drivers/gpu/drm/nova/gem.rs
Normal file
@ -0,0 +1,49 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
use kernel::{
|
||||
drm,
|
||||
drm::{gem, gem::BaseObject},
|
||||
prelude::*,
|
||||
types::ARef,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
driver::{NovaDevice, NovaDriver},
|
||||
file::File,
|
||||
};
|
||||
|
||||
/// GEM Object inner driver data
|
||||
#[pin_data]
|
||||
pub(crate) struct NovaObject {}
|
||||
|
||||
impl gem::BaseDriverObject<gem::Object<NovaObject>> for NovaObject {
|
||||
fn new(_dev: &NovaDevice, _size: usize) -> impl PinInit<Self, Error> {
|
||||
try_pin_init!(NovaObject {})
|
||||
}
|
||||
}
|
||||
|
||||
impl gem::DriverObject for NovaObject {
|
||||
type Driver = NovaDriver;
|
||||
}
|
||||
|
||||
impl NovaObject {
|
||||
/// Create a new DRM GEM object.
|
||||
pub(crate) fn new(dev: &NovaDevice, size: usize) -> Result<ARef<gem::Object<Self>>> {
|
||||
let aligned_size = size.next_multiple_of(1 << 12);
|
||||
|
||||
if size == 0 || size > aligned_size {
|
||||
return Err(EINVAL);
|
||||
}
|
||||
|
||||
gem::Object::new(dev, aligned_size)
|
||||
}
|
||||
|
||||
/// Look up a GEM object handle for a `File` and return an `ObjectRef` for it.
|
||||
#[inline]
|
||||
pub(crate) fn lookup_handle(
|
||||
file: &drm::File<File>,
|
||||
handle: u32,
|
||||
) -> Result<ARef<gem::Object<Self>>> {
|
||||
gem::Object::lookup_handle(file, handle)
|
||||
}
|
||||
}
|
18
drivers/gpu/drm/nova/nova.rs
Normal file
18
drivers/gpu/drm/nova/nova.rs
Normal file
@ -0,0 +1,18 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
//! Nova DRM Driver
|
||||
|
||||
mod driver;
|
||||
mod file;
|
||||
mod gem;
|
||||
mod uapi;
|
||||
|
||||
use crate::driver::NovaDriver;
|
||||
|
||||
kernel::module_auxiliary_driver! {
|
||||
type: NovaDriver,
|
||||
name: "Nova",
|
||||
author: "Danilo Krummrich",
|
||||
description: "Nova GPU driver",
|
||||
license: "GPL v2",
|
||||
}
|
61
drivers/gpu/drm/nova/uapi.rs
Normal file
61
drivers/gpu/drm/nova/uapi.rs
Normal file
@ -0,0 +1,61 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
use kernel::uapi;
|
||||
|
||||
// TODO Work out some common infrastructure to avoid boilerplate code for uAPI abstractions.
|
||||
|
||||
macro_rules! define_uapi_abstraction {
|
||||
($name:ident <= $inner:ty) => {
|
||||
#[repr(transparent)]
|
||||
pub struct $name(::kernel::types::Opaque<$inner>);
|
||||
|
||||
impl ::core::convert::From<&::kernel::types::Opaque<$inner>> for &$name {
|
||||
fn from(value: &::kernel::types::Opaque<$inner>) -> Self {
|
||||
// SAFETY: `Self` is a transparent wrapper of `$inner`.
|
||||
unsafe { ::core::mem::transmute(value) }
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
define_uapi_abstraction!(Getparam <= uapi::drm_nova_getparam);
|
||||
|
||||
impl Getparam {
|
||||
pub fn param(&self) -> u64 {
|
||||
// SAFETY: `self.get()` is a valid pointer to a `struct drm_nova_getparam`.
|
||||
unsafe { (*self.0.get()).param }
|
||||
}
|
||||
|
||||
pub fn set_value(&self, v: u64) {
|
||||
// SAFETY: `self.get()` is a valid pointer to a `struct drm_nova_getparam`.
|
||||
unsafe { (*self.0.get()).value = v };
|
||||
}
|
||||
}
|
||||
|
||||
define_uapi_abstraction!(GemCreate <= uapi::drm_nova_gem_create);
|
||||
|
||||
impl GemCreate {
|
||||
pub fn size(&self) -> u64 {
|
||||
// SAFETY: `self.get()` is a valid pointer to a `struct drm_nova_gem_create`.
|
||||
unsafe { (*self.0.get()).size }
|
||||
}
|
||||
|
||||
pub fn set_handle(&self, handle: u32) {
|
||||
// SAFETY: `self.get()` is a valid pointer to a `struct drm_nova_gem_create`.
|
||||
unsafe { (*self.0.get()).handle = handle };
|
||||
}
|
||||
}
|
||||
|
||||
define_uapi_abstraction!(GemInfo <= uapi::drm_nova_gem_info);
|
||||
|
||||
impl GemInfo {
|
||||
pub fn handle(&self) -> u32 {
|
||||
// SAFETY: `self.get()` is a valid pointer to a `struct drm_nova_gem_info`.
|
||||
unsafe { (*self.0.get()).handle }
|
||||
}
|
||||
|
||||
pub fn set_size(&self, size: u64) {
|
||||
// SAFETY: `self.get()` is a valid pointer to a `struct drm_nova_gem_info`.
|
||||
unsafe { (*self.0.get()).size = size };
|
||||
}
|
||||
}
|
101
include/uapi/drm/nova_drm.h
Normal file
101
include/uapi/drm/nova_drm.h
Normal file
@ -0,0 +1,101 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef __NOVA_DRM_H__
|
||||
#define __NOVA_DRM_H__
|
||||
|
||||
#include "drm.h"
|
||||
|
||||
/* DISCLAIMER: Do not use, this is not a stable uAPI.
|
||||
*
|
||||
* This uAPI serves only testing purposes as long as this driver is still in
|
||||
* development. It is required to implement and test infrastructure which is
|
||||
* upstreamed in the context of this driver. See also [1].
|
||||
*
|
||||
* [1] https://lore.kernel.org/dri-devel/Zfsj0_tb-0-tNrJy@cassiopeiae/T/#u
|
||||
*/
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* NOVA_GETPARAM_VRAM_BAR_SIZE
|
||||
*
|
||||
* Query the VRAM BAR size in bytes.
|
||||
*/
|
||||
#define NOVA_GETPARAM_VRAM_BAR_SIZE 0x1
|
||||
|
||||
/**
|
||||
* struct drm_nova_getparam - query GPU and driver metadata
|
||||
*/
|
||||
struct drm_nova_getparam {
|
||||
/**
|
||||
* @param: The identifier of the parameter to query.
|
||||
*/
|
||||
__u64 param;
|
||||
|
||||
/**
|
||||
* @value: The value for the specified parameter.
|
||||
*/
|
||||
__u64 value;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct drm_nova_gem_create - create a new DRM GEM object
|
||||
*/
|
||||
struct drm_nova_gem_create {
|
||||
/**
|
||||
* @handle: The handle of the new DRM GEM object.
|
||||
*/
|
||||
__u32 handle;
|
||||
|
||||
/**
|
||||
* @pad: 32 bit padding, should be 0.
|
||||
*/
|
||||
__u32 pad;
|
||||
|
||||
/**
|
||||
* @size: The size of the new DRM GEM object.
|
||||
*/
|
||||
__u64 size;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct drm_nova_gem_info - query DRM GEM object metadata
|
||||
*/
|
||||
struct drm_nova_gem_info {
|
||||
/**
|
||||
* @handle: The handle of the DRM GEM object to query.
|
||||
*/
|
||||
__u32 handle;
|
||||
|
||||
/**
|
||||
* @pad: 32 bit padding, should be 0.
|
||||
*/
|
||||
__u32 pad;
|
||||
|
||||
/**
|
||||
* @size: The size of the DRM GEM obejct.
|
||||
*/
|
||||
__u64 size;
|
||||
};
|
||||
|
||||
#define DRM_NOVA_GETPARAM 0x00
|
||||
#define DRM_NOVA_GEM_CREATE 0x01
|
||||
#define DRM_NOVA_GEM_INFO 0x02
|
||||
|
||||
/* Note: this is an enum so that it can be resolved by Rust bindgen. */
|
||||
enum {
|
||||
DRM_IOCTL_NOVA_GETPARAM = DRM_IOWR(DRM_COMMAND_BASE + DRM_NOVA_GETPARAM,
|
||||
struct drm_nova_getparam),
|
||||
DRM_IOCTL_NOVA_GEM_CREATE = DRM_IOWR(DRM_COMMAND_BASE + DRM_NOVA_GEM_CREATE,
|
||||
struct drm_nova_gem_create),
|
||||
DRM_IOCTL_NOVA_GEM_INFO = DRM_IOWR(DRM_COMMAND_BASE + DRM_NOVA_GEM_INFO,
|
||||
struct drm_nova_gem_info),
|
||||
};
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __NOVA_DRM_H__ */
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include <uapi/asm-generic/ioctl.h>
|
||||
#include <uapi/drm/drm.h>
|
||||
#include <uapi/drm/nova_drm.h>
|
||||
#include <uapi/linux/mdio.h>
|
||||
#include <uapi/linux/mii.h>
|
||||
#include <uapi/linux/ethtool.h>
|
||||
|
Loading…
Reference in New Issue
Block a user