| 1 | |
| 2 |
|
| 3 | |
| 4 |
|
| 5 | use hal::FalconHal;
|
| 6 |
|
| 7 | use kernel::{
|
| 8 | device,
|
| 9 | dma::{
|
| 10 | Coherent,
|
| 11 | CoherentBox,
|
| 12 | DmaAddress, |
| 13 | },
|
| 14 | io::{
|
| 15 | io_project,
|
| 16 | poll::read_poll_timeout,
|
| 17 | register::{
|
| 18 | RegisterBase,
|
| 19 | WithBase, |
| 20 | },
|
| 21 | Io,
|
| 22 | },
|
| 23 | prelude::*,
|
| 24 | time::Delta,
|
| 25 | };
|
| 26 |
|
| 27 | use crate::{
|
| 28 | bounded_enum,
|
| 29 | driver::Bar0,
|
| 30 | falcon::hal::LoadMethod,
|
| 31 | gpu::Chipset,
|
| 32 | num::{
|
| 33 | self,
|
| 34 | FromSafeCast, |
| 35 | },
|
| 36 | regs,
|
| 37 | };
|
| 38 |
|
| 39 | pub(crate) mod fsp;
|
| 40 | pub(crate) mod gsp;
|
| 41 | mod hal;
|
| 42 | pub(crate) mod sec2;
|
| 43 |
|
| 44 | |
| 45 | pub(crate) const MEM_BLOCK_ALIGNMENT: usize = 256;
|
| 46 |
|
| 47 | bounded_enum! {
|
| 48 | |
| 49 | |
| 50 | #[derive(Debug, Copy, Clone)]
|
| 51 | pub(crate) enum FalconCoreRev with TryFrom<Bounded<u32, 4>> {
|
| 52 | Rev1 = 1,
|
| 53 | Rev2 = 2,
|
| 54 | Rev3 = 3,
|
| 55 | Rev4 = 4,
|
| 56 | Rev5 = 5,
|
| 57 | Rev6 = 6,
|
| 58 | Rev7 = 7,
|
| 59 | }
|
| 60 | }
|
| 61 |
|
| 62 | bounded_enum! {
|
| 63 | |
| 64 | |
| 65 | #[derive(Debug, Copy, Clone)]
|
| 66 | pub(crate) enum FalconCoreRevSubversion with From<Bounded<u32, 2>> {
|
| 67 | Subversion0 = 0,
|
| 68 | Subversion1 = 1,
|
| 69 | Subversion2 = 2,
|
| 70 | Subversion3 = 3,
|
| 71 | }
|
| 72 | }
|
| 73 |
|
| 74 | bounded_enum! {
|
| 75 | |
| 76 | |
| 77 | |
| 78 | #[derive(Debug, Copy, Clone)]
|
| 79 | pub(crate) enum FalconSecurityModel with TryFrom<Bounded<u32, 2>> {
|
| 80 | |
| 81 | None = 0,
|
| 82 | |
| 83 | |
| 84 | |
| 85 | |
| 86 | |
| 87 | Light = 2,
|
| 88 | |
| 89 | |
| 90 | |
| 91 | |
| 92 | Heavy = 3,
|
| 93 | }
|
| 94 | }
|
| 95 |
|
| 96 | bounded_enum! {
|
| 97 | |
| 98 | |
| 99 | |
| 100 | #[derive(Debug, Copy, Clone)]
|
| 101 | pub(crate) enum FalconModSelAlgo with TryFrom<Bounded<u32, 8>> {
|
| 102 | |
| 103 | Aes = 0,
|
| 104 | |
| 105 | Rsa3k = 1,
|
| 106 | }
|
| 107 | }
|
| 108 |
|
| 109 | bounded_enum! {
|
| 110 | |
| 111 | |
| 112 | #[derive(Debug, Copy, Clone)]
|
| 113 | pub(crate) enum DmaTrfCmdSize with TryFrom<Bounded<u32, 3>> {
|
| 114 | |
| 115 | Size256B = 0x6,
|
| 116 | }
|
| 117 | }
|
| 118 |
|
| 119 | bounded_enum! {
|
| 120 | |
| 121 | #[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
| 122 | pub(crate) enum PeregrineCoreSelect with From<Bounded<u32, 1>> {
|
| 123 | |
| 124 | Falcon = 0,
|
| 125 | |
| 126 | Riscv = 1,
|
| 127 | }
|
| 128 | }
|
| 129 |
|
| 130 | |
| 131 | #[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
| 132 | pub(crate) enum FalconMem {
|
| 133 | |
| 134 | ImemSecure,
|
| 135 | |
| 136 | #[expect(unused)]
|
| 137 | ImemNonSecure,
|
| 138 | |
| 139 | Dmem,
|
| 140 | }
|
| 141 |
|
| 142 | bounded_enum! {
|
| 143 | |
| 144 | |
| 145 | |
| 146 | #[derive(Debug, Copy, Clone)]
|
| 147 | pub(crate) enum FalconFbifTarget with TryFrom<Bounded<u32, 2>> {
|
| 148 | |
| 149 | LocalFb = 0,
|
| 150 | |
| 151 | CoherentSysmem = 1,
|
| 152 | |
| 153 | NoncoherentSysmem = 2,
|
| 154 | }
|
| 155 | }
|
| 156 |
|
| 157 | bounded_enum! {
|
| 158 | |
| 159 | #[derive(Debug, Copy, Clone)]
|
| 160 | pub(crate) enum FalconFbifMemType with From<Bounded<u32, 1>> {
|
| 161 | |
| 162 | Virtual = 0,
|
| 163 | |
| 164 | Physical = 1,
|
| 165 | }
|
| 166 | }
|
| 167 |
|
| 168 | |
| 169 | pub(crate) struct PFalconBase(());
|
| 170 |
|
| 171 | |
| 172 | pub(crate) struct PFalcon2Base(());
|
| 173 |
|
| 174 | |
| 175 | |
| 176 | |
| 177 | pub(crate) trait FalconEngine:
|
| 178 | Send + Sync + RegisterBase<PFalconBase> + RegisterBase<PFalcon2Base> + Sized
|
| 179 | {
|
| 180 | }
|
| 181 |
|
| 182 | |
| 183 | |
| 184 | #[derive(Debug, Clone)]
|
| 185 | pub(crate) struct FalconDmaLoadTarget {
|
| 186 | |
| 187 | pub(crate) src_start: u32,
|
| 188 | |
| 189 | pub(crate) dst_start: u32,
|
| 190 | |
| 191 | pub(crate) len: u32,
|
| 192 | }
|
| 193 |
|
| 194 | |
| 195 | #[derive(Debug, Clone)]
|
| 196 | pub(crate) struct FalconBromParams {
|
| 197 | |
| 198 | pub(crate) pkc_data_offset: u32,
|
| 199 | |
| 200 | pub(crate) engine_id_mask: u16,
|
| 201 | |
| 202 | pub(crate) ucode_id: u8,
|
| 203 | }
|
| 204 |
|
| 205 | |
| 206 | pub(crate) trait FalconDmaLoadable {
|
| 207 | |
| 208 | fn as_slice(&self) -> &[u8];
|
| 209 |
|
| 210 | |
| 211 | fn imem_sec_load_params(&self) -> FalconDmaLoadTarget;
|
| 212 |
|
| 213 | |
| 214 | |
| 215 | fn imem_ns_load_params(&self) -> Option<FalconDmaLoadTarget>;
|
| 216 |
|
| 217 | |
| 218 | fn dmem_load_params(&self) -> FalconDmaLoadTarget;
|
| 219 |
|
| 220 | |
| 221 | |
| 222 | |
| 223 | |
| 224 | fn try_as_pio_loadable(&self) -> Result<FalconDmaFirmwarePioAdapter<'_, Self>> {
|
| 225 | let new_pio_imem = |params: FalconDmaLoadTarget, secure| {
|
| 226 | let start = usize::from_safe_cast(params.src_start);
|
| 227 | let end = start + usize::from_safe_cast(params.len);
|
| 228 | let data = self.as_slice().get(start..end).ok_or(EINVAL)?;
|
| 229 |
|
| 230 | let dst_start = u16::try_from(params.dst_start).map_err(|_| EINVAL)?;
|
| 231 |
|
| 232 | Ok::<_, Error>(FalconPioImemLoadTarget {
|
| 233 | data,
|
| 234 | dst_start,
|
| 235 | secure,
|
| 236 | start_tag: dst_start >> 8,
|
| 237 | })
|
| 238 | };
|
| 239 |
|
| 240 | let imem_sec = new_pio_imem(self.imem_sec_load_params(), true)?;
|
| 241 |
|
| 242 | let imem_ns = if let Some(params) = self.imem_ns_load_params() {
|
| 243 | Some(new_pio_imem(params, false)?)
|
| 244 | } else {
|
| 245 | None
|
| 246 | };
|
| 247 |
|
| 248 | let dmem = {
|
| 249 | let params = self.dmem_load_params();
|
| 250 | let start = usize::from_safe_cast(params.src_start);
|
| 251 | let end = start + usize::from_safe_cast(params.len);
|
| 252 | let data = self.as_slice().get(start..end).ok_or(EINVAL)?;
|
| 253 |
|
| 254 | let dst_start = u16::try_from(params.dst_start).map_err(|_| EINVAL)?;
|
| 255 |
|
| 256 | FalconPioDmemLoadTarget { data, dst_start }
|
| 257 | };
|
| 258 |
|
| 259 | Ok(FalconDmaFirmwarePioAdapter {
|
| 260 | fw: self,
|
| 261 | imem_sec,
|
| 262 | imem_ns,
|
| 263 | dmem,
|
| 264 | })
|
| 265 | }
|
| 266 | }
|
| 267 |
|
| 268 | |
| 269 | #[derive(Clone)]
|
| 270 | pub(crate) struct FalconPioImemLoadTarget<'a> {
|
| 271 | pub(crate) data: &'a [u8],
|
| 272 | pub(crate) dst_start: u16,
|
| 273 | pub(crate) secure: bool,
|
| 274 | pub(crate) start_tag: u16,
|
| 275 | }
|
| 276 |
|
| 277 | |
| 278 | #[derive(Clone)]
|
| 279 | pub(crate) struct FalconPioDmemLoadTarget<'a> {
|
| 280 | pub(crate) data: &'a [u8],
|
| 281 | pub(crate) dst_start: u16,
|
| 282 | }
|
| 283 |
|
| 284 | |
| 285 | pub(crate) trait FalconPioLoadable {
|
| 286 | |
| 287 | fn imem_sec_load_params(&self) -> Option<FalconPioImemLoadTarget<'_>>;
|
| 288 |
|
| 289 | |
| 290 | fn imem_ns_load_params(&self) -> Option<FalconPioImemLoadTarget<'_>>;
|
| 291 |
|
| 292 | |
| 293 | fn dmem_load_params(&self) -> FalconPioDmemLoadTarget<'_>;
|
| 294 | }
|
| 295 |
|
| 296 | |
| 297 | |
| 298 | |
| 299 | pub(crate) struct FalconDmaFirmwarePioAdapter<'a, T: FalconDmaLoadable + ?Sized> {
|
| 300 | |
| 301 | fw: &'a T,
|
| 302 | |
| 303 | imem_sec: FalconPioImemLoadTarget<'a>,
|
| 304 | |
| 305 | imem_ns: Option<FalconPioImemLoadTarget<'a>>,
|
| 306 | |
| 307 | dmem: FalconPioDmemLoadTarget<'a>,
|
| 308 | }
|
| 309 |
|
| 310 | impl<'a, T> FalconPioLoadable for FalconDmaFirmwarePioAdapter<'a, T>
|
| 311 | where
|
| 312 | T: FalconDmaLoadable + ?Sized,
|
| 313 | {
|
| 314 | fn imem_sec_load_params(&self) -> Option<FalconPioImemLoadTarget<'_>> {
|
| 315 | Some(self.imem_sec.clone())
|
| 316 | }
|
| 317 |
|
| 318 | fn imem_ns_load_params(&self) -> Option<FalconPioImemLoadTarget<'_>> {
|
| 319 | self.imem_ns.clone()
|
| 320 | }
|
| 321 |
|
| 322 | fn dmem_load_params(&self) -> FalconPioDmemLoadTarget<'_> {
|
| 323 | self.dmem.clone()
|
| 324 | }
|
| 325 | }
|
| 326 |
|
| 327 | impl<'a, T> FalconFirmware for FalconDmaFirmwarePioAdapter<'a, T>
|
| 328 | where
|
| 329 | T: FalconDmaLoadable + FalconFirmware + ?Sized,
|
| 330 | {
|
| 331 | type Target = <T as FalconFirmware>::Target;
|
| 332 |
|
| 333 | fn brom_params(&self) -> FalconBromParams {
|
| 334 | self.fw.brom_params()
|
| 335 | }
|
| 336 |
|
| 337 | fn boot_addr(&self) -> u32 {
|
| 338 | self.fw.boot_addr()
|
| 339 | }
|
| 340 | }
|
| 341 |
|
| 342 | |
| 343 | |
| 344 | |
| 345 | pub(crate) trait FalconFirmware {
|
| 346 | |
| 347 | type Target: FalconEngine;
|
| 348 |
|
| 349 | |
| 350 | fn brom_params(&self) -> FalconBromParams;
|
| 351 |
|
| 352 | |
| 353 | fn boot_addr(&self) -> u32;
|
| 354 | }
|
| 355 |
|
| 356 | |
| 357 | pub(crate) struct Falcon<'a, E: FalconEngine> {
|
| 358 | hal: KBox<dyn FalconHal<E>>,
|
| 359 | dev: &'a device::Device<device::Bound>,
|
| 360 | bar: Bar0<'a>,
|
| 361 | }
|
| 362 |
|
| 363 | impl<'a, E: FalconEngine + 'static> Falcon<'a, E> {
|
| 364 | |
| 365 | pub(crate) fn new(
|
| 366 | dev: &'a device::Device<device::Bound>,
|
| 367 | chipset: Chipset,
|
| 368 | bar: Bar0<'a>,
|
| 369 | ) -> Result<Self> {
|
| 370 | Ok(Self {
|
| 371 | hal: hal::falcon_hal(chipset)?,
|
| 372 | dev,
|
| 373 | bar,
|
| 374 | })
|
| 375 | }
|
| 376 |
|
| 377 | |
| 378 | pub(crate) fn dma_reset(&self) {
|
| 379 | self.bar.update(regs::NV_PFALCON_FBIF_CTL::of::<E>(), |v| {
|
| 380 | v.with_allow_phys_no_ctx(true)
|
| 381 | });
|
| 382 |
|
| 383 | self.bar.write(
|
| 384 | WithBase::of::<E>(),
|
| 385 | regs::NV_PFALCON_FALCON_DMACTL::zeroed(),
|
| 386 | );
|
| 387 | }
|
| 388 |
|
| 389 | |
| 390 | pub(crate) fn reset(&self) -> Result {
|
| 391 | self.hal.reset_eng(self)?;
|
| 392 | self.hal.select_core(self)?;
|
| 393 | self.hal.reset_wait_mem_scrubbing(self)?;
|
| 394 |
|
| 395 | self.bar.write(
|
| 396 | WithBase::of::<E>(),
|
| 397 | regs::NV_PFALCON_FALCON_RM::from(self.bar.read(regs::NV_PMC_BOOT_0).into_raw()),
|
| 398 | );
|
| 399 |
|
| 400 | Ok(())
|
| 401 | }
|
| 402 |
|
| 403 | |
| 404 | const PIO_PORT: usize = 0;
|
| 405 |
|
| 406 | |
| 407 | |
| 408 | |
| 409 | fn pio_wr_imem_slice(&self, load_offsets: FalconPioImemLoadTarget<'_>) -> Result {
|
| 410 | |
| 411 | |
| 412 | if load_offsets.data.len() % 4 != 0 {
|
| 413 | return Err(EINVAL);
|
| 414 | }
|
| 415 |
|
| 416 | self.bar.write(
|
| 417 | WithBase::of::<E>().at(Self::PIO_PORT),
|
| 418 | regs::NV_PFALCON_FALCON_IMEMC::zeroed()
|
| 419 | .with_secure(load_offsets.secure)
|
| 420 | .with_aincw(true)
|
| 421 | .with_offs(load_offsets.dst_start),
|
| 422 | );
|
| 423 |
|
| 424 | for (n, block) in load_offsets.data.chunks(MEM_BLOCK_ALIGNMENT).enumerate() {
|
| 425 | let n = u16::try_from(n)?;
|
| 426 | let tag: u16 = load_offsets.start_tag.checked_add(n).ok_or(ERANGE)?;
|
| 427 | self.bar.write(
|
| 428 | WithBase::of::<E>().at(Self::PIO_PORT),
|
| 429 | regs::NV_PFALCON_FALCON_IMEMT::zeroed().with_tag(tag),
|
| 430 | );
|
| 431 | for word in block.chunks_exact(4) {
|
| 432 | let w = [word[0], word[1], word[2], word[3]];
|
| 433 | self.bar.write(
|
| 434 | WithBase::of::<E>().at(Self::PIO_PORT),
|
| 435 | regs::NV_PFALCON_FALCON_IMEMD::zeroed().with_data(u32::from_le_bytes(w)),
|
| 436 | );
|
| 437 | }
|
| 438 | }
|
| 439 |
|
| 440 | Ok(())
|
| 441 | }
|
| 442 |
|
| 443 | |
| 444 | |
| 445 | |
| 446 | fn pio_wr_dmem_slice(&self, load_offsets: FalconPioDmemLoadTarget<'_>) -> Result {
|
| 447 | |
| 448 | |
| 449 | if load_offsets.data.len() % 4 != 0 {
|
| 450 | return Err(EINVAL);
|
| 451 | }
|
| 452 |
|
| 453 | self.bar.write(
|
| 454 | WithBase::of::<E>().at(Self::PIO_PORT),
|
| 455 | regs::NV_PFALCON_FALCON_DMEMC::zeroed()
|
| 456 | .with_aincw(true)
|
| 457 | .with_offs(load_offsets.dst_start),
|
| 458 | );
|
| 459 |
|
| 460 | for word in load_offsets.data.chunks_exact(4) {
|
| 461 | let w = [word[0], word[1], word[2], word[3]];
|
| 462 | self.bar.write(
|
| 463 | WithBase::of::<E>().at(Self::PIO_PORT),
|
| 464 | regs::NV_PFALCON_FALCON_DMEMD::zeroed().with_data(u32::from_le_bytes(w)),
|
| 465 | );
|
| 466 | }
|
| 467 |
|
| 468 | Ok(())
|
| 469 | }
|
| 470 |
|
| 471 | |
| 472 | pub(crate) fn pio_load<F: FalconFirmware<Target = E> + FalconPioLoadable>(
|
| 473 | &self,
|
| 474 | fw: &F,
|
| 475 | ) -> Result {
|
| 476 | self.bar.update(regs::NV_PFALCON_FBIF_CTL::of::<E>(), |v| {
|
| 477 | v.with_allow_phys_no_ctx(true)
|
| 478 | });
|
| 479 |
|
| 480 | self.bar.write(
|
| 481 | WithBase::of::<E>(),
|
| 482 | regs::NV_PFALCON_FALCON_DMACTL::zeroed(),
|
| 483 | );
|
| 484 |
|
| 485 | if let Some(imem_ns) = fw.imem_ns_load_params() {
|
| 486 | self.pio_wr_imem_slice(imem_ns)?;
|
| 487 | }
|
| 488 | if let Some(imem_sec) = fw.imem_sec_load_params() {
|
| 489 | self.pio_wr_imem_slice(imem_sec)?;
|
| 490 | }
|
| 491 | self.pio_wr_dmem_slice(fw.dmem_load_params())?;
|
| 492 |
|
| 493 | self.hal.program_brom(self, &fw.brom_params());
|
| 494 |
|
| 495 | self.bar.write(
|
| 496 | WithBase::of::<E>(),
|
| 497 | regs::NV_PFALCON_FALCON_BOOTVEC::zeroed().with_value(fw.boot_addr()),
|
| 498 | );
|
| 499 |
|
| 500 | Ok(())
|
| 501 | }
|
| 502 |
|
| 503 | |
| 504 | |
| 505 | |
| 506 | |
| 507 | fn dma_wr(
|
| 508 | &self,
|
| 509 | dma_obj: &Coherent<[u8]>,
|
| 510 | target_mem: FalconMem,
|
| 511 | load_offsets: FalconDmaLoadTarget,
|
| 512 | ) -> Result {
|
| 513 | const DMA_LEN: u32 = num::usize_into_u32::<{ MEM_BLOCK_ALIGNMENT }>();
|
| 514 |
|
| 515 | |
| 516 | |
| 517 | let num_transfers = load_offsets.len.div_ceil(DMA_LEN);
|
| 518 |
|
| 519 | |
| 520 | |
| 521 | |
| 522 | |
| 523 | let (src_start, dma_start) = match target_mem {
|
| 524 | FalconMem::ImemSecure | FalconMem::ImemNonSecure => (load_offsets.src_start, 0),
|
| 525 | FalconMem::Dmem => (0, usize::from_safe_cast(load_offsets.src_start)),
|
| 526 | };
|
| 527 |
|
| 528 | let dma_address = {
|
| 529 | |
| 530 | let dma_end = num_transfers
|
| 531 | .checked_mul(DMA_LEN)
|
| 532 | .and_then(|size| size.checked_add(load_offsets.src_start))
|
| 533 | .map(usize::from_safe_cast)
|
| 534 | .ok_or(EOVERFLOW)?;
|
| 535 |
|
| 536 | io_project!(dma_obj, [try: dma_start..dma_end]).dma_address()
|
| 537 | };
|
| 538 |
|
| 539 | if dma_address % DmaAddress::from(DMA_LEN) > 0 {
|
| 540 | dev_err!(
|
| 541 | self.dev,
|
| 542 | "DMA transfer start addresses must be a multiple of {}\n",
|
| 543 | DMA_LEN
|
| 544 | );
|
| 545 | return Err(EINVAL);
|
| 546 | }
|
| 547 |
|
| 548 | |
| 549 |
|
| 550 | self.bar.write(
|
| 551 | WithBase::of::<E>(),
|
| 552 | regs::NV_PFALCON_FALCON_DMATRFBASE::zeroed().with_base(
|
| 553 | |
| 554 | |
| 555 | (dma_address >> 8) as u32,
|
| 556 | ),
|
| 557 | );
|
| 558 | self.bar.write(
|
| 559 | WithBase::of::<E>(),
|
| 560 | regs::NV_PFALCON_FALCON_DMATRFBASE1::zeroed().try_with_base(dma_address >> 40)?,
|
| 561 | );
|
| 562 |
|
| 563 | let cmd = regs::NV_PFALCON_FALCON_DMATRFCMD::zeroed()
|
| 564 | .with_size(DmaTrfCmdSize::Size256B)
|
| 565 | .with_falcon_mem(target_mem);
|
| 566 |
|
| 567 | for pos in (0..num_transfers).map(|i| i * DMA_LEN) {
|
| 568 | |
| 569 | self.bar.write(
|
| 570 | WithBase::of::<E>(),
|
| 571 | regs::NV_PFALCON_FALCON_DMATRFMOFFS::zeroed()
|
| 572 | .try_with_offs(load_offsets.dst_start + pos)?,
|
| 573 | );
|
| 574 | self.bar.write(
|
| 575 | WithBase::of::<E>(),
|
| 576 | regs::NV_PFALCON_FALCON_DMATRFFBOFFS::zeroed().with_offs(src_start + pos),
|
| 577 | );
|
| 578 |
|
| 579 | self.bar.write(WithBase::of::<E>(), cmd);
|
| 580 |
|
| 581 | |
| 582 | |
| 583 | |
| 584 | read_poll_timeout(
|
| 585 | || Ok(self.bar.read(regs::NV_PFALCON_FALCON_DMATRFCMD::of::<E>())),
|
| 586 | |r| r.idle(),
|
| 587 | Delta::ZERO,
|
| 588 | Delta::from_secs(2),
|
| 589 | )?;
|
| 590 | }
|
| 591 |
|
| 592 | Ok(())
|
| 593 | }
|
| 594 |
|
| 595 | |
| 596 | fn dma_load<F: FalconFirmware<Target = E> + FalconDmaLoadable>(&self, fw: &F) -> Result {
|
| 597 | |
| 598 | let dma_obj = {
|
| 599 | let fw_slice = fw.as_slice();
|
| 600 |
|
| 601 | |
| 602 | |
| 603 | let mut dma_obj = CoherentBox::zeroed_slice(
|
| 604 | self.dev,
|
| 605 | fw_slice.len().next_multiple_of(MEM_BLOCK_ALIGNMENT),
|
| 606 | GFP_KERNEL,
|
| 607 | )?;
|
| 608 |
|
| 609 | |
| 610 | |
| 611 | dma_obj[..fw_slice.len()].copy_from_slice(fw_slice);
|
| 612 |
|
| 613 | dma_obj.into()
|
| 614 | };
|
| 615 |
|
| 616 | self.dma_reset();
|
| 617 | self.bar
|
| 618 | .update(regs::NV_PFALCON_FBIF_TRANSCFG::of::<E>().at(0), |v| {
|
| 619 | v.with_target(FalconFbifTarget::CoherentSysmem)
|
| 620 | .with_mem_type(FalconFbifMemType::Physical)
|
| 621 | });
|
| 622 |
|
| 623 | self.dma_wr(&dma_obj, FalconMem::ImemSecure, fw.imem_sec_load_params())?;
|
| 624 | self.dma_wr(&dma_obj, FalconMem::Dmem, fw.dmem_load_params())?;
|
| 625 |
|
| 626 | self.hal.program_brom(self, &fw.brom_params());
|
| 627 |
|
| 628 | |
| 629 | self.bar.write(
|
| 630 | WithBase::of::<E>(),
|
| 631 | regs::NV_PFALCON_FALCON_BOOTVEC::zeroed().with_value(fw.boot_addr()),
|
| 632 | );
|
| 633 |
|
| 634 | Ok(())
|
| 635 | }
|
| 636 |
|
| 637 | |
| 638 | pub(crate) fn wait_till_halted(&self) -> Result<()> {
|
| 639 | |
| 640 | read_poll_timeout(
|
| 641 | || Ok(self.bar.read(regs::NV_PFALCON_FALCON_CPUCTL::of::<E>())),
|
| 642 | |r| r.halted(),
|
| 643 | Delta::ZERO,
|
| 644 | Delta::from_secs(2),
|
| 645 | )?;
|
| 646 |
|
| 647 | Ok(())
|
| 648 | }
|
| 649 |
|
| 650 | |
| 651 | pub(crate) fn start(&self) -> Result<()> {
|
| 652 | match self
|
| 653 | .bar
|
| 654 | .read(regs::NV_PFALCON_FALCON_CPUCTL::of::<E>())
|
| 655 | .alias_en()
|
| 656 | {
|
| 657 | true => self.bar.write(
|
| 658 | WithBase::of::<E>(),
|
| 659 | regs::NV_PFALCON_FALCON_CPUCTL_ALIAS::zeroed().with_startcpu(true),
|
| 660 | ),
|
| 661 | false => self.bar.write(
|
| 662 | WithBase::of::<E>(),
|
| 663 | regs::NV_PFALCON_FALCON_CPUCTL::zeroed().with_startcpu(true),
|
| 664 | ),
|
| 665 | }
|
| 666 |
|
| 667 | Ok(())
|
| 668 | }
|
| 669 |
|
| 670 | |
| 671 | pub(crate) fn write_mailboxes(&self, mbox0: Option<u32>, mbox1: Option<u32>) {
|
| 672 | if let Some(mbox0) = mbox0 {
|
| 673 | self.bar.write(
|
| 674 | WithBase::of::<E>(),
|
| 675 | regs::NV_PFALCON_FALCON_MAILBOX0::zeroed().with_value(mbox0),
|
| 676 | );
|
| 677 | }
|
| 678 |
|
| 679 | if let Some(mbox1) = mbox1 {
|
| 680 | self.bar.write(
|
| 681 | WithBase::of::<E>(),
|
| 682 | regs::NV_PFALCON_FALCON_MAILBOX1::zeroed().with_value(mbox1),
|
| 683 | );
|
| 684 | }
|
| 685 | }
|
| 686 |
|
| 687 | |
| 688 | pub(crate) fn read_mailbox0(&self) -> u32 {
|
| 689 | self.bar
|
| 690 | .read(regs::NV_PFALCON_FALCON_MAILBOX0::of::<E>())
|
| 691 | .value()
|
| 692 | }
|
| 693 |
|
| 694 | |
| 695 | pub(crate) fn read_mailbox1(&self) -> u32 {
|
| 696 | self.bar
|
| 697 | .read(regs::NV_PFALCON_FALCON_MAILBOX1::of::<E>())
|
| 698 | .value()
|
| 699 | }
|
| 700 |
|
| 701 | |
| 702 | pub(crate) fn read_mailboxes(&self) -> (u32, u32) {
|
| 703 | let mbox0 = self.read_mailbox0();
|
| 704 | let mbox1 = self.read_mailbox1();
|
| 705 |
|
| 706 | (mbox0, mbox1)
|
| 707 | }
|
| 708 |
|
| 709 | |
| 710 | |
| 711 | |
| 712 | |
| 713 | |
| 714 | |
| 715 | |
| 716 | pub(crate) fn boot(&self, mbox0: Option<u32>, mbox1: Option<u32>) -> Result<(u32, u32)> {
|
| 717 | self.write_mailboxes(mbox0, mbox1);
|
| 718 | self.start()?;
|
| 719 | self.wait_till_halted()?;
|
| 720 | Ok(self.read_mailboxes())
|
| 721 | }
|
| 722 |
|
| 723 | |
| 724 | |
| 725 | pub(crate) fn signature_reg_fuse_version(
|
| 726 | &self,
|
| 727 | engine_id_mask: u16,
|
| 728 | ucode_id: u8,
|
| 729 | ) -> Result<u32> {
|
| 730 | self.hal
|
| 731 | .signature_reg_fuse_version(self, engine_id_mask, ucode_id)
|
| 732 | }
|
| 733 |
|
| 734 | |
| 735 | |
| 736 | |
| 737 | |
| 738 | |
| 739 | pub(crate) fn is_riscv_active(&self) -> bool {
|
| 740 | self.hal.is_riscv_active(self)
|
| 741 | }
|
| 742 |
|
| 743 | |
| 744 | |
| 745 | |
| 746 | |
| 747 | |
| 748 | pub(crate) fn is_riscv_halted(&self) -> Result<bool> {
|
| 749 | self.hal.is_riscv_halted(self)
|
| 750 | }
|
| 751 |
|
| 752 | |
| 753 | |
| 754 | pub(crate) fn load<F: FalconFirmware<Target = E> + FalconDmaLoadable>(&self, fw: &F) -> Result {
|
| 755 | match self.hal.load_method() {
|
| 756 | LoadMethod::Dma => self.dma_load(fw),
|
| 757 | LoadMethod::Pio => self.pio_load(&fw.try_as_pio_loadable()?),
|
| 758 | }
|
| 759 | }
|
| 760 |
|
| 761 | |
| 762 | pub(crate) fn write_os_version(&self, app_version: u32) {
|
| 763 | self.bar.write(
|
| 764 | WithBase::of::<E>(),
|
| 765 | regs::NV_PFALCON_FALCON_OS::zeroed().with_value(app_version),
|
| 766 | );
|
| 767 | }
|
| 768 | }
|