init commit
This commit is contained in:
27
zynq7000/Cargo.toml
Normal file
27
zynq7000/Cargo.toml
Normal file
@ -0,0 +1,27 @@
|
||||
[package]
|
||||
name = "zynq7000"
|
||||
version = "0.1.0"
|
||||
authors = ["Robin Mueller <muellerr@irs.uni-stuttgart.de>"]
|
||||
edition = "2024"
|
||||
description = "PAC for the Zynq7000 family of SoCs"
|
||||
homepage = "https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs"
|
||||
repository = "https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs"
|
||||
license = "MIT OR Apache-2.0"
|
||||
keywords = ["no-std", "arm", "cortex-a", "amd", "zynq7000"]
|
||||
categories = ["embedded", "no-std", "hardware-support"]
|
||||
|
||||
[dependencies]
|
||||
static_assertions = "1.1"
|
||||
derive-mmio = { path = "../../derive-mmio", default-features = false }
|
||||
bitbybit = "1.3"
|
||||
arbitrary-int = "1.3"
|
||||
rustversion = "1"
|
||||
thiserror = { version = "2", default-features = false }
|
||||
once_cell = { version = "1", default-features = false, features = ["critical-section"] }
|
||||
|
||||
[dev-dependencies]
|
||||
approx = "0.5"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
201
zynq7000/LICENSE-APACHE
Normal file
201
zynq7000/LICENSE-APACHE
Normal file
@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
21
zynq7000/LICENSE-MIT
Normal file
21
zynq7000/LICENSE-MIT
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Robin A. Mueller
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
8
zynq7000/README.md
Normal file
8
zynq7000/README.md
Normal file
@ -0,0 +1,8 @@
|
||||
# PAC for the AMD Zynq 7000 SoC family
|
||||
|
||||
This repository contains the Peripheral Access Crate (PAC) for the AMD Zynq7000 SoC family.
|
||||
|
||||
If you are interested in higher-level abstractions, it is recommended you visit
|
||||
the `zynq7000-hal` HAL crate which build on top of this PAC.
|
||||
|
||||
Check out the documentation for more details.
|
3
zynq7000/build.rs
Normal file
3
zynq7000/build.rs
Normal file
@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
}
|
202
zynq7000/src/gic.rs
Normal file
202
zynq7000/src/gic.rs
Normal file
@ -0,0 +1,202 @@
|
||||
//! # GIC (Generic Interrupt Controller) register module.
|
||||
pub use crate::mpcore::{GICC_BASE_ADDR, GICD_BASE_ADDR};
|
||||
use arbitrary_int::{u3, u5, u10};
|
||||
use static_assertions::const_assert_eq;
|
||||
|
||||
/// Distributor Control Register
|
||||
#[bitbybit::bitfield(u32, default = 0x0)]
|
||||
pub struct Dcr {
|
||||
#[bit(1, rw)]
|
||||
enable_non_secure: bool,
|
||||
#[bit(0, rw)]
|
||||
enable_secure: bool,
|
||||
}
|
||||
|
||||
/// Read only bit. This register only returns fixed constants.
|
||||
#[bitbybit::bitfield(u32)]
|
||||
pub struct TypeRegister {
|
||||
#[bits(11..=15, r)]
|
||||
lspi: u5,
|
||||
#[bit(10, r)]
|
||||
security_extension: bool,
|
||||
#[bits(5..=7, r)]
|
||||
cpu_number: u3,
|
||||
#[bits(0..=4, r)]
|
||||
it_lines_number: u5,
|
||||
}
|
||||
|
||||
impl TypeRegister {
|
||||
pub const SECURITY_EXTNS_BIT: bool = true;
|
||||
/// 31 LSPIs.
|
||||
pub const NUM_LSPI: usize = 0x1f;
|
||||
/// Encoding: 0b001 means that the Cortex-A9 MPCore has 2 processors.
|
||||
pub const CPU_NUMBER_BITS: u8 = 0b001;
|
||||
/// The distributor provides 96 interrupts.
|
||||
pub const IT_LINES_NUMBER: u8 = 0x2;
|
||||
|
||||
pub const NUM_OF_CPUS: usize = 2;
|
||||
pub const NUM_OF_INTERRUPTS: usize = 96;
|
||||
}
|
||||
|
||||
pub type Typer = TypeRegister;
|
||||
|
||||
/// GIC Distributor registers.
|
||||
#[derive(derive_mmio::Mmio)]
|
||||
#[repr(C, align(8))]
|
||||
pub struct Gicd {
|
||||
/// Distributor Control Register
|
||||
pub dcr: Dcr,
|
||||
/// Interrupt Controller Type Register
|
||||
#[mmio(PureRead)]
|
||||
pub ictr: Typer,
|
||||
/// Distributor Implementer Identification Register
|
||||
#[mmio(PureRead)]
|
||||
pub iidr: u32,
|
||||
_reserved_0: [u32; 0x1D],
|
||||
/// Interrupt security registers
|
||||
pub isr: [u32; 3],
|
||||
_reserved_1: [u32; 0x1D],
|
||||
/// Interrupt Set-Enable Registers
|
||||
pub iser: [u32; 0x3],
|
||||
_reserved_3: [u32; 0x1D],
|
||||
/// Interrupt Clear-Enable Registers
|
||||
pub icer: [u32; 0x3],
|
||||
_reserved_4: [u32; 0x1D],
|
||||
/// Interrupt Set-Pending Registers
|
||||
pub ispr: [u32; 0x3],
|
||||
_reserved_5: [u32; 0x1D],
|
||||
/// Interrupt Clear-Pending Registers
|
||||
pub icpr: [u32; 0x3],
|
||||
_reserved_6: [u32; 0x1D],
|
||||
/// Active Bit Registers
|
||||
pub abr: [u32; 0x3],
|
||||
_reserved_10: [u32; 0x3D],
|
||||
/// Interrupt Priority Registers
|
||||
pub ipr: [u32; 0x18],
|
||||
_reserved_11: [u32; 0xE8],
|
||||
/// Interrupt Processor Targes Registers
|
||||
pub iptr_sgi: [u32; 0x4],
|
||||
// TODO: Mark those read-only as soon as that works for arrays.
|
||||
pub iptr_ppi: [u32; 0x4],
|
||||
pub iptr_spi: [u32; 0x10],
|
||||
// Those are split in the ARM documentation for some reason..
|
||||
_reserved_12: [u32; 0xE8],
|
||||
/// Interrupt Configuration Registers
|
||||
/// Interupt sensitivity register for software generated interrupts (SGI)
|
||||
pub icfr_0_sgi: u32,
|
||||
/// Interupt sensitivity register for private peripheral interrupts (PPI)
|
||||
pub icfr_1_ppi: u32,
|
||||
pub icfr_2_spi: u32,
|
||||
pub icfr_3_spi: u32,
|
||||
pub icfr_4_spi: u32,
|
||||
pub icfr_5_spi: u32,
|
||||
_reserved_13: [u32; 0x3A],
|
||||
pub ppi_status: u32,
|
||||
pub spi_status_0: u32,
|
||||
pub spi_status_1: u32,
|
||||
_reserved_14: [u32; 0x7D],
|
||||
/// Software Generated Interrupt Register.
|
||||
pub sgir: u32,
|
||||
_reserved_15: [u32; 0x33],
|
||||
pub pidr_4: u32,
|
||||
pub pidr_5: u32,
|
||||
pub pidr_6: u32,
|
||||
pub pidr_7: u32,
|
||||
pub pidr_0: u32,
|
||||
pub pidr_1: u32,
|
||||
pub pidr_2: u32,
|
||||
pub pidr_3: u32,
|
||||
pub cidr: [u32; 4],
|
||||
}
|
||||
|
||||
const_assert_eq!(core::mem::size_of::<Gicd>(), 0x1000);
|
||||
|
||||
impl Gicd {
|
||||
/// Create a new Global Interrupt Controller Distributor MMIO instance at the fixed address of
|
||||
/// the processing system.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This API can be used to potentially create a driver to the same peripheral structure
|
||||
/// from multiple threads. The user must ensure that concurrent accesses are safe and do not
|
||||
/// interfere with each other.
|
||||
#[inline]
|
||||
pub const unsafe fn new_mmio_fixed() -> MmioGicd<'static> {
|
||||
unsafe { Self::new_mmio_at(GICD_BASE_ADDR) }
|
||||
}
|
||||
}
|
||||
|
||||
/// CPU interface control register.
|
||||
#[bitbybit::bitfield(u32, default = 0x0)]
|
||||
pub struct Icr {
|
||||
#[bit(4, rw)]
|
||||
sbpr: bool,
|
||||
#[bit(3, rw)]
|
||||
fiq_en: bool,
|
||||
#[bit(2, rw)]
|
||||
ack_ctrl: bool,
|
||||
#[bit(1, rw)]
|
||||
enable_non_secure: bool,
|
||||
#[bit(0, rw)]
|
||||
enable_secure: bool,
|
||||
}
|
||||
|
||||
/// Priority Mask Register
|
||||
#[bitbybit::bitfield(u32)]
|
||||
pub struct PriorityRegister {
|
||||
#[bits(0..=7, rw)]
|
||||
priority: u8,
|
||||
}
|
||||
|
||||
/// Interrupt acknowledge register.
|
||||
#[bitbybit::bitfield(u32)]
|
||||
#[derive(Debug)]
|
||||
pub struct InterruptSignalRegister {
|
||||
#[bits(10..=12, rw)]
|
||||
cpu_id: u3,
|
||||
#[bits(0..=9, rw)]
|
||||
ack_int_id: u10,
|
||||
}
|
||||
|
||||
/// GIC CPU interface registers.
|
||||
#[derive(derive_mmio::Mmio)]
|
||||
#[repr(C, align(8))]
|
||||
pub struct Gicc {
|
||||
/// CPU Interface Control Register.
|
||||
pub icr: Icr,
|
||||
/// Interrupt Priority Mask Register.
|
||||
pub pmr: PriorityRegister,
|
||||
/// Binary Point Register.
|
||||
pub bpr: u32,
|
||||
/// Interrupt Acknowledge Register.
|
||||
pub iar: InterruptSignalRegister,
|
||||
/// End of Interrupt Register.
|
||||
pub eoir: InterruptSignalRegister,
|
||||
/// Running Priority Register.
|
||||
pub rpr: PriorityRegister,
|
||||
/// Highest Pending Interrupt Register.
|
||||
pub hpir: InterruptSignalRegister,
|
||||
/// Aliased Binary Point Register
|
||||
pub abpr: u32,
|
||||
_reserved_0: [u32; 0x37],
|
||||
/// CPU Interface Identification Register.
|
||||
#[mmio(PureRead)]
|
||||
pub iidr: u32,
|
||||
}
|
||||
|
||||
const_assert_eq!(core::mem::size_of::<Gicc>(), 0x100);
|
||||
|
||||
impl Gicc {
|
||||
/// Create a new Global Interrupt Controller CPU MMIO instance at the fixed address of the
|
||||
/// processing system.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This API can be used to potentially create a driver to the same peripheral structure
|
||||
/// from multiple threads. The user must ensure that concurrent accesses are safe and do not
|
||||
/// interfere with each other.
|
||||
#[inline]
|
||||
pub const unsafe fn new_mmio_fixed() -> MmioGicc<'static> {
|
||||
unsafe { Self::new_mmio_at(GICC_BASE_ADDR) }
|
||||
}
|
||||
}
|
121
zynq7000/src/gpio.rs
Normal file
121
zynq7000/src/gpio.rs
Normal file
@ -0,0 +1,121 @@
|
||||
//! # GPIO register module.
|
||||
#[bitbybit::bitfield(u32, default = 0x0)]
|
||||
#[derive(Debug)]
|
||||
pub struct MaskedOutput {
|
||||
#[bits(16..=31, w)]
|
||||
pub mask: u16,
|
||||
#[bits(0..=15, rw)]
|
||||
pub output: u16,
|
||||
}
|
||||
|
||||
#[derive(derive_mmio::Mmio)]
|
||||
#[repr(C)]
|
||||
pub struct BankCtrl {
|
||||
/// Direction mode
|
||||
dirm: u32,
|
||||
/// Output enable
|
||||
out_en: u32,
|
||||
/// Interrupt mask status
|
||||
#[mmio(PureRead)]
|
||||
int_mask: u32,
|
||||
/// Interrupt enable/unmask
|
||||
#[mmio(Write)]
|
||||
int_en: u32,
|
||||
/// Interrupt disable/mask
|
||||
#[mmio(Write)]
|
||||
int_dis: u32,
|
||||
/// Interrupt status
|
||||
#[mmio(PureRead, Write)]
|
||||
int_sts: u32,
|
||||
/// Interrupt type
|
||||
int_type: u32,
|
||||
/// Interrupt polarity
|
||||
int_pol: u32,
|
||||
/// Interrupt any edge sensitivity
|
||||
int_any: u32,
|
||||
}
|
||||
|
||||
#[derive(derive_mmio::Mmio)]
|
||||
#[repr(C)]
|
||||
pub struct Gpio {
|
||||
/// Maskable output data (GPIO bank 0, MIO, lower 16 bits)
|
||||
masked_out_0_lsw: MaskedOutput,
|
||||
/// Maskable output data (GPIO bank 0, MIO, upper 16 bits)
|
||||
masked_out_0_msw: MaskedOutput,
|
||||
/// Maskable output data (GPIO bank 1, MIO, lower 16 bits)
|
||||
masked_out_1_lsw: MaskedOutput,
|
||||
/// Maskable output data (GPIO bank 1, MIO, upper 16 bits)
|
||||
masked_out_1_msw: MaskedOutput,
|
||||
/// Maskable output data (GPIO bank 2, EMIO, lower 16 bits)
|
||||
masked_out_2_lsw: MaskedOutput,
|
||||
/// Maskable output data (GPIO bank 2, EMIO, upper 16 bits)
|
||||
masked_out_2_msw: MaskedOutput,
|
||||
/// Maskable output data (GPIO bank 3, EMIO, lower 16 bits)
|
||||
masked_out_3_lsw: MaskedOutput,
|
||||
/// Maskable output data (GPIO bank 3, EMIO, upper 16 bits)
|
||||
masked_out_3_msw: MaskedOutput,
|
||||
|
||||
_reserved_0: [u32; 8],
|
||||
|
||||
/// Output data (GPIO bank 0, MIO)
|
||||
out_0: u32,
|
||||
/// Output data (GPIO bank 1, MIO)
|
||||
out_1: u32,
|
||||
/// Output data (GPIO bank 2, EMIO)
|
||||
out_2: u32,
|
||||
/// Output data (GPIO bank 3, EMIO)
|
||||
out_3: u32,
|
||||
|
||||
_reserved_1: [u32; 4],
|
||||
|
||||
/// Input data (GPIO bank 0, MIO)
|
||||
#[mmio(PureRead)]
|
||||
in_0: u32,
|
||||
/// Input data (GPIO bank 1, MIO)
|
||||
#[mmio(PureRead)]
|
||||
in_1: u32,
|
||||
/// Input data (GPIO bank 2, EMIO)
|
||||
#[mmio(PureRead)]
|
||||
in_2: u32,
|
||||
/// Input data (GPIO bank 3, EMIO)
|
||||
#[mmio(PureRead)]
|
||||
in_3: u32,
|
||||
|
||||
_reserved_2: [u32; 101],
|
||||
|
||||
#[mmio(inner)]
|
||||
bank_0: BankCtrl,
|
||||
|
||||
_reserved_3: [u32; 7],
|
||||
|
||||
#[mmio(inner)]
|
||||
bank_1: BankCtrl,
|
||||
|
||||
_reserved_4: [u32; 7],
|
||||
|
||||
#[mmio(inner)]
|
||||
bank_2: BankCtrl,
|
||||
|
||||
_reserved_5: [u32; 7],
|
||||
|
||||
#[mmio(inner)]
|
||||
bank_3: BankCtrl,
|
||||
}
|
||||
|
||||
static_assertions::const_assert_eq!(core::mem::size_of::<Gpio>(), 0x2E8);
|
||||
|
||||
impl Gpio {
|
||||
/// Create a new XGPIOPS GPIO MMIO instance.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This API can be used to potentially create a driver to the same peripheral structure
|
||||
/// from multiple threads. The user must ensure that concurrent accesses are safe and do not
|
||||
/// interfere with each other.
|
||||
pub const unsafe fn new_mmio_fixed() -> MmioGpio<'static> {
|
||||
MmioGpio {
|
||||
ptr: 0xE000A000 as *mut Gpio,
|
||||
phantom: core::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
60
zynq7000/src/gtc.rs
Normal file
60
zynq7000/src/gtc.rs
Normal file
@ -0,0 +1,60 @@
|
||||
//! # Global timer counter module.
|
||||
|
||||
pub const GTC_BASE_ADDR: usize = super::mpcore::MPCORE_BASE_ADDR + 0x0000_0200;
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
pub struct GtcCtrl {
|
||||
#[bits(8..=15, rw)]
|
||||
prescaler: u8,
|
||||
#[bit(3, rw)]
|
||||
auto_increment: bool,
|
||||
#[bit(2, rw)]
|
||||
irq_enable: bool,
|
||||
#[bit(1, rw)]
|
||||
comparator_enable: bool,
|
||||
#[bit(0, rw)]
|
||||
enable: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
pub struct InterruptStatus {
|
||||
#[bit(0, rw)]
|
||||
event_flag: bool,
|
||||
}
|
||||
|
||||
/// Global timer counter.
|
||||
#[derive(derive_mmio::Mmio)]
|
||||
#[repr(C)]
|
||||
pub struct Gtc {
|
||||
/// Count register 0, lower 32 bits
|
||||
count_lower: u32,
|
||||
/// Count register 1, upper 32 bits
|
||||
count_upper: u32,
|
||||
/// Control register
|
||||
ctrl: GtcCtrl,
|
||||
/// Interrupt status register
|
||||
#[mmio(PureRead, Write)]
|
||||
isr: InterruptStatus,
|
||||
/// Comparator 0, lower 32 bits
|
||||
comparator_lower: u32,
|
||||
/// Comparator 1, upper 32 bits
|
||||
comparator_upper: u32,
|
||||
/// Auto-increment register
|
||||
auto_increment: u32,
|
||||
}
|
||||
|
||||
static_assertions::const_assert_eq!(core::mem::size_of::<Gtc>(), 0x1C);
|
||||
|
||||
impl Gtc {
|
||||
/// Create a new GTC MMIO instance at the fixed base address.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This API can be used to potentially create a driver to the same peripheral structure
|
||||
/// from multiple threads. The user must ensure that concurrent accesses are safe and do not
|
||||
/// interfere with each other.
|
||||
#[inline]
|
||||
pub const unsafe fn new_mmio_fixed() -> MmioGtc<'static> {
|
||||
unsafe { Gtc::new_mmio_at(GTC_BASE_ADDR) }
|
||||
}
|
||||
}
|
203
zynq7000/src/i2c.rs
Normal file
203
zynq7000/src/i2c.rs
Normal file
@ -0,0 +1,203 @@
|
||||
//! SPI register module.
|
||||
use arbitrary_int::{u2, u6, u10};
|
||||
|
||||
pub const I2C_0_BASE_ADDR: usize = 0xE000_4000;
|
||||
pub const I2C_1_BASE_ADDR: usize = 0xE000_5000;
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug)]
|
||||
pub enum Direction {
|
||||
Receiver = 0b1,
|
||||
Transmitter = 0b0,
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug)]
|
||||
pub enum Mode {
|
||||
Slave = 0b0,
|
||||
Master = 0b1,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, default = 0x0)]
|
||||
pub struct Control {
|
||||
/// Divides the input PCLK frequency by this value + 1
|
||||
#[bits(14..=15, rw)]
|
||||
div_a: u2,
|
||||
/// Divides the output from divisor A by this value + 1
|
||||
#[bits(8..=13, rw)]
|
||||
div_b: u6,
|
||||
#[bit(6, rw)]
|
||||
clear_fifo: bool,
|
||||
#[bit(5, rw)]
|
||||
slv_mon: bool,
|
||||
/// 0: Allow transfer to terminate as soon as all data has been transmitted or received.
|
||||
/// 1: When no more data is avilable for transmit or no more data can be received, hold
|
||||
/// the SCK line low until services by the host.
|
||||
#[bit(4, rw)]
|
||||
hold_bus: bool,
|
||||
/// Should be set to 1. 0: Disabled, NACK transmitted. 1: Enabled, ACK transmitted.
|
||||
#[bit(3, rw)]
|
||||
acken: bool,
|
||||
/// Only used in master mode. 0: Reserved. 1: Normal 7-bit address.
|
||||
#[bit(2, rw)]
|
||||
addressing: bool,
|
||||
#[bit(1, rw)]
|
||||
mode: Mode,
|
||||
#[bit(0, rw)]
|
||||
dir: Direction,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
pub struct Status {
|
||||
#[bit(8, r)]
|
||||
bus_active: bool,
|
||||
/// FIFO is full and new byte was received. The new byte is not acknowledged and the contents
|
||||
/// of the FIFO remain unchanged.
|
||||
#[bit(6, r)]
|
||||
rx_overflow: bool,
|
||||
/// 1: There is still a byte of data to be transmitted by the interface.
|
||||
#[bit(6, r)]
|
||||
tx_busy: bool,
|
||||
/// Receiver data valid, ca be read from the interface.
|
||||
#[bit(5, r)]
|
||||
rx_valid: bool,
|
||||
#[bit(3, r)]
|
||||
rx_rw: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
pub struct Addr {
|
||||
#[bits(0..=9, rw)]
|
||||
addr: u10,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
pub struct Fifo {
|
||||
#[bits(0..=7, rw)]
|
||||
data: u8,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
pub struct InterruptStatus {
|
||||
#[bit(9, rw)]
|
||||
arbitration_lost: bool,
|
||||
#[bit(7, rw)]
|
||||
rx_underflow: bool,
|
||||
#[bit(6, rw)]
|
||||
tx_overflow: bool,
|
||||
#[bit(5, rw)]
|
||||
rx_overflow: bool,
|
||||
#[bit(4, rw)]
|
||||
slave_ready: bool,
|
||||
#[bit(3, rw)]
|
||||
timeout: bool,
|
||||
#[bit(2, rw)]
|
||||
nack: bool,
|
||||
#[bit(1, rw)]
|
||||
data: bool,
|
||||
#[bit(0, rw)]
|
||||
complete: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
pub struct InterruptMask {
|
||||
#[bit(9, r)]
|
||||
arbitration_lost: bool,
|
||||
#[bit(7, r)]
|
||||
rx_underflow: bool,
|
||||
#[bit(6, r)]
|
||||
tx_overflow: bool,
|
||||
#[bit(5, r)]
|
||||
rx_overflow: bool,
|
||||
#[bit(4, r)]
|
||||
slave_ready: bool,
|
||||
#[bit(3, r)]
|
||||
timeout: bool,
|
||||
#[bit(2, r)]
|
||||
nack: bool,
|
||||
#[bit(1, r)]
|
||||
data: bool,
|
||||
#[bit(0, r)]
|
||||
complete: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
pub struct InterruptControl {
|
||||
#[bit(9, w)]
|
||||
arbitration_lost: bool,
|
||||
#[bit(7, w)]
|
||||
rx_underflow: bool,
|
||||
#[bit(6, w)]
|
||||
tx_overflow: bool,
|
||||
#[bit(5, w)]
|
||||
rx_overflow: bool,
|
||||
#[bit(4, w)]
|
||||
slave_ready: bool,
|
||||
#[bit(3, w)]
|
||||
timeout: bool,
|
||||
#[bit(2, w)]
|
||||
nack: bool,
|
||||
#[bit(1, w)]
|
||||
data: bool,
|
||||
#[bit(0, w)]
|
||||
complete: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
pub struct Timeout {
|
||||
/// Reset value: 0x1F.
|
||||
#[bits(0..=7, rw)]
|
||||
timeout: u8,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, default = 0x0)]
|
||||
pub struct TransferSize {
|
||||
#[bits(0..=7, rw)]
|
||||
size: u8,
|
||||
}
|
||||
|
||||
#[derive(derive_mmio::Mmio)]
|
||||
#[repr(C)]
|
||||
pub struct I2c {
|
||||
cr: Control,
|
||||
#[mmio(PureRead)]
|
||||
sr: Status,
|
||||
addr: Addr,
|
||||
#[mmio(Read, Write)]
|
||||
data: Fifo,
|
||||
#[mmio(PureRead, Write, Modify)]
|
||||
isr: InterruptStatus,
|
||||
transfer_size: TransferSize,
|
||||
slave_pause: u32,
|
||||
timeout: Timeout,
|
||||
#[mmio(PureRead)]
|
||||
imr: InterruptMask,
|
||||
#[mmio(Write)]
|
||||
ier: InterruptControl,
|
||||
#[mmio(Write)]
|
||||
idr: InterruptControl,
|
||||
}
|
||||
|
||||
impl I2c {
|
||||
/// Create a new I2C MMIO instance for I2C0 at address [I2C_0_BASE_ADDR].
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This API can be used to potentially create a driver to the same peripheral structure
|
||||
/// from multiple threads. The user must ensure that concurrent accesses are safe and do not
|
||||
/// interfere with each other.
|
||||
pub const unsafe fn new_mmio_fixed_0() -> MmioI2c<'static> {
|
||||
unsafe { Self::new_mmio_at(I2C_0_BASE_ADDR) }
|
||||
}
|
||||
|
||||
/// Create a new I2C MMIO instance for I2C1 at address [I2C_1_BASE_ADDR].
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This API can be used to potentially create a driver to the same peripheral structure
|
||||
/// from multiple threads. The user must ensure that concurrent accesses are safe and do not
|
||||
/// interfere with each other.
|
||||
pub const unsafe fn new_mmio_fixed_1() -> MmioI2c<'static> {
|
||||
unsafe { Self::new_mmio_at(I2C_1_BASE_ADDR) }
|
||||
}
|
||||
}
|
85
zynq7000/src/lib.rs
Normal file
85
zynq7000/src/lib.rs
Normal file
@ -0,0 +1,85 @@
|
||||
//! # Rust peripheral acess crate to the AMD Zynq 7000 SoCs
|
||||
//!
|
||||
//! This crate provides a low-level register access API building on the
|
||||
//! [`derive-mmio` crate](https://crates.io/crates/derive-mmio). However, its structure
|
||||
//! is similar to the crates auto-generated by [`svd2rust`](https://docs.rs/svd2rust/latest/svd2rust/#peripheral-api).
|
||||
//!
|
||||
//! This crate is purposely kept low-level to allow building higher level abstractions like HALs
|
||||
//! on top of it.
|
||||
#![no_std]
|
||||
|
||||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
#[cfg(test)]
|
||||
extern crate std;
|
||||
|
||||
pub const MPCORE_BASE_ADDR: usize = 0xF8F0_0000;
|
||||
|
||||
pub mod gic;
|
||||
pub mod gpio;
|
||||
pub mod gtc;
|
||||
pub mod i2c;
|
||||
pub mod mpcore;
|
||||
pub mod slcr;
|
||||
pub mod spi;
|
||||
pub mod ttc;
|
||||
pub mod uart;
|
||||
|
||||
static PERIPHERALS_TAKEN: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
/// This is a collection of all the processing peripherals.
|
||||
///
|
||||
/// It is a singleton which exposes all peripherals supported by this crate.
|
||||
/// The [`svd2rust` documentation](https://docs.rs/svd2rust/latest/svd2rust/#peripheral-api)
|
||||
/// provides some more information about this.
|
||||
pub struct PsPeripherals {
|
||||
pub gicc: gic::MmioGicc<'static>,
|
||||
pub gicd: gic::MmioGicd<'static>,
|
||||
pub uart_0: uart::MmioUart<'static>,
|
||||
pub uart_1: uart::MmioUart<'static>,
|
||||
pub spi_0: spi::MmioSpi<'static>,
|
||||
pub spi_1: spi::MmioSpi<'static>,
|
||||
pub i2c_0: i2c::MmioI2c<'static>,
|
||||
pub i2c_1: i2c::MmioI2c<'static>,
|
||||
pub gtc: gtc::MmioGtc<'static>,
|
||||
pub gpio: gpio::MmioGpio<'static>,
|
||||
pub slcr: slcr::MmioSlcr<'static>,
|
||||
pub ttc_0: ttc::MmioTtc<'static>,
|
||||
pub ttc_1: ttc::MmioTtc<'static>,
|
||||
}
|
||||
|
||||
impl PsPeripherals {
|
||||
/// Returns all supported processing system peripherals *once*.
|
||||
pub fn take() -> Option<Self> {
|
||||
let taken = PERIPHERALS_TAKEN.swap(true, Ordering::Relaxed);
|
||||
if taken {
|
||||
return None;
|
||||
}
|
||||
Some(unsafe { Self::steal() })
|
||||
}
|
||||
|
||||
/// Unchecked version of [Self::take].
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Each of the returned peripherals must be used at most once.
|
||||
pub unsafe fn steal() -> Self {
|
||||
unsafe {
|
||||
Self {
|
||||
gicc: gic::Gicc::new_mmio_fixed(),
|
||||
gicd: gic::Gicd::new_mmio_fixed(),
|
||||
uart_0: uart::Uart::new_mmio_fixed_0(),
|
||||
uart_1: uart::Uart::new_mmio_fixed_1(),
|
||||
gtc: gtc::Gtc::new_mmio_fixed(),
|
||||
gpio: gpio::Gpio::new_mmio_fixed(),
|
||||
slcr: slcr::Slcr::new_mmio_fixed(),
|
||||
spi_0: spi::Spi::new_mmio_fixed_0(),
|
||||
spi_1: spi::Spi::new_mmio_fixed_1(),
|
||||
i2c_0: i2c::I2c::new_mmio_fixed_0(),
|
||||
i2c_1: i2c::I2c::new_mmio_fixed_1(),
|
||||
ttc_0: ttc::Ttc::new_mmio_fixed_0(),
|
||||
ttc_1: ttc::Ttc::new_mmio_fixed_1(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
97
zynq7000/src/mpcore.rs
Normal file
97
zynq7000/src/mpcore.rs
Normal file
@ -0,0 +1,97 @@
|
||||
//! Application Processing Unit Registers (mpcore)
|
||||
//!
|
||||
//! Based on p.1483 of the Zynq-7000 TRM.
|
||||
use static_assertions::const_assert_eq;
|
||||
|
||||
use crate::{
|
||||
gic::{Gicc, Gicd, MmioGicc, MmioGicd},
|
||||
gtc::{Gtc, MmioGtc},
|
||||
};
|
||||
|
||||
pub const MPCORE_BASE_ADDR: usize = 0xF8F0_0000;
|
||||
pub const SCU_BASE_ADDR: usize = MPCORE_BASE_ADDR;
|
||||
pub const GICC_BASE_ADDR: usize = MPCORE_BASE_ADDR + 0x100;
|
||||
pub const GICD_BASE_ADDR: usize = MPCORE_BASE_ADDR + 0x1000;
|
||||
|
||||
#[derive(derive_mmio::Mmio)]
|
||||
#[repr(C)]
|
||||
pub struct Scu {
|
||||
ctrl: u32,
|
||||
config: u32,
|
||||
cpu_power_status: u32,
|
||||
invalidate_all_regs_in_secure_state: u32,
|
||||
_reserved_0: [u32; 0xC],
|
||||
filtering_start_addr: u32,
|
||||
filtering_end_addr: u32,
|
||||
_reserved_1: [u32; 0x2],
|
||||
access_ctrl: u32,
|
||||
non_secure_access_ctrl: u32,
|
||||
}
|
||||
|
||||
impl Scu {
|
||||
/// Create a new Snoop Control Unit interface at the fixed base address.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This API can be used to potentially create a driver to the same peripheral structure
|
||||
/// from multiple threads. The user must ensure that concurrent accesses are safe and do not
|
||||
/// interfere with each other.
|
||||
#[inline]
|
||||
pub const unsafe fn new_mmio_fixed() -> MmioScu<'static> {
|
||||
unsafe { Self::new_mmio_at(SCU_BASE_ADDR) }
|
||||
}
|
||||
}
|
||||
|
||||
const_assert_eq!(core::mem::size_of::<Scu>(), 0x58);
|
||||
|
||||
#[derive(derive_mmio::Mmio)]
|
||||
#[repr(C)]
|
||||
pub struct Mpcore {
|
||||
#[mmio(inner)]
|
||||
scu: Scu,
|
||||
|
||||
_reserved_0: [u32; 0x2A],
|
||||
|
||||
#[mmio(inner)]
|
||||
gicc: Gicc,
|
||||
|
||||
#[mmio(inner)]
|
||||
gt: Gtc,
|
||||
|
||||
_reserved_1: [u32; 0xF9],
|
||||
|
||||
private_timer_load: u32,
|
||||
private_timer_counter: u32,
|
||||
private_timer_ctrl: u32,
|
||||
private_interrupt_status: u32,
|
||||
|
||||
_reserved_2: [u32; 0x4],
|
||||
|
||||
watchdog_load: u32,
|
||||
watchdog_counter: u32,
|
||||
watchdog_ctrl: u32,
|
||||
watchdog_interrupt_status: u32,
|
||||
watchdog_reset_status: u32,
|
||||
watchdog_disable: u32,
|
||||
|
||||
_reserved_3: [u32; 0x272],
|
||||
|
||||
#[mmio(inner)]
|
||||
gicd: Gicd,
|
||||
}
|
||||
|
||||
const_assert_eq!(core::mem::size_of::<Mpcore>(), 0x2000);
|
||||
|
||||
impl Mpcore {
|
||||
/// Create a MP core peripheral interface at the fixed base address.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This API can be used to potentially create a driver to the same peripheral structure
|
||||
/// from multiple threads. The user must ensure that concurrent accesses are safe and do not
|
||||
/// interfere with each other.
|
||||
#[inline]
|
||||
pub const unsafe fn new_mmio_fixed() -> MmioMpcore<'static> {
|
||||
unsafe { Self::new_mmio_at(MPCORE_BASE_ADDR) }
|
||||
}
|
||||
}
|
364
zynq7000/src/slcr/clocks.rs
Normal file
364
zynq7000/src/slcr/clocks.rs
Normal file
@ -0,0 +1,364 @@
|
||||
//! SLCR clock control registers.
|
||||
//!
|
||||
//! Writing any of these registers required unlocking the SLCR first.
|
||||
use super::{CLOCK_CONTROL_OFFSET, SLCR_BASE_ADDR};
|
||||
use arbitrary_int::{u4, u6, u7, u10};
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug)]
|
||||
pub enum BypassForce {
|
||||
EnabledOrSetByBootMode = 0b0,
|
||||
Bypassed = 0b1,
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug)]
|
||||
pub enum BypassQual {
|
||||
BypassForceBit = 0b0,
|
||||
BootModeFourthBit = 0b1,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
#[derive(Debug)]
|
||||
pub struct PllCtrl {
|
||||
/// Feedback divisor for the PLL.
|
||||
///
|
||||
/// NOTE: Before changing this value, the PLL must first be bypassed and then put into
|
||||
/// reset mode.
|
||||
#[bits(12..=18, rw)]
|
||||
fdiv: u7,
|
||||
/// Select source for the ARM PLL bypass control
|
||||
#[bit(4, rw)]
|
||||
bypass_force: BypassForce,
|
||||
/// Select source for the ARM PLL bypass control
|
||||
#[bit(3, rw)]
|
||||
bypass_qual: BypassQual,
|
||||
// Power-down control
|
||||
#[bit(1, rw)]
|
||||
pwrdwn: bool,
|
||||
/// Reset control
|
||||
#[bit(0, rw)]
|
||||
reset: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
#[derive(Debug)]
|
||||
pub struct PllCfg {
|
||||
#[bits(12..=21, rw)]
|
||||
lock_count: u10,
|
||||
/// Charge Pump control
|
||||
#[bits(8..=11, rw)]
|
||||
pll_cp: u4,
|
||||
/// Loop resistor control
|
||||
#[bits(4..=7, rw)]
|
||||
pll_res: u4,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
#[derive(Debug)]
|
||||
pub struct PllStatus {
|
||||
#[bit(5)]
|
||||
io_pll_stable: bool,
|
||||
#[bit(4)]
|
||||
ddr_pll_stable: bool,
|
||||
#[bit(3)]
|
||||
arm_pll_stable: bool,
|
||||
#[bit(2)]
|
||||
io_pll_lock: bool,
|
||||
#[bit(1)]
|
||||
drr_pll_lock: bool,
|
||||
#[bit(0)]
|
||||
arm_pll_lock: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
#[derive(Debug)]
|
||||
pub struct FpgaClkControl {
|
||||
// Reset value 0x1
|
||||
#[bits(20..=25, rw)]
|
||||
divisor_1: u6,
|
||||
// Reset value 0x18
|
||||
#[bits(8..=13, rw)]
|
||||
divisor_0: u6,
|
||||
#[bits(4..=5, rw)]
|
||||
srcsel: SrcSelIo,
|
||||
}
|
||||
|
||||
#[derive(derive_mmio::Mmio)]
|
||||
#[repr(C)]
|
||||
pub struct FpgaClkBlock {
|
||||
clk_ctrl: FpgaClkControl,
|
||||
thr_ctrl: u32,
|
||||
thr_cnt: u32,
|
||||
thr_status: u32,
|
||||
}
|
||||
|
||||
static_assertions::const_assert_eq!(core::mem::size_of::<FpgaClkBlock>(), 0x10);
|
||||
|
||||
#[bitbybit::bitenum(u2, exhaustive = true)]
|
||||
#[derive(Debug)]
|
||||
pub enum SrcSelArm {
|
||||
ArmPll = 0b00,
|
||||
ArmPllAlt = 0b01,
|
||||
DdrPll = 0b10,
|
||||
IoPll = 0b11,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
pub struct ArmClkCtrl {
|
||||
#[bit(28, rw)]
|
||||
cpu_peri_clk_act: bool,
|
||||
#[bit(27, rw)]
|
||||
cpu_1x_clk_act: bool,
|
||||
#[bit(26, rw)]
|
||||
cpu_2x_clk_act: bool,
|
||||
#[bit(25, rw)]
|
||||
cpu_3or2x_clk_act: bool,
|
||||
#[bit(24, rw)]
|
||||
cpu_6or4x_clk_act: bool,
|
||||
/// Reset value: 0x4. There is a requirement for the quality of the high speed clock that
|
||||
/// it has to be divided by an even number. This field must be equal to or greater than 2.
|
||||
#[bits(8..=13, rw)]
|
||||
divisor: u6,
|
||||
/// Reset value: 0x0
|
||||
#[bits(4..=5, rw)]
|
||||
srcsel: SrcSelArm,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
pub struct DdrClkCtrl {
|
||||
/// Divisor for DDR 2x clock. Reset value: 0x6
|
||||
#[bits(26..=31, rw)]
|
||||
div_2x_clk: u6,
|
||||
/// Divisor for DDR 3x clock. Only even divisors are allowed! Reset value: 0x4
|
||||
#[bits(20..=25, rw)]
|
||||
div_3x_clk: u6,
|
||||
/// Reset value: 0x1
|
||||
#[bit(1, rw)]
|
||||
ddr_2x_clk_act: bool,
|
||||
/// Reset value: 0x1
|
||||
#[bit(0, rw)]
|
||||
ddr_3x_clk_act: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
pub struct DciClkCtrl {
|
||||
/// Second cascade divider. Reset value: 0x1E
|
||||
#[bits(20..=25, rw)]
|
||||
divisor_1: u6,
|
||||
/// Reset value: 0x32
|
||||
#[bits(8..=13, rw)]
|
||||
divisor_0: u6,
|
||||
/// Reset value: 0x1
|
||||
#[bit(0, rw)]
|
||||
clk_act: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
#[derive(Debug)]
|
||||
pub struct ClockRatioSelectReg {
|
||||
/// Reset value: 0x1 (6:2:1 clock)
|
||||
#[bit(0, rw)]
|
||||
sel: ClockRatioSelect,
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug)]
|
||||
pub enum ClockRatioSelect {
|
||||
/// 4:2:1 clock ratio, which is an abbreviation for 4:2:2:1.
|
||||
FourToTwoToOne = 0b0,
|
||||
/// 6:2:1 clock ratio, which is an abbreviation for 6:3:2:1.
|
||||
SixToTwoToOne = 0b1,
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u2, exhaustive = true)]
|
||||
#[derive(Debug)]
|
||||
pub enum SrcSelIo {
|
||||
IoPll = 0b00,
|
||||
IoPllAlt = 0b01,
|
||||
ArmPll = 0b10,
|
||||
DdrPll = 0b11,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
#[derive(Debug)]
|
||||
pub struct GigEthClkCtrl {
|
||||
#[bits(20..=25, rw)]
|
||||
divisor_1: u6,
|
||||
#[bits(8..=13, rw)]
|
||||
divisor_0: u6,
|
||||
#[bit(6, rw)]
|
||||
use_emio_tx_clk: bool,
|
||||
#[bits(4..=5, rw)]
|
||||
srcsel: SrcSelIo,
|
||||
#[bit(0, rw)]
|
||||
clk_act: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
#[derive(Debug)]
|
||||
pub struct CanClkCtrl {
|
||||
#[bits(20..=25, rw)]
|
||||
divisor_1: u6,
|
||||
#[bits(8..=13, rw)]
|
||||
divisor_0: u6,
|
||||
#[bits(4..=5, rw)]
|
||||
srcsel: SrcSelIo,
|
||||
#[bit(1, rw)]
|
||||
clk_1_act: bool,
|
||||
#[bit(0, rw)]
|
||||
clk_0_act: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
pub struct SingleCommonPeriphIoClkCtrl {
|
||||
#[bits(8..=13, rw)]
|
||||
divisor: u6,
|
||||
#[bits(4..=5, rw)]
|
||||
srcsel: SrcSelIo,
|
||||
#[bit(0, rw)]
|
||||
clk_act: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
#[derive(Debug)]
|
||||
pub struct DualCommonPeriphIoClkCtrl {
|
||||
#[bits(8..=13, rw)]
|
||||
divisor: u6,
|
||||
#[bits(4..=5, rw)]
|
||||
srcsel: SrcSelIo,
|
||||
#[bit(1, rw)]
|
||||
clk_1_act: bool,
|
||||
#[bit(0, rw)]
|
||||
clk_0_act: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u3, exhaustive = true)]
|
||||
#[derive(Debug)]
|
||||
pub enum SrcSelTpiu {
|
||||
IoPll = 0b000,
|
||||
IoPllAlt = 0b001,
|
||||
ArmPll = 0b010,
|
||||
DdrPll = 0b011,
|
||||
EmioTraceClk = 0b100,
|
||||
EmioTraceClkAlt0 = 0b101,
|
||||
EmioTraceClkAlt1 = 0b110,
|
||||
EmioTraceClkAlt2 = 0b111,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
pub struct TracePortClkCtrl {
|
||||
#[bits(8..=13, rw)]
|
||||
divisor: u6,
|
||||
#[bits(4..=6, rw)]
|
||||
srcsel: SrcSelTpiu,
|
||||
#[bit(1, rw)]
|
||||
clk_1x_clk_act: bool,
|
||||
#[bit(0, rw)]
|
||||
clk_act: bool,
|
||||
}
|
||||
|
||||
/// AMBA peripheral clock control.
|
||||
///
|
||||
/// These clocks must be enabled if you want to read from the peripheral register space.
|
||||
#[bitbybit::bitfield(u32)]
|
||||
#[derive(Debug)]
|
||||
pub struct AperClkCtrl {
|
||||
#[bit(24, rw)]
|
||||
smc_1x_clk_act: bool,
|
||||
#[bit(23, rw)]
|
||||
lqspi_1x_clk_act: bool,
|
||||
#[bit(22, rw)]
|
||||
gpio_1x_clk_act: bool,
|
||||
#[bit(21, rw)]
|
||||
uart_1_1x_clk_act: bool,
|
||||
#[bit(20, rw)]
|
||||
uart_0_1x_clk_act: bool,
|
||||
#[bit(19, rw)]
|
||||
i2c_1_1x_clk_act: bool,
|
||||
#[bit(18, rw)]
|
||||
i2c_0_1x_clk_act: bool,
|
||||
#[bit(17, rw)]
|
||||
can_1_1x_clk_act: bool,
|
||||
#[bit(16, rw)]
|
||||
can_0_1x_clk_act: bool,
|
||||
#[bit(15, rw)]
|
||||
spi_1_1x_clk_act: bool,
|
||||
#[bit(14, rw)]
|
||||
spi_0_1x_clk_act: bool,
|
||||
#[bit(11, rw)]
|
||||
sdio_1_1x_clk_act: bool,
|
||||
#[bit(10, rw)]
|
||||
sdio_0_1x_clk_act: bool,
|
||||
#[bit(7, rw)]
|
||||
gem_1_1x_clk_act: bool,
|
||||
#[bit(6, rw)]
|
||||
gem_0_1x_clk_act: bool,
|
||||
#[bit(3, rw)]
|
||||
usb_1_cpu_1x_clk_act: bool,
|
||||
#[bit(2, rw)]
|
||||
usb_0_cpu_1x_clk_act: bool,
|
||||
#[bit(0, rw)]
|
||||
dma_cpu_2x_clk_act: bool,
|
||||
}
|
||||
|
||||
#[derive(derive_mmio::Mmio)]
|
||||
#[repr(C)]
|
||||
pub struct ClockControl {
|
||||
arm_pll: PllCtrl,
|
||||
ddr_pll: PllCtrl,
|
||||
io_pll: PllCtrl,
|
||||
pll_status: PllStatus,
|
||||
arm_pll_cfg: PllCfg,
|
||||
ddr_pll_cfg: PllCfg,
|
||||
io_pll_cfg: PllCfg,
|
||||
_gap0: u32,
|
||||
arm_clk_ctrl: ArmClkCtrl,
|
||||
ddr_clk_ctrl: DdrClkCtrl,
|
||||
dci_clk_ctrl: DciClkCtrl,
|
||||
/// AMBA peripheral clock control
|
||||
aper_clk_ctrl: AperClkCtrl,
|
||||
usb_0_clk_ctrl: u32,
|
||||
usb_1_clk_ctrl: u32,
|
||||
gem_0_rclk_ctrl: u32,
|
||||
gem_1_rclk_ctrl: u32,
|
||||
gem_0_clk_ctrl: GigEthClkCtrl,
|
||||
gem_1_clk_ctrl: GigEthClkCtrl,
|
||||
smc_clk_ctrl: SingleCommonPeriphIoClkCtrl,
|
||||
lqspi_clk_ctrl: SingleCommonPeriphIoClkCtrl,
|
||||
sdio_clk_ctrl: DualCommonPeriphIoClkCtrl,
|
||||
uart_clk_ctrl: DualCommonPeriphIoClkCtrl,
|
||||
spi_clk_ctrl: DualCommonPeriphIoClkCtrl,
|
||||
can_clk_ctrl: CanClkCtrl,
|
||||
can_mioclk_ctrl: u32,
|
||||
/// Debug or Trace Port clock control.
|
||||
dbg_clk_ctrl: TracePortClkCtrl,
|
||||
pcap_clk_ctrl: SingleCommonPeriphIoClkCtrl,
|
||||
topsw_clk_ctrl: u32,
|
||||
#[mmio(inner)]
|
||||
fpga_0_clk_ctrl: FpgaClkBlock,
|
||||
#[mmio(inner)]
|
||||
fpga_1_clk_ctrl: FpgaClkBlock,
|
||||
#[mmio(inner)]
|
||||
fpga_2_clk_ctrl: FpgaClkBlock,
|
||||
#[mmio(inner)]
|
||||
fpga_3_clk_ctrl: FpgaClkBlock,
|
||||
_gap1: [u32; 5],
|
||||
clk_621_true: ClockRatioSelectReg,
|
||||
}
|
||||
|
||||
impl ClockControl {
|
||||
/// Create a new handle to this peripheral.
|
||||
///
|
||||
/// Writing to this register requires unlocking the SLCR registers first.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// If you create multiple instances of this handle at the same time, you are responsible for
|
||||
/// ensuring that there are no read-modify-write races on any of the registers.
|
||||
pub unsafe fn new_mmio_fixed() -> MmioClockControl<'static> {
|
||||
unsafe { Self::new_mmio_at(SLCR_BASE_ADDR + CLOCK_CONTROL_OFFSET) }
|
||||
}
|
||||
}
|
||||
|
||||
static_assertions::const_assert_eq!(core::mem::size_of::<ClockControl>(), 0xC8);
|
41
zynq7000/src/slcr/mio.rs
Normal file
41
zynq7000/src/slcr/mio.rs
Normal file
@ -0,0 +1,41 @@
|
||||
//! # SLCR MIO (Multiplexed I/O) configuration registers
|
||||
//!
|
||||
//! Writing any of these registers required unlocking the SLCR first.
|
||||
use arbitrary_int::{u2, u3};
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
pub enum Speed {
|
||||
SlowCmosEdge = 0b0,
|
||||
FastCmosEdge = 0b1,
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u3)]
|
||||
pub enum IoType {
|
||||
LvCmos18 = 0b001,
|
||||
LvCmos25 = 0b010,
|
||||
LvCmos33 = 0b011,
|
||||
Hstl = 0b100,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
#[derive(Debug)]
|
||||
pub struct Config {
|
||||
#[bit(13, rw)]
|
||||
disable_hstl_rcvr: bool,
|
||||
#[bit(12, rw)]
|
||||
pullup: bool,
|
||||
#[bits(9..=11, rw)]
|
||||
io_type: Option<IoType>,
|
||||
#[bit(8, rw)]
|
||||
speed: Speed,
|
||||
#[bits(5..=7, rw)]
|
||||
l3_sel: u3,
|
||||
#[bits(3..=4, rw)]
|
||||
l2_sel: u2,
|
||||
#[bit(2, rw)]
|
||||
l1_sel: bool,
|
||||
#[bit(1, rw)]
|
||||
l0_sel: bool,
|
||||
#[bit(0, rw)]
|
||||
tri_enable: bool,
|
||||
}
|
206
zynq7000/src/slcr/mod.rs
Normal file
206
zynq7000/src/slcr/mod.rs
Normal file
@ -0,0 +1,206 @@
|
||||
//! System Level Control Registers (slcr)
|
||||
//!
|
||||
//! Writing any of these registers required unlocking the SLCR first.
|
||||
use arbitrary_int::u4;
|
||||
pub use clocks::{ClockControl, MmioClockControl};
|
||||
pub use reset::{MmioResetControl, ResetControl};
|
||||
|
||||
const SLCR_BASE_ADDR: usize = 0xF8000000;
|
||||
const CLOCK_CONTROL_OFFSET: usize = 0x100;
|
||||
const RESET_BLOCK_OFFSET: usize = 0x200;
|
||||
const GPIOB_OFFSET: usize = 0xB00;
|
||||
const DDRIOB_OFFSET: usize = 0xB40;
|
||||
|
||||
pub mod clocks;
|
||||
pub mod mio;
|
||||
pub mod reset;
|
||||
|
||||
#[derive(derive_mmio::Mmio)]
|
||||
#[repr(C)]
|
||||
pub struct DdrIoB {
|
||||
ddriob_addr0: u32,
|
||||
ddriob_addr1: u32,
|
||||
ddriob_data0: u32,
|
||||
ddriob_data1: u32,
|
||||
ddriob_diff0: u32,
|
||||
ddriob_diff1: u32,
|
||||
ddriob_clock: u32,
|
||||
ddriob_drive_slew_addr: u32,
|
||||
ddriob_drive_slew_data: u32,
|
||||
ddriob_drive_slew_diff: u32,
|
||||
ddriob_drive_slew_clock: u32,
|
||||
ddriob_ddr_ctrl: u32,
|
||||
ddriob_dci_ctrl: u32,
|
||||
ddriob_dci_status: u32,
|
||||
}
|
||||
|
||||
impl DdrIoB {
|
||||
/// Create a new handle to this peripheral.
|
||||
///
|
||||
/// Writing to this register requires unlocking the SLCR registers first.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// If you create multiple instances of this handle at the same time, you are responsible for
|
||||
/// ensuring that there are no read-modify-write races on any of the registers.
|
||||
pub unsafe fn new_mmio_fixed() -> MmioDdrIoB<'static> {
|
||||
unsafe { Self::new_mmio_at(SLCR_BASE_ADDR + DDRIOB_OFFSET) }
|
||||
}
|
||||
}
|
||||
|
||||
static_assertions::const_assert_eq!(core::mem::size_of::<DdrIoB>(), 0x38);
|
||||
|
||||
#[derive(derive_mmio::Mmio)]
|
||||
#[repr(C)]
|
||||
pub struct GpiobCtrl {
|
||||
ctrl: u32,
|
||||
cfg_cmos18: u32,
|
||||
cfg_cmos25: u32,
|
||||
cfg_cmos33: u32,
|
||||
_gap17: u32,
|
||||
cfg_hstl: u32,
|
||||
drvr_bias_ctrl: u32,
|
||||
}
|
||||
|
||||
impl GpiobCtrl {
|
||||
/// Create a new handle to this peripheral.
|
||||
///
|
||||
/// Writing to this register requires unlocking the SLCR registers first.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// If you create multiple instances of this handle at the same time, you are responsible for
|
||||
/// ensuring that there are no read-modify-write races on any of the registers.
|
||||
pub unsafe fn new_mmio_fixed() -> MmioGpiobCtrl<'static> {
|
||||
unsafe { Self::new_mmio_at(SLCR_BASE_ADDR + GPIOB_OFFSET) }
|
||||
}
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
pub struct BootModeRegister {
|
||||
#[bit(4, r)]
|
||||
pll_bypass: bool,
|
||||
#[bits(0..=3, r)]
|
||||
boot_mode: u4,
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u4)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum LevelShifterConfig {
|
||||
DisableAll = 0x00,
|
||||
EnablePsToPl = 0xA,
|
||||
EnableAll = 0xF,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
pub struct LevelShifterReg {
|
||||
#[bits(0..=3, rw)]
|
||||
user_lvl_shftr_en: Option<LevelShifterConfig>,
|
||||
}
|
||||
|
||||
/// System Level Control Registers
|
||||
#[derive(derive_mmio::Mmio)]
|
||||
#[repr(C)]
|
||||
pub struct Slcr {
|
||||
/// Secure configuration lock.
|
||||
scl: u32,
|
||||
/// SLCR write protection lock
|
||||
lock: u32,
|
||||
/// SLCR write protection unlock
|
||||
unlock: u32,
|
||||
/// SLCR write protection status
|
||||
lock_status: u32,
|
||||
|
||||
_gap0: [u32; 0x3C],
|
||||
|
||||
#[mmio(inner)]
|
||||
clk_ctrl: ClockControl,
|
||||
|
||||
_gap1: [u32; 0x0E],
|
||||
|
||||
#[mmio(inner)]
|
||||
reset_ctrl: ResetControl,
|
||||
|
||||
_gap2: [u32; 0x02],
|
||||
|
||||
reboot_status: u32,
|
||||
boot_mode: BootModeRegister,
|
||||
|
||||
_gap3: [u32; 0x28],
|
||||
|
||||
apu_ctrl: u32,
|
||||
wdt_clk_set: u32,
|
||||
|
||||
_gap4: [u32; 0x4E],
|
||||
|
||||
tz_dma_ns: u32,
|
||||
tz_dma_irq_ns: u32,
|
||||
tz_dma_periph_ns: u32,
|
||||
|
||||
_gap5: [u32; 0x39],
|
||||
|
||||
pss_idcode: u32,
|
||||
|
||||
_gap6: [u32; 0x33],
|
||||
|
||||
ddr_urgent: u32,
|
||||
_gap7: [u32; 0x02],
|
||||
ddr_cal_start: u32,
|
||||
_gap8: u32,
|
||||
ddr_ref_start: u32,
|
||||
ddr_cmd_status: u32,
|
||||
ddr_urgent_sel: u32,
|
||||
ddr_dfi_status: u32,
|
||||
|
||||
_gap9: [u32; 0x37],
|
||||
|
||||
mio_pins: [mio::Config; 0x36],
|
||||
|
||||
_gap10: [u32; 0x0B],
|
||||
|
||||
mio_loopback: u32,
|
||||
_gap11: u32,
|
||||
mio_mst_tri_0: u32,
|
||||
mio_mst_tri_1: u32,
|
||||
_gap12: [u32; 7],
|
||||
sd_0_wp_cd_sel: u32,
|
||||
sd_1_wp_cd_sel: u32,
|
||||
|
||||
_gap13: [u32; 0x32],
|
||||
|
||||
lvl_shftr_en: LevelShifterReg,
|
||||
|
||||
_gap14: [u32; 0x03],
|
||||
|
||||
ocm_cfg: u32,
|
||||
|
||||
_gap15: [u32; 0x42],
|
||||
|
||||
reserved: u32,
|
||||
|
||||
_gap16: [u32; 0x38],
|
||||
|
||||
_gap18: [u32; 0x09],
|
||||
|
||||
#[mmio(inner)]
|
||||
gpiob: GpiobCtrl,
|
||||
|
||||
#[mmio(inner)]
|
||||
ddriob: DdrIoB,
|
||||
}
|
||||
|
||||
static_assertions::const_assert_eq!(core::mem::size_of::<Slcr>(), 0xB78);
|
||||
|
||||
impl Slcr {
|
||||
/// Create a new handle to this peripheral.
|
||||
///
|
||||
/// Writing to this register requires unlocking the SLCR registers first.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// If you create multiple instances of this handle at the same time, you are responsible for
|
||||
/// ensuring that there are no read-modify-write races on any of the registers.
|
||||
pub unsafe fn new_mmio_fixed() -> MmioSlcr<'static> {
|
||||
unsafe { Self::new_mmio_at(SLCR_BASE_ADDR) }
|
||||
}
|
||||
}
|
79
zynq7000/src/slcr/reset.rs
Normal file
79
zynq7000/src/slcr/reset.rs
Normal file
@ -0,0 +1,79 @@
|
||||
use super::{RESET_BLOCK_OFFSET, SLCR_BASE_ADDR};
|
||||
|
||||
#[bitbybit::bitfield(u32, default = 0x0)]
|
||||
#[derive(Debug)]
|
||||
pub struct DualClockReset {
|
||||
/// Peripheral 1 AMBA software reset.
|
||||
#[bit(1, rw)]
|
||||
periph1_cpu1x_rst: bool,
|
||||
/// Peripheral 0 AMBA software reset.
|
||||
#[bit(0, rw)]
|
||||
periph0_cpu1x_rst: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, default = 0x0)]
|
||||
#[derive(Debug)]
|
||||
pub struct DualRefAndClockReset {
|
||||
/// Periperal 1 Reference software reset.
|
||||
#[bit(3, rw)]
|
||||
periph1_ref_rst: bool,
|
||||
/// Peripheral 0 Reference software reset.
|
||||
#[bit(2, rw)]
|
||||
periph0_ref_rst: bool,
|
||||
/// Peripheral 1 AMBA software reset.
|
||||
#[bit(1, rw)]
|
||||
periph1_cpu1x_rst: bool,
|
||||
/// Peripheral 0 AMBA software reset.
|
||||
#[bit(0, rw)]
|
||||
periph0_cpu1x_rst: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, default = 0x0)]
|
||||
#[derive(Debug)]
|
||||
pub struct GpioClockReset {
|
||||
#[bit(0, rw)]
|
||||
gpio_cpu1x_rst: bool,
|
||||
}
|
||||
|
||||
#[derive(derive_mmio::Mmio)]
|
||||
#[repr(C)]
|
||||
pub struct ResetControl {
|
||||
/// PS Software reset control
|
||||
pss: u32,
|
||||
ddr: u32,
|
||||
/// Central interconnect reset control
|
||||
topsw: u32,
|
||||
dmac: u32,
|
||||
usb: u32,
|
||||
gem: u32,
|
||||
sdio: DualRefAndClockReset,
|
||||
spi: DualRefAndClockReset,
|
||||
can: DualClockReset,
|
||||
i2c: DualClockReset,
|
||||
uart: DualRefAndClockReset,
|
||||
gpio: GpioClockReset,
|
||||
lqspi: u32,
|
||||
smc: u32,
|
||||
ocm: u32,
|
||||
_gap0: u32,
|
||||
fpga: u32,
|
||||
a9_cpu: u32,
|
||||
_gap1: u32,
|
||||
rs_awdt: u32,
|
||||
}
|
||||
|
||||
impl ResetControl {
|
||||
/// Create a new handle to this peripheral.
|
||||
///
|
||||
/// Writing to this register requires unlocking the SLCR registers first.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// If you create multiple instances of this handle at the same time, you are responsible for
|
||||
/// ensuring that there are no read-modify-write races on any of the registers.
|
||||
pub unsafe fn new_mmio_fixed() -> MmioResetControl<'static> {
|
||||
unsafe { Self::new_mmio_at(SLCR_BASE_ADDR + RESET_BLOCK_OFFSET) }
|
||||
}
|
||||
}
|
||||
|
||||
static_assertions::const_assert_eq!(core::mem::size_of::<ResetControl>(), 0x50);
|
236
zynq7000/src/spi.rs
Normal file
236
zynq7000/src/spi.rs
Normal file
@ -0,0 +1,236 @@
|
||||
//! SPI register module.
|
||||
use arbitrary_int::{Number, u4};
|
||||
|
||||
pub const SPI_0_BASE_ADDR: usize = 0xE000_6000;
|
||||
pub const SPI_1_BASE_ADDR: usize = 0xE000_7000;
|
||||
|
||||
/// The SPI reference block will be divided by a divisor value.
|
||||
#[bitbybit::bitenum(u3)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum BaudDivSelect {
|
||||
By4 = 0b001,
|
||||
By8 = 0b010,
|
||||
By16 = 0b011,
|
||||
By32 = 0b100,
|
||||
By64 = 0b101,
|
||||
By128 = 0b110,
|
||||
By256 = 0b111,
|
||||
}
|
||||
|
||||
impl BaudDivSelect {
|
||||
pub const fn div_value(&self) -> usize {
|
||||
match self {
|
||||
BaudDivSelect::By4 => 4,
|
||||
BaudDivSelect::By8 => 8,
|
||||
BaudDivSelect::By16 => 16,
|
||||
BaudDivSelect::By32 => 32,
|
||||
BaudDivSelect::By64 => 64,
|
||||
BaudDivSelect::By128 => 128,
|
||||
BaudDivSelect::By256 => 256,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, default = 0x0)]
|
||||
#[derive(Debug)]
|
||||
pub struct Config {
|
||||
#[bit(17, rw)]
|
||||
modefail_gen_en: bool,
|
||||
#[bit(16, w)]
|
||||
manual_start: bool,
|
||||
#[bit(15, rw)]
|
||||
manual_start_enable: bool,
|
||||
#[bit(14, rw)]
|
||||
manual_cs: bool,
|
||||
#[bits(10..=13, rw)]
|
||||
cs_raw: u4,
|
||||
/// Peripheral select decode, 1: Allow external 3-to-8 decode.
|
||||
/// I am not sure how exactly this work, but I suspect the last three bits of the chip
|
||||
/// select bits will be output directly to the 3 chip select output lines.
|
||||
#[bit(9, rw)]
|
||||
peri_sel: bool,
|
||||
/// Uses SPI reference clock, value 1 is not supported.
|
||||
#[bit(8, r)]
|
||||
ref_clk: bool,
|
||||
#[bits(3..=5, rw)]
|
||||
baud_rate_div: Option<BaudDivSelect>,
|
||||
/// Clock phase. 1: The SPI clock is inactive outside the word.
|
||||
#[bit(2, rw)]
|
||||
cpha: bool,
|
||||
/// Clock phase. 1: The SPI clock is quiescent high.
|
||||
#[bit(1, rw)]
|
||||
cpol: bool,
|
||||
/// Master mode enable. 1 is master mode.
|
||||
#[bit(0, rw)]
|
||||
master_ern: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, default = 0x0)]
|
||||
#[derive(Debug)]
|
||||
pub struct InterruptStatus {
|
||||
#[bit(6, rw)]
|
||||
tx_underflow: bool,
|
||||
#[bit(5, rw)]
|
||||
rx_full: bool,
|
||||
#[bit(4, rw)]
|
||||
rx_not_empty: bool,
|
||||
#[bit(3, rw)]
|
||||
tx_full: bool,
|
||||
#[bit(2, rw)]
|
||||
tx_not_full: bool,
|
||||
#[bit(1, rw)]
|
||||
mode_fault: bool,
|
||||
/// Receiver overflow interrupt.
|
||||
#[bit(0, rw)]
|
||||
rx_ovr: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, default = 0x0)]
|
||||
#[derive(Debug)]
|
||||
pub struct InterruptControl {
|
||||
#[bit(6, w)]
|
||||
tx_underflow: bool,
|
||||
#[bit(5, w)]
|
||||
rx_full: bool,
|
||||
#[bit(4, w)]
|
||||
rx_not_empty: bool,
|
||||
#[bit(3, w)]
|
||||
tx_full: bool,
|
||||
#[bit(2, w)]
|
||||
tx_trig: bool,
|
||||
#[bit(1, w)]
|
||||
mode_fault: bool,
|
||||
/// Receiver overflow interrupt.
|
||||
#[bit(0, w)]
|
||||
rx_ovr: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
#[derive(Debug)]
|
||||
pub struct InterruptMask {
|
||||
#[bit(6, r)]
|
||||
tx_underflow: bool,
|
||||
#[bit(5, r)]
|
||||
rx_full: bool,
|
||||
#[bit(4, r)]
|
||||
rx_not_empty: bool,
|
||||
#[bit(3, r)]
|
||||
tx_full: bool,
|
||||
#[bit(2, r)]
|
||||
tx_trig: bool,
|
||||
#[bit(1, r)]
|
||||
mode_fault: bool,
|
||||
/// Receiver overflow interrupt.
|
||||
#[bit(0, r)]
|
||||
rx_ovr: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FifoWrite(arbitrary_int::UInt<u32, 8>);
|
||||
|
||||
impl FifoWrite {
|
||||
#[inline]
|
||||
pub fn new(data: u8) -> Self {
|
||||
Self(data.into())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn value(&self) -> u8 {
|
||||
self.0.as_u8()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn write(&mut self, value: u8) {
|
||||
self.0 = value.into();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FifoRead(arbitrary_int::UInt<u32, 8>);
|
||||
|
||||
impl FifoRead {
|
||||
#[inline]
|
||||
pub fn new(data: u8) -> Self {
|
||||
Self(data.into())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn value(&self) -> u8 {
|
||||
self.0.as_u8()
|
||||
}
|
||||
}
|
||||
|
||||
/// The numbers specified in the register fields are always specified in number of
|
||||
#[bitbybit::bitfield(u32, default = 0x0)]
|
||||
#[derive(Debug)]
|
||||
pub struct DelayControl {
|
||||
/// Number of cycles the chip select is de-asserted between words when CPHA = 0
|
||||
#[bits(24..=31, rw)]
|
||||
inter_word_cs_deassert: u8,
|
||||
/// Delay between one chip select being de-activated, and activation of another.
|
||||
#[bits(16..=23, rw)]
|
||||
between_cs_assertion: u8,
|
||||
/// Delay between words.
|
||||
#[bits(8..=15, rw)]
|
||||
inter_word: u8,
|
||||
/// Added delay between assertion of slave select and first bit transfer.
|
||||
#[bits(0..=7, rw)]
|
||||
cs_to_first_bit: u8,
|
||||
}
|
||||
|
||||
/// Register block specification for both PS SPIs.
|
||||
#[derive(derive_mmio::Mmio)]
|
||||
#[repr(C)]
|
||||
pub struct Spi {
|
||||
cr: Config,
|
||||
#[mmio(PureRead, Write)]
|
||||
isr: InterruptStatus,
|
||||
/// Interrupt Enable Register.
|
||||
#[mmio(Write)]
|
||||
ier: InterruptControl,
|
||||
/// Interrupt Disable Register.
|
||||
#[mmio(Write)]
|
||||
idr: InterruptControl,
|
||||
/// Interrupt Mask Register.
|
||||
#[mmio(PureRead)]
|
||||
imr: InterruptMask,
|
||||
enable: u32,
|
||||
delay_control: DelayControl,
|
||||
#[mmio(Write)]
|
||||
txd: FifoWrite,
|
||||
#[mmio(Read)]
|
||||
rxd: FifoRead,
|
||||
sicr: u32,
|
||||
tx_trig: u32,
|
||||
rx_trig: u32,
|
||||
_reserved: [u32; 0x33],
|
||||
// Reset value: 0x90106
|
||||
#[mmio(PureRead)]
|
||||
mod_id: u32,
|
||||
}
|
||||
|
||||
static_assertions::const_assert_eq!(core::mem::size_of::<Spi>(), 0x100);
|
||||
|
||||
impl Spi {
|
||||
/// Create a new SPI MMIO instance for SPI0 at address [SPI_0_BASE_ADDR].
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This API can be used to potentially create a driver to the same peripheral structure
|
||||
/// from multiple threads. The user must ensure that concurrent accesses are safe and do not
|
||||
/// interfere with each other.
|
||||
pub const unsafe fn new_mmio_fixed_0() -> MmioSpi<'static> {
|
||||
unsafe { Self::new_mmio_at(SPI_0_BASE_ADDR) }
|
||||
}
|
||||
|
||||
/// Create a new SPI MMIO instance for SPI1 at address [SPI_1_BASE_ADDR].
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This API can be used to potentially create a driver to the same peripheral structure
|
||||
/// from multiple threads. The user must ensure that concurrent accesses are safe and do not
|
||||
/// interfere with each other.
|
||||
pub const unsafe fn new_mmio_fixed_1() -> MmioSpi<'static> {
|
||||
unsafe { Self::new_mmio_at(SPI_1_BASE_ADDR) }
|
||||
}
|
||||
}
|
189
zynq7000/src/ttc.rs
Normal file
189
zynq7000/src/ttc.rs
Normal file
@ -0,0 +1,189 @@
|
||||
//! Triple-timer counter (TTC) register module.
|
||||
use arbitrary_int::u4;
|
||||
|
||||
pub const TTC_0_BASE_ADDR: usize = 0xF800_1000;
|
||||
pub const TTC_1_BASE_ADDR: usize = 0xF800_2000;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
pub enum ClockSource {
|
||||
/// PS internal bus clock.
|
||||
#[default]
|
||||
Pclk = 0b0,
|
||||
External = 0b1,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, default = 0x0)]
|
||||
pub struct ClockControl {
|
||||
/// When this bit is set and the external clock is selected, the counter clocks on the
|
||||
/// negative edge of the external clock input.
|
||||
#[bit(6, rw)]
|
||||
ext_clk_edge: bool,
|
||||
#[bit(5, rw)]
|
||||
clk_src: ClockSource,
|
||||
#[bits(1..=4, rw)]
|
||||
prescaler: u4,
|
||||
#[bit(0, rw)]
|
||||
prescale_enable: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
pub enum Mode {
|
||||
Overflow = 0b0,
|
||||
Interval = 0b1,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
pub enum WavePolarity {
|
||||
/// The waveform output goes from high to low on a match 0 interrupt and returns high on
|
||||
/// overflow or interval interrupt.
|
||||
#[default]
|
||||
HighToLowOnMatch1 = 0b0,
|
||||
/// The waveform output goes from low to high on a match 0 interrupt and returns low on
|
||||
/// overflow or interval interrupt.
|
||||
LowToHighOnMatch1 = 0b1,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
pub enum WaveEnable {
|
||||
Enable = 0b0,
|
||||
Disable = 0b1,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, default = 0x0)]
|
||||
pub struct CounterControl {
|
||||
#[bit(6, rw)]
|
||||
wave_polarity: WavePolarity,
|
||||
/// Output waveform enable, active low. Reset value 1.
|
||||
#[bit(5, rw)]
|
||||
wave_enable_n: WaveEnable,
|
||||
/// Resets the counter and restarts counting. Automatically cleared on restart.
|
||||
#[bit(4, rw)]
|
||||
reset: bool,
|
||||
/// When this bit is set, an interrupt is generated when the count value matches one of the
|
||||
/// three match registers and the corresponding bit is set in the IER register.
|
||||
#[bit(3, rw)]
|
||||
match_enable: bool,
|
||||
/// When this bit is high, the timer counts down.
|
||||
#[bit(2, rw)]
|
||||
decrementing: bool,
|
||||
#[bit(1, rw)]
|
||||
mode: Mode,
|
||||
#[bit(0, rw)]
|
||||
disable: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
pub struct Counter {
|
||||
#[bits(0..=15, r)]
|
||||
count: u16,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
pub struct RwValue {
|
||||
#[bits(0..=15, rw)]
|
||||
value: u16,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
pub struct InterruptStatus {
|
||||
/// Even timer overflow interrupt.
|
||||
#[bit(5, r)]
|
||||
event: bool,
|
||||
#[bit(4, r)]
|
||||
counter_overflow: bool,
|
||||
#[bit(3, r)]
|
||||
match_2: bool,
|
||||
#[bit(2, r)]
|
||||
match_1: bool,
|
||||
#[bit(1, r)]
|
||||
match_0: bool,
|
||||
#[bit(0, r)]
|
||||
interval: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
pub struct InterruptControl {
|
||||
/// Even timer overflow interrupt.
|
||||
#[bit(5, rw)]
|
||||
event: bool,
|
||||
#[bit(4, rw)]
|
||||
counter_overflow: bool,
|
||||
#[bit(3, rw)]
|
||||
match_2: bool,
|
||||
#[bit(2, rw)]
|
||||
match_1: bool,
|
||||
#[bit(1, rw)]
|
||||
match_0: bool,
|
||||
#[bit(0, rw)]
|
||||
interval: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
pub struct EventControl {
|
||||
/// E_Ov bit. When set to 0, the event timer is disabled and set to 0 when an event timer
|
||||
/// register overflow occurs. Otherwise, continue counting on overflow.
|
||||
#[bit(2, rw)]
|
||||
continuous_mode: bool,
|
||||
/// E_Lo bit. When set to 1, counts PCLK cycles during low level duration of the external
|
||||
/// clock. Otherwise, counts it during high level duration.
|
||||
#[bit(1, rw)]
|
||||
count_low_level_of_ext_clk: bool,
|
||||
#[bit(0, rw)]
|
||||
enable: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
pub struct EventCount {
|
||||
#[bits(0..=15, r)]
|
||||
count: u16,
|
||||
}
|
||||
|
||||
/// Triple-timer counter
|
||||
#[derive(derive_mmio::Mmio)]
|
||||
#[repr(C)]
|
||||
pub struct Ttc {
|
||||
clk_cntr: [ClockControl; 3],
|
||||
cnt_ctrl: [CounterControl; 3],
|
||||
#[mmio(PureRead)]
|
||||
current_counter: [Counter; 3],
|
||||
interval_value: [RwValue; 3],
|
||||
match_value_0: [RwValue; 3],
|
||||
match_value_1: [RwValue; 3],
|
||||
match_value_2: [RwValue; 3],
|
||||
#[mmio(Read)]
|
||||
isr: [InterruptStatus; 3],
|
||||
ier: [InterruptControl; 3],
|
||||
event_cntrl: [EventControl; 3],
|
||||
#[mmio(PureRead)]
|
||||
event_reg: [EventCount; 3],
|
||||
}
|
||||
|
||||
static_assertions::const_assert_eq!(core::mem::size_of::<Ttc>(), 0x84);
|
||||
|
||||
impl Ttc {
|
||||
/// Create a new TTC MMIO instance for TTC0 at address [TTC_0_BASE_ADDR].
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This API can be used to potentially create a driver to the same peripheral structure
|
||||
/// from multiple threads. The user must ensure that concurrent accesses are safe and do not
|
||||
/// interfere with each other.
|
||||
pub const unsafe fn new_mmio_fixed_0() -> MmioTtc<'static> {
|
||||
unsafe { Self::new_mmio_at(TTC_0_BASE_ADDR) }
|
||||
}
|
||||
|
||||
/// Create a new TTC MMIO instance for TTC1 at address [TTC_1_BASE_ADDR].
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This API can be used to potentially create a driver to the same peripheral structure
|
||||
/// from multiple threads. The user must ensure that concurrent accesses are safe and do not
|
||||
/// interfere with each other.
|
||||
pub const unsafe fn new_mmio_fixed_1() -> MmioTtc<'static> {
|
||||
unsafe { Self::new_mmio_at(TTC_1_BASE_ADDR) }
|
||||
}
|
||||
}
|
356
zynq7000/src/uart.rs
Normal file
356
zynq7000/src/uart.rs
Normal file
@ -0,0 +1,356 @@
|
||||
//! PS UART register module.
|
||||
use arbitrary_int::u6;
|
||||
|
||||
pub const UART_0_BASE: usize = 0xE000_0000;
|
||||
pub const UART_1_BASE: usize = 0xE000_1000;
|
||||
|
||||
#[bitbybit::bitenum(u3, exhaustive = true)]
|
||||
pub enum Parity {
|
||||
Even = 0b000,
|
||||
Odd = 0b001,
|
||||
/// Forced to 0 (Space)
|
||||
ForcedTo0 = 0b010,
|
||||
/// Forced to 1 (Mark)
|
||||
ForcedTo1 = 0b011,
|
||||
NoParity = 0b100,
|
||||
NoParityAlt0 = 0b101,
|
||||
NoParityAlt1 = 0b110,
|
||||
NoParityAlt2 = 0b111,
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u2, exhaustive = true)]
|
||||
#[derive(Default, Debug, PartialEq, Eq)]
|
||||
pub enum Chrl {
|
||||
SixBits = 0b11,
|
||||
SevenBits = 0b10,
|
||||
#[default]
|
||||
EightBits = 0b00,
|
||||
EightBitsAlt = 0b01,
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Default, Debug, PartialEq, Eq)]
|
||||
pub enum ClkSel {
|
||||
#[default]
|
||||
UartRefClk = 0b0,
|
||||
UartRefClkDiv8 = 0b1,
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u2)]
|
||||
#[derive(Default, Debug, PartialEq, Eq)]
|
||||
pub enum Stopbits {
|
||||
#[default]
|
||||
One = 0b00,
|
||||
OnePointFive = 0b01,
|
||||
Two = 0b10,
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u2, exhaustive = true)]
|
||||
#[derive(Debug, Default)]
|
||||
pub enum ChMode {
|
||||
#[default]
|
||||
Normal = 0b00,
|
||||
AutoEcho = 0b01,
|
||||
LocalLoopback = 0b10,
|
||||
RemoteLoopback = 0b11,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
#[derive(Debug)]
|
||||
pub struct Ctrl {
|
||||
/// Stop transmitter break.
|
||||
#[bit(8, rw)]
|
||||
stopbrk: bool,
|
||||
/// Start transmitter break.
|
||||
#[bit(7, rw)]
|
||||
startbrk: bool,
|
||||
/// Restart receiver timeout counter.
|
||||
#[bit(6, rw)]
|
||||
rstto: bool,
|
||||
/// TX disable. If this is 1, TX is disabled, regardless of TXEN.
|
||||
#[bit(5, rw)]
|
||||
tx_dis: bool,
|
||||
/// TX enable. TX will be enabled if this bit is 1 and the TXDIS is 0.
|
||||
#[bit(4, rw)]
|
||||
tx_en: bool,
|
||||
/// RX disable. If this is 1, RX is disabled, regardless of RXEN.
|
||||
#[bit(3, rw)]
|
||||
rx_dis: bool,
|
||||
/// RX enable. RX will be enabled if this bit is 1 and the RXDIS is 0.
|
||||
#[bit(2, rw)]
|
||||
rx_en: bool,
|
||||
/// TX soft reset.
|
||||
#[bit(1, rw)]
|
||||
tx_rst: bool,
|
||||
/// RX soft reset.
|
||||
#[bit(0, rw)]
|
||||
rx_rst: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, default = 0x0)]
|
||||
#[derive(Debug)]
|
||||
pub struct Mode {
|
||||
#[bits(8..=9, rw)]
|
||||
chmode: ChMode,
|
||||
#[bits(6..=7, rw)]
|
||||
nbstop: Option<Stopbits>,
|
||||
#[bits(3..=5, rw)]
|
||||
par: Parity,
|
||||
/// Char length.
|
||||
#[bits(1..=2, rw)]
|
||||
chrl: Chrl,
|
||||
#[bit(0, rw)]
|
||||
clksel: ClkSel,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, default = 0x0)]
|
||||
#[derive(Debug)]
|
||||
pub struct Baudgen {
|
||||
#[bits(0..=15, rw)]
|
||||
cd: u16,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, default = 0x0)]
|
||||
#[derive(Debug)]
|
||||
pub struct BaudRateDiv {
|
||||
#[bits(0..=7, rw)]
|
||||
bdiv: u8,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
#[derive(Debug)]
|
||||
pub struct Fifo {
|
||||
#[bits(0..=7, rw)]
|
||||
fifo: u8,
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
pub enum Ttrig {
|
||||
LessThanTTrig = 0b0,
|
||||
GreaterEqualTTrig = 0b1,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
#[derive(Debug)]
|
||||
pub struct Status {
|
||||
#[bit(14, r)]
|
||||
tx_near_full: bool,
|
||||
#[bit(13, r)]
|
||||
tx_trig: Ttrig,
|
||||
#[bit(12, r)]
|
||||
flowdel: bool,
|
||||
/// Transmitter state machine active.
|
||||
#[bit(11, r)]
|
||||
tx_active: bool,
|
||||
/// Receiver state machine active.
|
||||
#[bit(10, r)]
|
||||
rx_active: bool,
|
||||
#[bit(4, r)]
|
||||
tx_full: bool,
|
||||
#[bit(3, r)]
|
||||
tx_empty: bool,
|
||||
#[bit(2, r)]
|
||||
rx_full: bool,
|
||||
#[bit(1, r)]
|
||||
rx_empty: bool,
|
||||
/// RX FIFO trigger level was reached.
|
||||
#[bit(0, r)]
|
||||
rx_trg: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, default = 0x0)]
|
||||
#[derive(Debug)]
|
||||
pub struct InterruptControl {
|
||||
#[bit(12, w)]
|
||||
tx_over: bool,
|
||||
#[bit(11, w)]
|
||||
tx_near_full: bool,
|
||||
#[bit(10, w)]
|
||||
tx_trig: bool,
|
||||
#[bit(9, w)]
|
||||
rx_dms: bool,
|
||||
/// Receiver timeout error interrupt.
|
||||
#[bit(8, w)]
|
||||
rx_timeout: bool,
|
||||
#[bit(7, w)]
|
||||
rx_parity: bool,
|
||||
#[bit(6, w)]
|
||||
rx_framing: bool,
|
||||
#[bit(5, w)]
|
||||
rx_over: bool,
|
||||
#[bit(4, w)]
|
||||
tx_full: bool,
|
||||
#[bit(3, w)]
|
||||
tx_empty: bool,
|
||||
#[bit(2, w)]
|
||||
rx_full: bool,
|
||||
#[bit(1, w)]
|
||||
rx_empty: bool,
|
||||
#[bit(0, w)]
|
||||
rx_trg: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
#[derive(Debug)]
|
||||
pub struct FifoTrigger {
|
||||
#[bits(0..=5, rw)]
|
||||
trig: u6,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
#[derive(Debug)]
|
||||
pub struct InterruptMask {
|
||||
#[bit(12, r)]
|
||||
tx_over: bool,
|
||||
#[bit(11, r)]
|
||||
tx_near_full: bool,
|
||||
#[bit(10, r)]
|
||||
tx_trig: bool,
|
||||
#[bit(9, r)]
|
||||
rx_dms: bool,
|
||||
/// Receiver timeout error interrupt.
|
||||
#[bit(8, r)]
|
||||
rx_timeout: bool,
|
||||
#[bit(7, r)]
|
||||
rx_parity: bool,
|
||||
#[bit(6, r)]
|
||||
rx_framing: bool,
|
||||
#[bit(5, r)]
|
||||
rx_over: bool,
|
||||
#[bit(4, r)]
|
||||
tx_full: bool,
|
||||
#[bit(3, r)]
|
||||
tx_empty: bool,
|
||||
#[bit(2, r)]
|
||||
rx_full: bool,
|
||||
#[bit(1, r)]
|
||||
rx_empty: bool,
|
||||
/// RX FIFO trigger level reached.
|
||||
#[bit(0, r)]
|
||||
rx_trg: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, default = 0x0)]
|
||||
#[derive(Debug)]
|
||||
pub struct InterruptStatus {
|
||||
#[bit(12, rw)]
|
||||
tx_over: bool,
|
||||
#[bit(11, rw)]
|
||||
tx_near_full: bool,
|
||||
#[bit(10, rw)]
|
||||
tx_trig: bool,
|
||||
#[bit(9, rw)]
|
||||
rx_dms: bool,
|
||||
/// Receiver timeout error interrupt.
|
||||
#[bit(8, rw)]
|
||||
rx_timeout: bool,
|
||||
#[bit(7, rw)]
|
||||
rx_parity: bool,
|
||||
#[bit(6, rw)]
|
||||
rx_framing: bool,
|
||||
#[bit(5, rw)]
|
||||
rx_over: bool,
|
||||
#[bit(4, rw)]
|
||||
tx_full: bool,
|
||||
#[bit(3, rw)]
|
||||
tx_empty: bool,
|
||||
#[bit(2, rw)]
|
||||
rx_full: bool,
|
||||
#[bit(1, rw)]
|
||||
rx_empty: bool,
|
||||
/// RX FIFO trigger level reached.
|
||||
#[bit(0, rw)]
|
||||
rx_trg: bool,
|
||||
}
|
||||
|
||||
impl InterruptStatus {
|
||||
pub fn new_for_clearing_rx_errors() -> Self {
|
||||
Self::builder()
|
||||
.with_tx_over(false)
|
||||
.with_tx_near_full(false)
|
||||
.with_tx_trig(false)
|
||||
.with_rx_dms(false)
|
||||
.with_rx_timeout(false)
|
||||
.with_rx_parity(true)
|
||||
.with_rx_framing(true)
|
||||
.with_rx_over(true)
|
||||
.with_tx_full(false)
|
||||
.with_tx_empty(false)
|
||||
.with_rx_full(false)
|
||||
.with_rx_empty(false)
|
||||
.with_rx_trg(false)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(derive_mmio::Mmio)]
|
||||
#[repr(C)]
|
||||
pub struct Uart {
|
||||
/// Control Register
|
||||
cr: Ctrl,
|
||||
/// Mode register
|
||||
mr: Mode,
|
||||
/// Interrupt enable register
|
||||
#[mmio(Write)]
|
||||
ier: InterruptControl,
|
||||
/// Interrupt disable register
|
||||
#[mmio(Write)]
|
||||
idr: InterruptControl,
|
||||
/// Interrupt mask register, showing enabled interrupts.
|
||||
#[mmio(PureRead)]
|
||||
imr: InterruptMask,
|
||||
/// Interrupt status register
|
||||
#[mmio(PureRead, Write)]
|
||||
isr: InterruptStatus,
|
||||
/// Baudgen register
|
||||
baudgen: Baudgen,
|
||||
/// RX timeout register
|
||||
rx_tout: u32,
|
||||
/// RX FIFO trigger level register
|
||||
rx_fifo_trigger: FifoTrigger,
|
||||
/// Modem control register
|
||||
modem_cr: u32,
|
||||
/// Modem status register
|
||||
modem_sr: u32,
|
||||
/// Channel status register
|
||||
#[mmio(PureRead)]
|
||||
sr: Status,
|
||||
/// FIFO register
|
||||
#[mmio(Read, Write)]
|
||||
fifo: Fifo,
|
||||
/// Baud rate divider register
|
||||
baud_rate_div: BaudRateDiv,
|
||||
/// Flow control delay register
|
||||
flow_delay: u32,
|
||||
|
||||
_reserved: [u32; 2],
|
||||
|
||||
/// TX fifo trigger level
|
||||
tx_fifo_trigger: FifoTrigger,
|
||||
}
|
||||
|
||||
static_assertions::const_assert_eq!(core::mem::size_of::<Uart>(), 0x48);
|
||||
|
||||
impl Uart {
|
||||
/// Create a new UART MMIO instance for uart0 at address 0xE000_0000.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This API can be used to potentially create a driver to the same peripheral structure
|
||||
/// from multiple threads. The user must ensure that concurrent accesses are safe and do not
|
||||
/// interfere with each other.
|
||||
pub const unsafe fn new_mmio_fixed_0() -> MmioUart<'static> {
|
||||
unsafe { Self::new_mmio_at(UART_0_BASE) }
|
||||
}
|
||||
|
||||
/// Create a new UART MMIO instance for uart1 at address 0xE000_1000.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This API can be used to potentially create a driver to the same peripheral structure
|
||||
/// from multiple threads. The user must ensure that concurrent accesses are safe and do not
|
||||
/// interfere with each other.
|
||||
pub const unsafe fn new_mmio_fixed_1() -> MmioUart<'static> {
|
||||
unsafe { Self::new_mmio_at(UART_1_BASE) }
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user