This is still very preliminary work, and is mostly designed to show how
register fields can be turned into safe types that force us to handle
invalid values.

Signed-off-by: Alexandre Courbot <acour...@nvidia.com>
---
 drivers/gpu/nova-core/driver.rs    |   2 +-
 drivers/gpu/nova-core/falcon.rs    | 618 +++++++++++++++++++++++++++++++++++++
 drivers/gpu/nova-core/gpu.rs       |  13 +
 drivers/gpu/nova-core/nova_core.rs |   1 +
 drivers/gpu/nova-core/regs.rs      | 188 ++++++++++-
 5 files changed, 820 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver.rs
index 
0cd23aa306e4082405f480afc0530a41131485e7..dee5fd22eecb2ce1f4ea765338b0c1b68853b2d3
 100644
--- a/drivers/gpu/nova-core/driver.rs
+++ b/drivers/gpu/nova-core/driver.rs
@@ -10,7 +10,7 @@ pub(crate) struct NovaCore {
     pub(crate) gpu: Gpu,
 }
 
-const BAR0_SIZE: usize = 0x9500;
+const BAR0_SIZE: usize = 0x1000000;
 pub(crate) type Bar0 = pci::Bar<BAR0_SIZE>;
 
 kernel::pci_device_table!(
diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon.rs
new file mode 100644
index 
0000000000000000000000000000000000000000..0dd4b45abbe0a62238efe24d899c55d5db348586
--- /dev/null
+++ b/drivers/gpu/nova-core/falcon.rs
@@ -0,0 +1,618 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Falcon microprocessor base support
+
+// TODO: remove this once this module is actively used.
+#![allow(dead_code)]
+
+use core::hint::unreachable_unchecked;
+use core::marker::PhantomData;
+use core::time::Duration;
+use kernel::bindings;
+use kernel::devres::Devres;
+use kernel::{pci, prelude::*};
+
+use crate::driver::Bar0;
+use crate::gpu::Chipset;
+use crate::regs;
+use crate::timer::Timer;
+
+#[repr(u8)]
+#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
+pub(crate) enum FalconCoreRev {
+    #[default]
+    Rev1 = 1,
+    Rev2 = 2,
+    Rev3 = 3,
+    Rev4 = 4,
+    Rev5 = 5,
+    Rev6 = 6,
+    Rev7 = 7,
+}
+
+impl TryFrom<u32> for FalconCoreRev {
+    type Error = Error;
+
+    fn try_from(value: u32) -> core::result::Result<Self, Self::Error> {
+        use FalconCoreRev::*;
+
+        let rev = match value {
+            1 => Rev1,
+            2 => Rev2,
+            3 => Rev3,
+            4 => Rev4,
+            5 => Rev5,
+            6 => Rev6,
+            7 => Rev7,
+            _ => return Err(EINVAL),
+        };
+
+        Ok(rev)
+    }
+}
+
+#[repr(u8)]
+#[derive(Debug, Default, Copy, Clone)]
+pub(crate) enum FalconSecurityModel {
+    #[default]
+    None = 0,
+    Light = 2,
+    Heavy = 3,
+}
+
+impl TryFrom<u32> for FalconSecurityModel {
+    type Error = Error;
+
+    fn try_from(value: u32) -> core::result::Result<Self, Self::Error> {
+        use FalconSecurityModel::*;
+
+        let sec_model = match value {
+            0 => None,
+            2 => Light,
+            3 => Heavy,
+            _ => return Err(EINVAL),
+        };
+
+        Ok(sec_model)
+    }
+}
+
+#[repr(u8)]
+#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
+pub(crate) enum FalconCoreRevSubversion {
+    #[default]
+    Subversion0 = 0,
+    Subversion1 = 1,
+    Subversion2 = 2,
+    Subversion3 = 3,
+}
+
+impl From<u32> for FalconCoreRevSubversion {
+    fn from(value: u32) -> Self {
+        use FalconCoreRevSubversion::*;
+
+        match value & 0b11 {
+            0 => Subversion0,
+            1 => Subversion1,
+            2 => Subversion2,
+            3 => Subversion3,
+            // SAFETY: the `0b11` mask limits the possible values to `0..=3`.
+            4..=u32::MAX => unsafe { unreachable_unchecked() },
+        }
+    }
+}
+
+#[repr(u8)]
+#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
+pub(crate) enum FalconModSelAlgo {
+    #[default]
+    Rsa3k = 1,
+}
+
+impl TryFrom<u32> for FalconModSelAlgo {
+    type Error = Error;
+
+    fn try_from(value: u32) -> core::result::Result<Self, Self::Error> {
+        match value {
+            1 => Ok(FalconModSelAlgo::Rsa3k),
+            _ => Err(EINVAL),
+        }
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub(crate) enum RiscvCoreSelect {
+    Falcon = 0,
+    Riscv = 1,
+}
+
+impl From<bool> for RiscvCoreSelect {
+    fn from(value: bool) -> Self {
+        match value {
+            false => RiscvCoreSelect::Falcon,
+            true => RiscvCoreSelect::Riscv,
+        }
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub(crate) enum FalconMem {
+    Imem,
+    Dmem,
+}
+
+#[repr(C)]
+#[derive(Debug, Clone, Copy)]
+pub(crate) struct FalconUCodeDescV3 {
+    pub(crate) hdr: u32,
+    pub(crate) stored_size: u32,
+    pub(crate) pkc_data_offset: u32,
+    pub(crate) interface_offset: u32,
+    pub(crate) imem_phys_base: u32,
+    pub(crate) imem_load_size: u32,
+    pub(crate) imem_virt_base: u32,
+    pub(crate) dmem_phys_base: u32,
+    pub(crate) dmem_load_size: u32,
+    pub(crate) engine_id_mask: u16,
+    pub(crate) ucode_id: u8,
+    pub(crate) signature_count: u8,
+    pub(crate) signature_versions: u16,
+    _reserved: u16,
+}
+
+impl FalconUCodeDescV3 {
+    pub(crate) fn ver(&self) -> u8 {
+        ((self.hdr & 0xff00) >> 8) as u8
+    }
+
+    pub(crate) fn size(&self) -> usize {
+        ((self.hdr & 0xffff0000) >> 16) as usize
+    }
+}
+
+/// Trait defining the parameters of a given Falcon instance.
+pub(crate) trait FalconInstance {
+    /// Base I/O address for the falcon, relative from which its registers are 
accessed.
+    const BASE: usize;
+}
+
+pub(crate) struct Gsp;
+impl FalconInstance for Gsp {
+    const BASE: usize = 0x00110000;
+}
+pub(crate) type GspFalcon = Falcon<Gsp>;
+
+pub(crate) struct Sec2;
+impl FalconInstance for Sec2 {
+    const BASE: usize = 0x00840000;
+}
+pub(crate) type Sec2Falcon = Falcon<Sec2>;
+
+/// Contains the base parameters common to all Falcon instances.
+#[derive(Debug)]
+pub(crate) struct Falcon<I: FalconInstance> {
+    /// Chipset this falcon belongs to.
+    chipset: Chipset,
+    /// Whether this falcon is part of a dual falcon/riscv engine.
+    has_riscv: bool,
+    _instance: PhantomData<I>,
+}
+
+impl<I: FalconInstance> Falcon<I> {
+    pub(crate) fn new(
+        pdev: &pci::Device,
+        chipset: Chipset,
+        bar: &Devres<Bar0>,
+        need_riscv: bool,
+    ) -> Result<Self> {
+        let hwcfg1 = with_bar!(bar, |b| regs::FalconHwcfg1::read(b, I::BASE))?;
+        let rev = hwcfg1.core_rev()?;
+        let subver = hwcfg1.core_rev_subversion();
+        let sec_model = hwcfg1.security_model()?;
+
+        if need_riscv {
+            let hwcfg2 = with_bar!(bar, |b| regs::FalconHwcfg2::read(b, 
I::BASE))?;
+            if !hwcfg2.riscv() {
+                dev_err!(
+                    pdev.as_ref(),
+                    "riscv support requested on falcon that does not support 
it\n"
+                );
+                return Err(EINVAL);
+            }
+        }
+
+        dev_info!(
+            pdev.as_ref(),
+            "new falcon: {:?} {:?} {:?}",
+            rev,
+            subver,
+            sec_model
+        );
+
+        Ok(Self {
+            chipset,
+            has_riscv: need_riscv,
+            _instance: PhantomData,
+        })
+    }
+
+    fn select_falcon_core(&self, bar: &Devres<Bar0>, timer: &Timer) -> 
Result<()> {
+        if self.has_riscv {
+            let bcr_ctrl = with_bar!(bar, |b| regs::RiscvBcrCtrl::read(b, 
I::BASE))?;
+            if bcr_ctrl.core_select() != RiscvCoreSelect::Falcon {
+                with_bar!(bar, |b| regs::RiscvBcrCtrl::default()
+                    .set_core_select(RiscvCoreSelect::Falcon)
+                    .write(b, I::BASE))?;
+
+                timer.wait_on(bar, Duration::from_millis(10), || {
+                    bar.try_access_with(|b| regs::RiscvBcrCtrl::read(b, 
I::BASE))
+                        .and_then(|v| if v.valid() { Some(()) } else { None })
+                })?;
+            }
+        }
+
+        Ok(())
+    }
+
+    fn reset_wait_mem_scrubbing(&self, bar: &Devres<Bar0>, timer: &Timer) -> 
Result<()> {
+        /* TODO: is this needed? */
+        with_bar!(bar, |b| regs::FalconMailbox0::alter(b, I::BASE, |v| v))?;
+
+        timer.wait_on(bar, Duration::from_millis(20), || {
+            bar.try_access_with(|b| regs::FalconHwcfg2::read(b, I::BASE))
+                .and_then(|r| if r.mem_scrubbing() { Some(()) } else { None })
+        })
+    }
+
+    fn reset_prep(&self, bar: &Devres<Bar0>, timer: &Timer) -> Result<()> {
+        let _ = with_bar!(bar, |b| regs::FalconHwcfg2::read(b, I::BASE))?;
+
+        // Expected to timeout apparently?
+        // TODO: check why with OpenRM.
+        let _ = timer.wait_on(bar, Duration::from_micros(150), || {
+            bar.try_access_with(|b| regs::FalconHwcfg2::read(b, I::BASE))
+                .and_then(|r| if r.unk_31() { Some(()) } else { None })
+        });
+
+        Ok(())
+    }
+
+    fn reset_eng(&self, bar: &Devres<Bar0>, timer: &Timer) -> Result<()> {
+        self.reset_prep(bar, timer)?;
+
+        with_bar!(bar, |b| regs::RiscvUnk3c0::alter(b, I::BASE, |v| v
+            .set_unk0(true)))?;
+
+        let _: Result<()> = timer.wait_on(bar, Duration::from_micros(10), || 
None);
+
+        with_bar!(bar, |b| regs::RiscvUnk3c0::alter(b, I::BASE, |v| v
+            .set_unk0(false)))?;
+
+        self.reset_wait_mem_scrubbing(bar, timer)?;
+
+        Ok(())
+    }
+
+    fn disable(&self, bar: &Devres<Bar0>, timer: &Timer) -> Result<()> {
+        self.select_falcon_core(bar, timer)?;
+
+        with_bar!(bar, |b| {
+            regs::FalconUnk0048::alter(b, I::BASE, |r| r.set_val0(0));
+
+            regs::FalconIrqmclr::default()
+                .set_val(u32::MAX)
+                .write(b, I::BASE)
+        })?;
+
+        self.reset_eng(bar, timer)
+    }
+
+    fn enable(&self, bar: &Devres<Bar0>, timer: &Timer) -> Result<()> {
+        self.reset_eng(bar, timer)?;
+        self.select_falcon_core(bar, timer)?;
+        self.reset_wait_mem_scrubbing(bar, timer)?;
+
+        with_bar!(bar, |b| {
+            // We write Boot0 into FalconRm, for some reason...
+            regs::FalconRm::default()
+                .set_val(regs::Boot0::read(b).into())
+                .write(b, I::BASE)
+        })
+    }
+
+    pub(crate) fn reset(&self, bar: &Devres<Bar0>, timer: &Timer) -> 
Result<()> {
+        self.disable(bar, timer)?;
+        self.enable(bar, timer)
+    }
+
+    fn dma_init(
+        &self,
+        bar: &Devres<Bar0>,
+        dma_handle: bindings::dma_addr_t,
+        mem: FalconMem,
+        xfer_len: u32,
+        sec: bool,
+    ) -> Result<regs::FalconDmaTrfCmd> {
+        with_bar!(bar, |b| {
+            regs::FalconDmaTrfBase::default()
+                .set_base((dma_handle >> 8) as u32)
+                .write(b, I::BASE);
+            regs::FalconDmaTrfBase1::default()
+                .set_base((dma_handle >> 40) as u16)
+                .write(b, I::BASE)
+        })?;
+
+        Ok(regs::FalconDmaTrfCmd::default()
+            .set_size((xfer_len.ilog2() - 2) as u8)
+            .set_imem(mem == FalconMem::Imem)
+            .set_sec(if sec { 1 } else { 0 }))
+    }
+
+    fn dma_xfer(
+        &self,
+        bar: &Devres<Bar0>,
+        mem_base: u32,
+        dma_base: u32,
+        cmd: regs::FalconDmaTrfCmd,
+    ) -> Result<()> {
+        with_bar!(bar, |b| {
+            regs::FalconDmaTrfMOffs::default()
+                .set_offs(mem_base)
+                .write(b, I::BASE);
+            regs::FalconDmaTrfBOffs::default()
+                .set_offs(dma_base)
+                .write(b, I::BASE);
+
+            cmd.write(b, I::BASE)
+        })
+    }
+
+    fn dma_done(&self, bar: &Devres<Bar0>, timer: &Timer) -> Result<()> {
+        timer.wait_on(bar, Duration::from_millis(2000), || {
+            bar.try_access_with(|b| regs::FalconDmaTrfCmd::read(b, I::BASE))
+                .and_then(|v| if v.idle() { Some(()) } else { None })
+        })
+    }
+
+    fn dma_wr(
+        &self,
+        bar: &Devres<Bar0>,
+        timer: &Timer,
+        dma_handle: bindings::dma_addr_t,
+        dma_base: u32,
+        mem: FalconMem,
+        mem_base: u32,
+        len: u32,
+        sec: bool,
+    ) -> Result<()> {
+        const DMA_LEN: u32 = 256;
+
+        let (dma_start, dma_addr) = match mem {
+            FalconMem::Imem => (0, dma_handle),
+            FalconMem::Dmem => (dma_base, dma_handle + dma_base as 
bindings::dma_addr_t),
+        };
+
+        pr_info!(
+            "dma write {:?}: dma_handle {:x} dma_start {:x} dma_addr {:x} len 
{:x}\n",
+            mem,
+            dma_handle,
+            dma_start,
+            dma_addr,
+            len
+        );
+
+        let cmd = self.dma_init(bar, dma_addr, mem, DMA_LEN, sec)?;
+
+        let mut dst = mem_base;
+        let mut src = dma_base;
+        let mut remain = len;
+
+        while remain >= DMA_LEN {
+            self.dma_xfer(bar, dst, src - dma_start, cmd)?;
+            self.dma_done(bar, timer)?;
+
+            src += DMA_LEN;
+            dst += DMA_LEN;
+            remain -= DMA_LEN;
+        }
+
+        pr_info!("dma write remain: {} bytes\n", remain);
+
+        Ok(())
+    }
+
+    pub(crate) fn dma_load(
+        &self,
+        bar: &Devres<Bar0>,
+        timer: &Timer,
+        dma_handle: bindings::dma_addr_t,
+        imem_params: (u32, u32, u32),
+        dmem_params: (u32, u32, u32),
+    ) -> Result<()> {
+        pr_info!("dma_load: {:?} {:?}\n", imem_params, dmem_params);
+
+        with_bar!(bar, |b| {
+            regs::FalconUnk624::alter(b, I::BASE, |v| v.set_unk7(true));
+            regs::FalconDmaCtl::default().write(b, I::BASE);
+            regs::FalconUnk600::alter(b, I::BASE, |v| 
v.set_unk16(false).set_unk2((1 << 2) | 1));
+        })?;
+
+        self.dma_wr(
+            bar,
+            timer,
+            dma_handle,
+            imem_params.0,
+            FalconMem::Imem,
+            imem_params.1,
+            imem_params.2,
+            true,
+        )?;
+        self.dma_wr(
+            bar,
+            timer,
+            dma_handle,
+            dmem_params.0,
+            FalconMem::Dmem,
+            dmem_params.1,
+            dmem_params.2,
+            true,
+        )?;
+
+        Ok(())
+    }
+
+    pub(crate) fn boot(
+        &self,
+        bar: &Devres<Bar0>,
+        timer: &Timer,
+        v3_desc: &FalconUCodeDescV3,
+        mbox0: Option<u32>,
+        mbox1: Option<u32>,
+    ) -> Result<(u32, u32)> {
+        pr_info!("boot 0\n");
+
+        // Program BROM registers for PKC signature validation.
+        if self.chipset >= Chipset::GA102 {
+            let pkc_data_offset = v3_desc.pkc_data_offset;
+            let engine_id_mask = v3_desc.engine_id_mask;
+            let ucode_id = v3_desc.ucode_id;
+
+            pr_info!(
+                "dmem_sign: {:#x}, engine_id: {:#x}, ucode_id: {:#x}",
+                pkc_data_offset,
+                engine_id_mask,
+                ucode_id
+            );
+
+            with_bar!(bar, |b| {
+                regs::FalconBromParaaddr0::default()
+                    .set_addr(pkc_data_offset)
+                    .write(b, I::BASE);
+                regs::FalconBromEngidmask::default()
+                    .set_mask(engine_id_mask as u32)
+                    .write(b, I::BASE);
+                regs::FalconBromCurrUcodeId::default()
+                    .set_ucode_id(ucode_id as u32)
+                    .write(b, I::BASE);
+                regs::FalconModSel::default()
+                    .set_algo(FalconModSelAlgo::Rsa3k)
+                    .write(b, I::BASE);
+            })?;
+        }
+
+        pr_info!("boot 1\n");
+
+        with_bar!(bar, |b| {
+            if let Some(mbox0) = mbox0 {
+                regs::FalconMailbox0::default()
+                    .set_mailbox0(mbox0)
+                    .write(b, I::BASE);
+            }
+
+            if let Some(mbox1) = mbox1 {
+                regs::FalconMailbox1::default()
+                    .set_mailbox1(mbox1)
+                    .write(b, I::BASE);
+            }
+
+            // Set `BootVec` to start of non-secure code.
+            // TODO: use boot vector variable - apparently this is 0 on v3 hdr?
+            regs::FalconBootVec::default()
+                .set_boot_vec(0)
+                .write(b, I::BASE);
+
+            regs::FalconCpuCtl::default()
+                .set_start_cpu(true)
+                .write(b, I::BASE);
+        })?;
+
+        pr_info!("booted!\n");
+        timer.wait_on(bar, Duration::from_secs(2), || {
+            bar.try_access()
+                .map(|b| regs::FalconCpuCtl::read(&*b, I::BASE))
+                .and_then(|v| if v.halted() { Some(()) } else { None })
+        })?;
+
+        let (mbox0, mbox1) = with_bar!(bar, |b| {
+            let mbox0 = regs::FalconMailbox0::read(b, I::BASE).mailbox0();
+            let mbox1 = regs::FalconMailbox1::read(b, I::BASE).mailbox1();
+
+            (mbox0, mbox1)
+        })?;
+
+        pr_info!("successfully returned {} {}\n", mbox0, mbox1);
+
+        Ok((mbox0, mbox1))
+    }
+}
+
+#[repr(C)]
+#[derive(Debug)]
+struct FalconAppifHdrV1 {
+    ver: u8,
+    hdr: u8,
+    len: u8,
+    cnt: u8,
+}
+
+#[repr(C)]
+#[derive(Debug)]
+struct FalconAppifV1 {
+    id: u32,
+    dmem_base: u32,
+}
+
+const NVFW_FALCON_APPIF_ID_DMEMMAPPER: u32 = 0x4;
+
+#[repr(C)]
+#[derive(Debug)]
+struct FalconAppifDmemmapperV3 {
+    signature: u32,
+    version: u16,
+    size: u16,
+    cmd_in_buffer_offset: u32,
+    cmd_in_buffer_size: u32,
+    cmd_out_buffer_offset: u32,
+    cmd_out_buffer_size: u32,
+    nvf_img_data_buffer_offset: u32,
+    nvf_img_data_buffer_size: u32,
+    printf_buffer_hdr: u32,
+    ucode_build_time_stamp: u32,
+    ucode_signature: u32,
+    init_cmd: u32,
+    ucode_feature: u32,
+    ucode_cmd_mask0: u32,
+    ucode_cmd_mask1: u32,
+    multi_tgt_tbl: u32,
+}
+
+pub(crate) const NVFW_FALCON_APPIF_DMEMMAPPER_CMD_FRTS: u32 = 0x15;
+
+#[derive(Debug)]
+#[repr(C)]
+struct ReadVbios {
+    ver: u32,
+    hdr: u32,
+    addr: u64,
+    size: u32,
+    flags: u32,
+}
+
+#[derive(Debug)]
+#[repr(C)]
+struct FrtsRegion {
+    ver: u32,
+    hdr: u32,
+    addr: u32,
+    size: u32,
+    ftype: u32,
+}
+
+const NVFW_FRTS_CMD_REGION_TYPE_FB: u32 = 2;
+
+#[derive(Debug)]
+#[repr(C)]
+struct FrtsCmd {
+    read_vbios: ReadVbios,
+    frts_region: FrtsRegion,
+}
diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
index 
f010d3152530b1cec032ca620e59de51a2fc1a13..ec745dd8175bd3164ed1b865293a526b09c59ab3
 100644
--- a/drivers/gpu/nova-core/gpu.rs
+++ b/drivers/gpu/nova-core/gpu.rs
@@ -5,6 +5,7 @@
 };
 
 use crate::driver::Bar0;
+use crate::falcon::{GspFalcon, Sec2Falcon};
 use crate::regs;
 use crate::timer::Timer;
 use crate::util;
@@ -198,6 +199,18 @@ pub(crate) fn new(pdev: &pci::Device, bar: Devres<Bar0>) 
-> Result<impl PinInit<
         );
 
         let timer = Timer::new();
+        let _gsp_falcon = GspFalcon::new(
+            pdev,
+            spec.chipset,
+            &bar,
+            if spec.chipset > Chipset::GA100 {
+                true
+            } else {
+                false
+            },
+        )?;
+
+        let _sec2_falcon = Sec2Falcon::new(pdev, spec.chipset, &bar, false)?;
 
         Ok(pin_init!(Self {
             spec,
diff --git a/drivers/gpu/nova-core/nova_core.rs 
b/drivers/gpu/nova-core/nova_core.rs
index 
f54dcfc66490cb6b10090ef944ac14feca9f6972..35c030485532633a5dd59a8a4a1f6d385cb46c98
 100644
--- a/drivers/gpu/nova-core/nova_core.rs
+++ b/drivers/gpu/nova-core/nova_core.rs
@@ -15,6 +15,7 @@ macro_rules! with_bar {
 }
 
 mod driver;
+mod falcon;
 mod firmware;
 mod gpu;
 mod regs;
diff --git a/drivers/gpu/nova-core/regs.rs b/drivers/gpu/nova-core/regs.rs
index 
0d06e09b1ba62d55688c633500f37d3fe1aeb30e..2952fa7f84c274f122bc12e5506b0b2ac0fbb82d
 100644
--- a/drivers/gpu/nova-core/regs.rs
+++ b/drivers/gpu/nova-core/regs.rs
@@ -2,8 +2,11 @@
 
 use core::ops::Deref;
 use kernel::io::Io;
-use kernel::register;
+use kernel::{register, register_rel};
 
+use crate::falcon::{
+    FalconCoreRev, FalconCoreRevSubversion, FalconModSelAlgo, 
FalconSecurityModel, RiscvCoreSelect,
+};
 use crate::gpu::Chipset;
 
 register!(Boot0@0x00000000, "Basic revision information about the GPU";
@@ -22,3 +25,186 @@
     31:0    hi => as u32, "high 32 bits of the timer"
 );
 
+/* PFALCON */
+
+register_rel!(FalconIrqsclr@0x00000004;
+    4:4     halt => as_bit bool;
+    6:6     swgen0 => as_bit bool;
+);
+
+register_rel!(FalconIrqstat@0x00000008;
+    4:4     halt => as_bit bool;
+    6:6     swgen0 => as_bit bool;
+);
+
+register_rel!(FalconIrqmclr@0x00000014;
+    31:0    val => as u32
+);
+
+register_rel!(FalconIrqmask@0x00000018;
+    31:0    val => as u32
+);
+
+register_rel!(FalconRm@0x00000084;
+    31:0    val => as u32
+);
+
+register_rel!(FalconIrqdest@0x0000001c;
+    31:0    val => as u32
+);
+
+register_rel!(FalconMailbox0@0x00000040;
+    31:0    mailbox0 => as u32
+);
+register_rel!(FalconMailbox1@0x00000044;
+    31:0    mailbox1 => as u32
+);
+
+register_rel!(FalconUnk0048@0x00000048;
+    1:0     val0 => as u32
+);
+
+register_rel!(FalconHwcfg2@0x000000f4;
+    10:10   riscv => as_bit bool;
+    12:12   mem_scrubbing => as_bit bool;
+    31:31   unk_31 => as_bit bool;
+);
+
+register_rel!(FalconCpuCtl@0x00000100;
+    1:1     start_cpu => as_bit bool;
+    4:4     halted => as_bit bool;
+    6:6     alias_en => as_bit bool;
+);
+register_rel!(FalconBootVec@0x00000104;
+    31:0    boot_vec => as u32
+);
+
+register_rel!(FalconHwCfg@0x00000108;
+    8:0     imem_size => as u32;
+    17:9    dmem_size => as u32;
+);
+
+register_rel!(FalconDmaCtl@0x0000010c;
+    0:0     require_ctx => as_bit bool;
+    1:1     dmem_scrubbing  => as_bit bool;
+    2:2     imem_scrubbing => as_bit bool;
+    6:3     dmaq_num => as_bit u8;
+    7:7     secure_stat => as_bit bool;
+);
+
+register_rel!(FalconDmaTrfBase@0x00000110;
+    31:0    base => as u32;
+);
+
+register_rel!(FalconDmaTrfMOffs@0x00000114;
+    23:0    offs => as u32;
+);
+
+register_rel!(FalconDmaTrfCmd@0x00000118;
+    0:0     full => as_bit bool;
+    1:1     idle => as_bit bool;
+    3:2     sec => as_bit u8;
+    4:4     imem => as_bit bool;
+    5:5     is_write => as_bit bool;
+    10:8    size => as u8;
+    14:12   ctxdma => as u8;
+    16:16   set_dmtag => as u8;
+);
+
+register_rel!(FalconDmaTrfBOffs@0x0000011c;
+    31:0    offs => as u32;
+);
+
+register_rel!(FalconDmaTrfBase1@0x00000128;
+    8:0     base => as u16;
+);
+
+register_rel!(FalconHwcfg1@0x0000012c;
+    3:0     core_rev => try_into FalconCoreRev, "core revision of the falcon";
+    5:4     security_model => try_into FalconSecurityModel, "security model of 
the falcon";
+    7:6     core_rev_subversion => into FalconCoreRevSubversion;
+    11:8    imem_ports => as u8;
+    15:12   dmem_ports => as u8;
+);
+
+// TODO: This should be able to take an index, like +0x180[16; 8]? Then the 
constructor or read
+// method take the port we want to address as argument.
+register_rel!(FalconImemC@0x00000180;
+    7:2     offs => as u8;
+    23:8    blk => as u8;
+    24:24   aincw => as_bit bool;
+    25:25   aincr => as_bit bool;
+    28:28   secure => as_bit bool;
+    29:29   sec_atomic => as_bit bool;
+);
+
+register_rel!(FalconImemD@0x00000184;
+    31:0    data => as u32;
+);
+
+register_rel!(FalconImemT@0x00000188;
+    15:0    data => as u16;
+);
+
+register_rel!(FalconDmemC@0x000001c0;
+    23:0    addr => as u32;
+    7:2     offs => as u8;
+    23:8    blk => as u8;
+    24:24   aincw => as_bit bool;
+    25:25   aincr => as_bit bool;
+    26:26   settag => as_bit bool;
+    27:27   setlvl => as_bit bool;
+    28:28   va => as_bit bool;
+    29:29   miss => as_bit bool;
+);
+
+register_rel!(FalconDmemD@0x000001c4;
+    31:0    data => as u32;
+);
+
+register_rel!(FalconModSel@0x00001180;
+    7:0     algo => try_into FalconModSelAlgo;
+);
+register_rel!(FalconBromCurrUcodeId@0x00001198;
+    31:0    ucode_id => as u32;
+);
+register_rel!(FalconBromEngidmask@0x0000119c;
+    31:0    mask => as u32;
+);
+register_rel!(FalconBromParaaddr0@0x00001210;
+    31:0    addr => as u32;
+);
+
+register_rel!(RiscvCpuCtl@0x00000388;
+    0:0     startcpu => as_bit bool;
+    4:4     halted => as_bit bool;
+    5:5     stopped => as_bit bool;
+    7:7     active_stat => as_bit bool;
+);
+
+register_rel!(RiscvUnk3c0@0x000003c0;
+    0:0     unk0 => as_bit bool;
+);
+
+register_rel!(RiscvIrqmask@0x00000528;
+    31:0    mask => as u32;
+);
+
+register_rel!(RiscvIrqdest@0x0000052c;
+    31:0    dest => as u32;
+);
+
+register_rel!(FalconUnk600@0x00000600;
+    16:16   unk16 => as_bit bool;
+    2:0     unk2 => as u8;
+);
+
+register_rel!(FalconUnk624@0x00000624;
+    7:7     unk7 => as_bit bool;
+);
+
+register_rel!(RiscvBcrCtrl@0x00001668;
+    0:0     valid => as_bit bool;
+    4:4     core_select => as_bit RiscvCoreSelect;
+    8:8     br_fetch => as_bit bool;
+);

-- 
2.48.1

Reply via email to