summaryrefslogtreecommitdiff
path: root/drivers/gpu/nova-core/falcon/gsp.rs
blob: 1faefaede9fe6dd742787d6b8f5fbc2abf134e2b (plain) (blame)
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
// SPDX-License-Identifier: GPL-2.0

use kernel::{
    io::{
        io_project,
        poll::read_poll_timeout,
        register,
        Io,
        Mmio, //
    },
    prelude::*,
    time::Delta, //
};

use crate::{
    driver::{
        Bar0,
        NovaRegisters, //
    },
    falcon::{
        Falcon,
        FalconEngine, //
    },
    regs,
};

/// Type specifying the `Gsp` falcon engine. Cannot be instantiated.
pub(crate) struct Gsp(());

register! {
    base: NovaRegisters;

    PFALCON: super::PFalconRegisters @ 0x00110000;
    PFALCON2: super::PFalcon2Registers @ 0x00111000;
}

impl FalconEngine for Gsp {
    #[inline]
    fn pfalcon(io: Bar0<'_>) -> Mmio<'_, super::PFalconRegisters> {
        io_project!(io, build: PFALCON)
    }

    #[inline]
    fn pfalcon2(io: Bar0<'_>) -> Mmio<'_, super::PFalcon2Registers> {
        io_project!(io, build: PFALCON2)
    }
}

impl<'a> Falcon<'a, Gsp> {
    /// Clears the SWGEN0 latch in the GSP falcon.
    ///
    /// While the latch is set, no later message signals the tree, so a caller that consumed a
    /// notification by polling must clear it.
    pub(crate) fn clear_swgen0_intr(&self) {
        self.pfalcon
            .write_reg(regs::NV_PFALCON_FALCON_IRQSCLR::zeroed().with_swgen0(true));
    }

    /// Reads the GSP falcon causes that are routed to the host, without clearing any latch.
    ///
    /// Every one of them other than SWGEN0 reports a GSP fault.
    pub(crate) fn read_host_intr(&self) -> regs::NV_PFALCON_FALCON_IRQSTAT {
        let latched = self.pfalcon.read(regs::NV_PFALCON_FALCON_IRQSTAT);

        self.hal.host_routed_causes(self, latched)
    }

    /// Reads the host-routed causes and clears the SWGEN0 latch if it was set.
    ///
    /// Returns the causes as read, before the clear. No other latch changes.
    pub(crate) fn take_host_intr(&self) -> regs::NV_PFALCON_FALCON_IRQSTAT {
        let status = self.read_host_intr();

        if status.swgen0() {
            self.clear_swgen0_intr();
        }

        status
    }

    /// Clears the latch of every interrupt cause set in `status`.
    ///
    /// A cause driven from outside the falcon is still set on return, and
    /// [`Self::read_host_intr`] reports the causes that remain.
    pub(crate) fn clear_intr(&self, status: regs::NV_PFALCON_FALCON_IRQSTAT) {
        self.pfalcon
            .write_reg(regs::NV_PFALCON_FALCON_IRQSCLR::from(status.into_raw()));
    }

    /// Retriggers the GSP falcon, which then re-emits its host-routed causes into the tree.
    ///
    /// Call this only once every host cause is clear. A cause still set is re-emitted at once, and
    /// its vector arrives again as soon as delivery is rearmed.
    ///
    /// Does nothing on Turing, whose falcons have no retrigger register.
    pub(crate) fn retrigger_intr(&self) {
        self.hal.retrigger(self);
    }

    /// Checks if GSP reload/resume has completed during the boot process.
    pub(crate) fn check_reload_completed(&self, timeout: Delta) -> Result<bool> {
        read_poll_timeout(
            || Ok(self.bar.read(regs::NV_PGC6_BSI_SECURE_SCRATCH_14)),
            |val| val.boot_stage_3_handoff(),
            Delta::ZERO,
            timeout,
        )
        .map(|_| true)
    }

    /// Returns whether the RISC-V branch privilege lockdown bit is set.
    pub(crate) fn riscv_branch_privilege_lockdown(&self) -> bool {
        self.pfalcon
            .read(regs::NV_PFALCON_FALCON_HWCFG2)
            .riscv_br_priv_lockdown()
    }

    /// Returns whether GSP registers can be read by the CPU.
    pub(crate) fn priv_target_mask_released(&self) -> bool {
        /// Pattern returned by GSP register reads while the PRIV target mask still blocks CPU
        /// access. The low byte varies; the upper 24 bits are fixed.
        const LOCKED_PATTERN: u32 = 0xbadf_4100;
        const LOCKED_MASK: u32 = 0xffff_ff00;

        let hwcfg2 = self.pfalcon.read(regs::NV_PFALCON_FALCON_HWCFG2).into_raw();

        hwcfg2 != 0 && (hwcfg2 & LOCKED_MASK) != LOCKED_PATTERN
    }
}