Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ git_override(
# Allow integration_tests to build for armv7-m / armv7e-m so the
# AST10x0 unittest_runner can use it.
"//third_party/pigweed:integration_tests_armv7m.patch",
# Stage .bin alongside .elf in system_image_test runfiles.
"//third_party/pigweed:system_image_test_bin_runfiles.patch",
],
remote = "https://pigweed.googlesource.com/pigweed/pigweed",
)
Expand Down
19 changes: 19 additions & 0 deletions target/ast10x0/board/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Licensed under the Apache-2.0 license
# SPDX-License-Identifier: Apache-2.0

load("@rules_rust//rust:defs.bzl", "rust_library")
load("//target/ast10x0:defs.bzl", "TARGET_COMPATIBLE_WITH")

rust_library(
name = "ast10x0_board",
srcs = [
"src/lib.rs",
],
crate_name = "ast10x0_board",
edition = "2024",
target_compatible_with = TARGET_COMPATIBLE_WITH,
visibility = ["//visibility:public"],
deps = [
"//target/ast10x0/peripherals",
],
)
14 changes: 14 additions & 0 deletions target/ast10x0/board/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# ast10x0_board

Board-level integration crate for AST10x0 platforms.

This is the empty scaffold. The crate exists so that board-specific
descriptors, monitor wiring, and SPIM routing helpers have a stable
home as they get added on top of the SCU + SPIMONITOR primitives in
`peripherals`.

## Build

```
bazelisk build --config=virt_ast10x0 //target/ast10x0/board:ast10x0_board
```
88 changes: 88 additions & 0 deletions target/ast10x0/board/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// Licensed under the Apache-2.0 license
// SPDX-License-Identifier: Apache-2.0

#![no_std]

#![deny(
clippy::unwrap_used,
clippy::expect_used,
clippy::panic,
clippy::unreachable,
clippy::todo,
clippy::unimplemented
)]

use ast10x0_peripherals::scu::{PinctrlPin, ScuRegisters};
use ast10x0_peripherals::scu::{ClockRegisterHalf, ScuRegisterHalf};

/// Board descriptor metadata for AST10x0 board initialization.
#[derive(Clone, Debug)]
pub struct Ast10x0BoardDescriptor {
/// Pin control groups to apply during board init.
/// Applied in order via `ScuRegisters::apply_pinctrl_group()`.
pub pinctrl_groups: &'static [&'static [PinctrlPin]],
}

/// Runtime board object that executes hardware initialization steps.
pub struct Ast10x0Board {
descriptor: Ast10x0BoardDescriptor,
}

impl Ast10x0Board {
/// Create a board runtime object from board metadata.
#[must_use]
pub const fn new(descriptor: Ast10x0BoardDescriptor) -> Self {
Self { descriptor }
}

/// Initialize board: apply pinctrl groups and initialize I2C subsystem.
///
/// This performs the complete platform-level initialization:
/// 1. Apply pinctrl groups
/// 2. Enable I2C clock via SCU
/// 3. Assert I2C/SMBus controller reset
/// 4. Delay for reset to settle
/// 5. Deassert reset
/// 6. Delay for recovery
/// 7. Configure I2C global registers (clock dividers, etc.)
///
/// # Safety
/// - Must be called only once during board initialization.
/// - Not thread-safe; caller must ensure no concurrent SCU or I2C accesses.
pub unsafe fn init(&self) {
// Unlock SCU once before the sequence of writes (aspeed-rust pattern)
let scu = unsafe { ScuRegisters::new_global_unlocked() };

// Apply pinctrl groups
for group in self.descriptor.pinctrl_groups {
scu.apply_pinctrl_group(group);
}

// Enable I2C clock (Group 0, bit 2)
scu.ungate_clock_mask(ClockRegisterHalf::Lower, 1 << 2);

// Assert I2C reset (Upper half, bit 2)
scu.assert_reset_mask(ScuRegisterHalf::Upper, 1 << 2);
delay_us(1000);

// Deassert I2C reset
scu.deassert_reset_mask(ScuRegisterHalf::Upper, 1 << 2);
delay_us(1000);

// Configure I2C global registers (clock dividers, etc.)
unsafe { ast10x0_peripherals::i2c::init_i2c_global() };
}
}

