diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/nova/driver.rs | 23 | ||||
-rw-r--r-- | drivers/gpu/drm/nova/gpu.rs | 59 | ||||
-rw-r--r-- | drivers/gpu/drm/nova/gsp.rs | 85 | ||||
-rw-r--r-- | drivers/gpu/drm/nova/nova.rs | 1 |
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; |