summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/nova/gpu.rs
blob: d8b80653bad872a6d4c0d0ef60b21adb52d6ecdd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
use kernel::{
    error::Result,
    io_mem::IoMem,
    pci,
    prelude::*,
};

use crate::bios::*;
use crate::gsp::*;
use crate::driver::BAR_SIZE;

#[derive(PartialEq)]
pub(crate) enum CardType {
    TU100 = 0x160,
    GA100 = 0x170,
    AD100 = 0x190,
}

pub(crate) struct Gpu {
    vidmem_size: u64,
    vga_workspace_addr: u64,
    vga_workspace_size: u64,
    card_type: CardType,
    bar: IoMem<BAR_SIZE>,
    bios: Bios,
    gsp: Gsp,
}

impl Gpu {
    pub(crate) fn new(card_type: CardType, bar: IoMem<BAR_SIZE>) -> Self
    {
        Self {
            card_type: card_type,
            bar: bar,
            vidmem_size: 0,
            vga_workspace_addr: 0,
            vga_workspace_size : 0,
            bios: Bios::new(),
            gsp: Gsp::new(),
        }
    }

    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;
        }

        addr = (addr & 0xffffff00) << 8;
        if addr < base {
            return self.vidmem_size - 0x20000;
        }
        addr
    }

    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(())
    }
}