summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/nova/driver.rs23
-rw-r--r--drivers/gpu/drm/nova/gpu.rs59
-rw-r--r--drivers/gpu/drm/nova/gsp.rs85
-rw-r--r--drivers/gpu/drm/nova/nova.rs1
4 files changed, 148 insertions, 20 deletions
diff --git a/drivers/gpu/drm/nova/driver.rs b/drivers/gpu/drm/nova/driver.rs
index 33abf2545994..84e01dc04f82 100644
--- a/drivers/gpu/drm/nova/driver.rs
+++ b/drivers/gpu/drm/nova/driver.rs
@@ -22,6 +22,29 @@ struct NovaDevice;
/// BAR Size
pub(crate) const BAR_SIZE: usize = 16777216;
+use core::ops::{Add, BitAnd, Div, Not, Sub};
+
+/// Aligns an integer type to a power of two.
+pub(crate) fn align<T>(a: T, b: T) -> T
+where
+ T: Copy
+ + Default
+ + BitAnd<Output = T>
+ + Not<Output = T>
+ + Add<Output = T>
+ + Sub<Output = T>
+ + Div<Output = T>
+ + core::cmp::PartialEq,
+{
+ let def: T = Default::default();
+ #[allow(clippy::eq_op)]
+ let one: T = !def / !def;
+
+ assert!((b & (b - one)) == def);
+
+ (a + b - one) & !(b - one)
+}
+
impl pci::Driver for NovaDevice {
define_pci_id_table! {
diff --git a/drivers/gpu/drm/nova/gpu.rs b/drivers/gpu/drm/nova/gpu.rs
index d3f1890953b1..d8b80653bad8 100644
--- a/drivers/gpu/drm/nova/gpu.rs
+++ b/drivers/gpu/drm/nova/gpu.rs
@@ -2,15 +2,15 @@
use kernel::{
error::Result,
io_mem::IoMem,
- c_str,
- firmware::{Firmware},
pci,
+ prelude::*,
};
use crate::bios::*;
-
+use crate::gsp::*;
use crate::driver::BAR_SIZE;
+#[derive(PartialEq)]
pub(crate) enum CardType {
TU100 = 0x160,
GA100 = 0x170,
@@ -18,46 +18,65 @@ pub(crate) enum CardType {
}
pub(crate) struct Gpu {
- booter_load_fw: Firmware,
- booter_unload_fw: Firmware,
- gsp_fw: Firmware,
+ vidmem_size: u64,
+ vga_workspace_addr: u64,
+ vga_workspace_size: u64,
card_type: CardType,
bar: IoMem<BAR_SIZE>,
- bios: Bios
+ bios: Bios,
+ gsp: Gsp,
}
impl Gpu {
pub(crate) fn new(card_type: CardType, bar: IoMem<BAR_SIZE>) -> Self
{
Self {
- booter_load_fw: Firmware::new(),
- booter_unload_fw: Firmware::new(),
- gsp_fw: Firmware::new(),
card_type: card_type,
bar: bar,
+ vidmem_size: 0,
+ vga_workspace_addr: 0,
+ vga_workspace_size : 0,
bios: Bios::new(),
+ gsp: Gsp::new(),
}
}
- pub(crate) fn init(&mut self, dev: &mut pci::Device) -> Result {
- match self.booter_load_fw.request(c_str!("nvidia/ad102/gsp/booter_load-535.113.01.bin"), dev) {
- Err(e) => return Err(e),
- Ok(_) => ()
+ fn gsp_vga_workspace_addr(&self) -> u64
+ {
+ let base: u64 = self.vidmem_size - 0x100000;
+ let mut addr: u64 = self.bar.readl(0x625f04) as u64;
+
+ if (addr & 0x00000008) == 0 {
+ return base;
}
- match self.booter_unload_fw.request(c_str!("nvidia/ad102/gsp/booter_unload-535.113.01.bin"), dev) {
- Err(e) => return Err(e),
- Ok(_) => ()
+ addr = (addr & 0xffffff00) << 8;
+ if addr < base {
+ return self.vidmem_size - 0x20000;
}
+ addr
+ }
- match self.gsp_fw.request(c_str!("nvidia/ad102/gsp/gsp-535.113.01.bin"), dev) {
- Err(e) => return Err(e),
- Ok(_) => (),
+ pub(crate) fn init(&mut self, dev: &mut pci::Device) -> Result {
+ // AD102 specific
+
+ if self.card_type != CardType::AD100 {
+ return Err(ENOENT);
}
+ self.vidmem_size = (self.bar.readl(0x1183a4) as u64) << 20;
+
+ self.vga_workspace_addr = self.gsp_vga_workspace_addr();
+ self.vga_workspace_size = self.vidmem_size - self.vga_workspace_addr;
+
+ pr_info!("video memory size {:#x}: vga {:#x} {:#x}\n", self.vidmem_size, self.vga_workspace_addr,
+ self.vga_workspace_size);
+
self.bios.probe(&self.bar)?;
self.bios.find_fwsec()?;
+
+ self.gsp.init(dev)?;
Ok(())
}
}
diff --git a/drivers/gpu/drm/nova/gsp.rs b/drivers/gpu/drm/nova/gsp.rs
new file mode 100644
index 000000000000..53367aba2210
--- /dev/null
+++ b/drivers/gpu/drm/nova/gsp.rs
@@ -0,0 +1,85 @@
+use kernel::{
+ error::Result,
+ c_str,
+ firmware::{Firmware},
+ pci,
+ dma::{CoherentAllocation, CoherentAllocator,try_alloc_coherent},
+};
+
+use alloc::vec::Vec;
+use crate::driver::align;
+
+const GSP_PAGE_SHIFT: u32 = 12;
+const GSP_PAGE_SIZE: u32 = 1 << GSP_PAGE_SHIFT;
+
+#[derive(Default)]
+pub(crate) struct GspRadix3 {
+ pub(crate) mem: Vec<CoherentAllocation<u64, CoherentAllocator>>,
+}
+
+impl GspRadix3 {
+
+ pub (crate) fn try_new(size: usize, dev: &mut pci::Device) -> Result<GspRadix3>
+ {
+ let mut gsp_radix3: GspRadix3 = Default::default();
+ let mut lvl_size = size;
+ let addr = 0;
+ for i in (0..2).rev() {
+ let tbl_size: usize = align::<usize>((lvl_size as usize / 4096) * 8 as usize, GSP_PAGE_SIZE as usize);
+
+ gsp_radix3.mem.try_push(try_alloc_coherent(dev, tbl_size as usize, false)?)?;
+
+ if i == 2 {
+ // TODO this is the main piece
+ } else {
+ for j in 0..size / GSP_PAGE_SIZE as usize {
+ let entry: u64 = (addr + GSP_PAGE_SIZE as usize * j) as u64;
+ gsp_radix3.mem[i].write(j, &entry);
+ }
+ }
+
+ lvl_size = tbl_size;
+ }
+ Ok(gsp_radix3)
+ }
+
+}
+
+pub(crate) struct Gsp {
+ booter_load_fw: Firmware,
+ booter_unload_fw: Firmware,
+ gsp_fw: Firmware,
+ radix3: Option<GspRadix3>,
+}
+
+impl Gsp {
+ pub(crate) fn new() -> Self
+ {
+ Self {
+ booter_load_fw: Firmware::new(),
+ booter_unload_fw: Firmware::new(),
+ gsp_fw: Firmware::new(),
+ radix3: None,
+ }
+ }
+
+ pub(crate) fn init(&mut self, dev: &mut pci::Device) -> Result {
+ match self.booter_load_fw.request(c_str!("nvidia/ad102/gsp/booter_load-535.113.01.bin"), dev) {
+ Err(e) => return Err(e),
+ Ok(_) => ()
+ }
+
+ match self.booter_unload_fw.request(c_str!("nvidia/ad102/gsp/booter_unload-535.113.01.bin"), dev) {
+ Err(e) => return Err(e),
+ Ok(_) => ()
+ }
+
+ match self.gsp_fw.request(c_str!("nvidia/ad102/gsp/gsp-535.113.01.bin"), dev) {
+ Err(e) => return Err(e),
+ Ok(_) => (),
+ }
+
+ self.radix3 = Some(GspRadix3::try_new(1024, dev)?);
+ Ok(())
+ }
+}
diff --git a/drivers/gpu/drm/nova/nova.rs b/drivers/gpu/drm/nova/nova.rs
index 0289fce7d2d5..06623fff33f3 100644
--- a/drivers/gpu/drm/nova/nova.rs
+++ b/drivers/gpu/drm/nova/nova.rs
@@ -3,6 +3,7 @@
mod driver;
mod bios;
mod fwsec;
+mod gsp;
mod gpu;
use kernel::prelude::module;