Skip to main content

airfrog_core/
rp.rs

1// Copyright (C) 2025 Piers Finlayson <piers@piers.rocks>
2//
3// MIT License
4
5//! airfrog-core - Raspberry Pi (RPxxxx) specific objects
6
7use core::fmt;
8
9use crate::arm::Cortex;
10use crate::arm::ap::{IDR_AHB_AP_CORTEX_M0, IDR_AHB_AP_CORTEX_M33, Idr};
11use crate::arm::dp::IdCode;
12
13// RP2040 Flash base addresses
14const RP2040_FLASH_BASE: u32 = 0x1000_0000;
15
16// RP2040 RAM base addresses
17const RP2040_RAM_BASE: u32 = 0x2000_0000;
18
19// RP2350 Flash base addresses
20const RP2350_FLASH_BASE: u32 = 0x1000_0000;
21
22// RP2350 RAM base addresses
23const RP2350_RAM_BASE: u32 = 0x2000_0000;
24
25// RP2040 chip ID
26pub const RP2040_CHIP_ID: u32 = 0x10002927;
27pub const RP2040_CHIP_ID_ADDR: u32 = 0x40000000;
28
29// RP2040 CPU ID
30pub const RP2040_CPU_ID: u32 = 0x410CC601;
31pub const RP2040_CPU_ID_ADDR: u32 = 0xE000ED00;
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34pub enum RpLine {
35    Rp2040,
36    Rp2350,
37    Unknown,
38}
39
40impl RpLine {
41    /// Whether this `airfrog-core` is familiar with this RP family
42    pub fn known(&self) -> bool {
43        !matches!(self, RpLine::Unknown)
44    }
45
46    /// Returns the RAM size in bytes
47    pub fn ram_size_bytes(&self) -> Option<u32> {
48        self.ram_size_kb().map(|size| size * 1024)
49    }
50
51    /// Returns the RAM size in KB
52    pub fn ram_size_kb(&self) -> Option<u32> {
53        match self {
54            RpLine::Rp2040 => Some(264),
55            RpLine::Rp2350 => Some(512),
56            RpLine::Unknown => None,
57        }
58    }
59
60    /// Returns the expected IDR value for this RP line.
61    pub fn expected_idr(&self) -> Option<Idr> {
62        match self {
63            RpLine::Rp2040 => Some(IDR_AHB_AP_CORTEX_M0),
64            RpLine::Rp2350 => Some(IDR_AHB_AP_CORTEX_M33),
65            RpLine::Unknown => None,
66        }
67    }
68}
69
70impl fmt::Display for RpLine {
71    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72        match self {
73            RpLine::Rp2040 => write!(f, "RP2040"),
74            RpLine::Rp2350 => write!(f, "RP2350"),
75            RpLine::Unknown => write!(f, "Unknown"),
76        }
77    }
78}
79
80/// RP device details
81#[derive(Debug, Clone, Copy)]
82pub struct RpDetails {
83    line: RpLine,
84}
85
86impl RpDetails {
87    /// Create a new `RpDetails` instance from a specific RP line
88    pub fn from_line(line: RpLine) -> Self {
89        Self { line }
90    }
91
92    /// Get the family of this RP device
93    pub fn line(&self) -> RpLine {
94        self.line
95    }
96
97    /// Create a new `RpDetails` instance from IdCode
98    pub fn from_idcode(idcode: IdCode) -> Option<Self> {
99        match idcode {
100            Cortex::IDCODE_M0 => Some(RpDetails {
101                line: RpLine::Rp2040,
102            }),
103            Cortex::IDCODE_M33 => Some(RpDetails {
104                line: RpLine::Rp2350,
105            }),
106            _ => None,
107        }
108    }
109
110    /// Get the base flash address for this MCU
111    pub fn flash_base(&self) -> Option<u32> {
112        match self.line {
113            RpLine::Rp2040 => Some(RP2040_FLASH_BASE),
114            RpLine::Rp2350 => Some(RP2350_FLASH_BASE),
115            RpLine::Unknown => None,
116        }
117    }
118
119    /// Get the base RAM address for this MCU
120    pub fn ram_base(&self) -> Option<u32> {
121        match self.line {
122            RpLine::Rp2040 => Some(RP2040_RAM_BASE),
123            RpLine::Rp2350 => Some(RP2350_RAM_BASE),
124            RpLine::Unknown => None,
125        }
126    }
127
128    /// Returns the expected IDR value for this device.
129    ///
130    /// Returns:
131    /// - `Some(Idr)`: If the RP line is known.
132    /// - `None`: If the RP line is unknown.
133    pub fn expected_idr(&self) -> Option<Idr> {
134        self.line.expected_idr()
135    }
136}
137
138impl fmt::Display for RpDetails {
139    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
140        write!(f, "{}", self.line)
141    }
142}