/// Simple busy-wait delay in microseconds.
///
/// This is a placeholder; production code should use a proper timer or delay provider.
/// Spins for approximately `micros` microseconds.
#[inline]
fn delay_us(micros: u32) {
// Very rough approximation: ~16 cycles per microsecond on Cortex-M4 @ ~50MHz
// This is calibration-free but inaccurate; improve for production.
for _ in 0..(micros * 16) {
core::hint::spin_loop();
}
}
24 changes: 24 additions & 0 deletions target/ast10x0/peripherals/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,40 @@ package(default_visibility = ["//visibility:public"])
rust_library(
name = "peripherals",
srcs = [
"i2c/constants.rs",
"i2c/controller.rs",
"i2c/error.rs",
"i2c/global.rs",
"i2c/hal_impl.rs",
"i2c/master.rs",
"i2c/mod.rs",
"i2c/recovery.rs",
"i2c/slave.rs",
"i2c/target_adapter.rs",
"i2c/timing.rs",
"i2c/transfer.rs",
"i2c/types.rs",
"lib.rs",
"scu/clock.rs",
"scu/mod.rs",
"scu/pinctrl.rs",
"scu/registers.rs",
"scu/reset.rs",
"scu/status.rs",
"scu/types.rs",
"uart/mod.rs",
],
crate_name = "ast10x0_peripherals",
crate_root = "lib.rs",
edition = "2024",
proc_macro_deps = [
"@rust_crates//:paste",
],
target_compatible_with = TARGET_COMPATIBLE_WITH,
deps = [
"@ast1060_pac",
"@rust_crates//:bitflags",
"@rust_crates//:embedded-hal",
"@rust_crates//:embedded-hal-nb",
"@rust_crates//:embedded-io",
"@rust_crates//:nb",
Expand Down
179 changes: 179 additions & 0 deletions target/ast10x0/peripherals/i2c/constants.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
// Licensed under the Apache-2.0 license
// SPDX-License-Identifier: Apache-2.0

//! Hardware constants for AST1060 I2C controller
//!
//! # Reference Implementation
//!
//! Constants derived from the original working code:
//! - **aspeed-rust/src/i2c/ast1060_i2c.rs** lines 55-100
//!
//! # Register Map (New Register Definition Mode)
//!
//! | Offset | Register | Description |
//! |--------|----------|-------------|
//! | 0x00 | I2CC00 | Function Control Register |
//! | 0x04 | I2CC04 | AC Timing Register |
//! | 0x08 | I2CC08 | Byte Buffer / Line Status Register |
//! | 0x0C | I2CC0C | Pool Buffer Control Register |
//! | 0x10 | I2CM10 | Master Interrupt Control Register |
//! | 0x14 | I2CM14 | Master Interrupt Status Register (write-to-clear) |
//! | 0x18 | I2CM18 | Master Command Register |
//! | 0x1C | I2CM1C | Master DMA Length Register |
//!
//! # Critical Register Notes
//!
//! - **i2cm18**: Command register - write all command bits here
//! - **i2cm14**: Status register - read status, write to clear interrupts
//! - **i2cc08**: Byte data register for byte mode (`tx_byte_buffer`, `rx_byte_buffer`)
//! - **i2cc0c**: Buffer size register for buffer mode (`tx_data_byte_count`, `rx_pool_buffer_size`)

/// HPLL frequency (1 `GHz`)
pub const HPLL_FREQ: u32 = 1_000_000_000;

/// ASPEED I2C bus clock (100 `MHz` typical)
pub const ASPEED_I2C_BUS_CLK_HZ: u32 = 100_000_000;

/// Standard mode speed (100 kHz)
pub const I2C_STANDARD_MODE_HZ: u32 = 100_000;

/// Fast mode speed (400 kHz)
pub const I2C_FAST_MODE_HZ: u32 = 400_000;

/// Fast-plus mode speed (1 `MHz`)
pub const I2C_FAST_PLUS_MODE_HZ: u32 = 1_000_000;

/// Buffer mode maximum size (32 bytes)
pub const BUFFER_MODE_SIZE: usize = 32;

/// DMA mode maximum transfer size (4096 bytes, hardware limit)
pub const DMA_MODE_MAX_SIZE: usize = 4096;

/// I2C buffer size register value
/// Reference: `ast1060_i2c.rs:97`
pub const I2C_BUF_SIZE: u8 = 0x20;

/// Default timeout in microseconds
pub const DEFAULT_TIMEOUT_US: u32 = 1_000_000;

/// Maximum retry attempts for operations
pub const MAX_RETRY_ATTEMPTS: u32 = 3;

// ============================================================================
// Register bit definitions
// Reference: aspeed-rust/src/i2c/ast1060_i2c.rs lines 55-100
// ============================================================================

// Function Control Register (I2CC00)
/// Enable slave function
pub const AST_I2CC_SLAVE_EN: u32 = 1 << 1;
/// Enable master function
pub const AST_I2CC_MASTER_EN: u32 = 1 << 0;
/// Disable multi-master capability
pub const AST_I2CC_MULTI_MASTER_DIS: u32 = 1 << 15;
/// Enable save address byte into buffer for Slave Packet mode receive command (I2CC00 bit 20)
/// Per AST1060 datasheet section 13.3.1, when this bit is set, the slave address byte
/// is saved into the receive buffer in slave packet mode.
pub const AST_I2CC_SLAVE_PKT_SAVE_ADDR: u32 = 1 << 20;

// Master Command Register (I2CM18) bit definitions
// Reference: ast1060_i2c.rs:58-69
/// Enable packet mode
pub const AST_I2CM_PKT_EN: u32 = 1 << 16;
/// Enable RX DMA mode
pub const AST_I2CM_RX_DMA_EN: u32 = 1 << 9;
/// Enable TX DMA mode
pub const AST_I2CM_TX_DMA_EN: u32 = 1 << 8;
/// Enable RX buffer mode
pub const AST_I2CM_RX_BUFF_EN: u32 = 1 << 7;
/// Enable TX buffer mode
pub const AST_I2CM_TX_BUFF_EN: u32 = 1 << 6;
/// Send STOP condition
pub const AST_I2CM_STOP_CMD: u32 = 1 << 5;
/// RX command with NACK (last byte)
pub const AST_I2CM_RX_CMD_LAST: u32 = 1 << 4;
/// RX command with ACK
pub const AST_I2CM_RX_CMD: u32 = 1 << 3;
/// TX command
pub const AST_I2CM_TX_CMD: u32 = 1 << 1;
/// Send START condition
pub const AST_I2CM_START_CMD: u32 = 1 << 0;

// Master Interrupt Status Register (I2CM14) bit definitions
// Reference: ast1060_i2c.rs:71-77
// NOTE: These bits overlap with command bits but have different meanings when read from i2cm14
/// SCL low timeout
pub const AST_I2CM_SCL_LOW_TO: u32 = 1 << 6;
/// Abnormal STOP condition
pub const AST_I2CM_ABNORMAL: u32 = 1 << 5;
/// Normal STOP condition
pub const AST_I2CM_NORMAL_STOP: u32 = 1 << 4;
/// Arbitration loss
pub const AST_I2CM_ARBIT_LOSS: u32 = 1 << 3;
/// RX transfer done
pub const AST_I2CM_RX_DONE: u32 = 1 << 2;
/// TX received NACK
pub const AST_I2CM_TX_NAK: u32 = 1 << 1;
/// TX received ACK
pub const AST_I2CM_TX_ACK: u32 = 1 << 0;

// Packet mode status (I2CM14 bits 12-17)
// Reference: ast1060_i2c.rs:86-92
/// Packet mode error
pub const AST_I2CM_PKT_ERROR: u32 = 1 << 17;
/// Packet mode done
pub const AST_I2CM_PKT_DONE: u32 = 1 << 16;
/// Bus recovery failed
pub const AST_I2CM_BUS_RECOVER_FAIL: u32 = 1 << 15;
/// SDA data line timeout
pub const AST_I2CM_SDA_DL_TO: u32 = 1 << 14;
/// Bus recovery done
pub const AST_I2CM_BUS_RECOVER: u32 = 1 << 13;
/// `SMBus` alert
pub const AST_I2CM_SMBUS_ALT: u32 = 1 << 12;

// Slave mode constants
// Reference: ast1060_i2c.rs:83-84 and 99-125
/// Enable slave packet mode
pub const AST_I2CS_PKT_MODE_EN: u32 = 1 << 16;
/// Active on all addresses
pub const AST_I2CS_ACTIVE_ALL: u32 = 0x3 << 17;
/// Enable slave RX DMA
pub const AST_I2CS_RX_DMA_EN: u32 = 1 << 9;
/// Enable slave TX DMA
pub const AST_I2CS_TX_DMA_EN: u32 = 1 << 8;
/// Enable slave RX buffer
pub const AST_I2CS_RX_BUFF_EN: u32 = 1 << 7;
/// Enable slave TX buffer
pub const AST_I2CS_TX_BUFF_EN: u32 = 1 << 6;
/// Slave TX command
pub const AST_I2CS_TX_CMD: u32 = 1 << 2;
/// Slave address matched
pub const AST_I2CS_SLAVE_MATCH: u32 = 1 << 7;
/// STOP condition received
pub const AST_I2CS_STOP: u32 = 1 << 4;
/// Slave RX done NACK
pub const AST_I2CS_RX_DONE_NAK: u32 = 1 << 3;
/// Slave RX done
pub const AST_I2CS_RX_DONE: u32 = 1 << 2;
/// Slave TX got NACK
pub const AST_I2CS_TX_NAK: u32 = 1 << 1;
/// Slave TX got ACK
pub const AST_I2CS_TX_ACK: u32 = 1 << 0;
/// Slave inactive timeout
pub const AST_I2CS_INACTIVE_TO: u32 = 1 << 15;
/// Slave packet mode done
pub const AST_I2CS_PKT_DONE: u32 = 1 << 16;
/// Slave packet mode error
pub const AST_I2CS_PKT_ERROR: u32 = 1 << 17;
/// Waiting for TX DMA
pub const AST_I2CS_WAIT_TX_DMA: u32 = 1 << 25;
/// Waiting for RX DMA
pub const AST_I2CS_WAIT_RX_DMA: u32 = 1 << 24;

/// Helper to build packet mode address field
#[inline]
#[must_use]
pub fn ast_i2cm_pkt_addr(addr: u8) -> u32 {
u32::from(addr & 0x7F) << 24
}
Loading